plantegg

java tcp mysql performance network docker Linux

为什么这么多CLOSE_WAIT

案例1:服务响应慢,经常连不上

应用发布新版本上线后,业务同学发现业务端口上的TCP连接处于CLOSE_WAIT状态的数量有积压,多的时候能堆积到几万个,有时候应用无法响应了

这个案例目标:怎么样才能获取举三反一的秘籍, 普通人为什么要案例来深化对理论知识的理解。

检查机器状态

img

img

从上述两个图中可以看到磁盘 sdb压力非常大,util经常会到 100%,这个时候对应地从top中也可以看到cpu wait%很高(这个ECS cpu本来竞争很激烈),st%一直非常高,所以整体留给应用的CPU不多,碰上磁盘缓慢的话,这时如果业务写日志是同步刷盘那么就会导致程序卡顿严重。

实际看到FGC的时间也是正常状态下的10倍了。

再看看实际上应用同步写日志到磁盘比较猛,平均20-30M,高的时候能到200M每秒。如果输出的时候磁盘卡住了那么就整个卡死了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#dstat
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read writ| recv send| in out | int csw
4 1 89 5 0 0|1549M 8533M| 0 0 | 521k 830k|6065k 7134
3 1 95 0 0 0|3044k 19M|1765k 85k| 0 84k| 329k 7770
5 1 93 0 0 0|3380k 18M|4050k 142k| 0 0 | 300k 8008
7 1 91 1 0 1|2788k 227M|5094k 141k| 0 28k| 316k 8644
4 1 93 2 0 0|2788k 55M|2897k 63k| 0 68k| 274k 6453
6 1 91 1 0 0|4464k 24M|3683k 98k| 0 28k| 299k 7379
7 1 91 1 0 0| 10M 34M|3655k 130k| 0 208k| 375k 8417
3 1 87 8 0 0|6940k 33M|1335k 91k| 0 112k| 334k 7369
3 1 88 7 0 0|4932k 16M|1918k 61k| 0 44k| 268k 6542
7 1 86 6 0 0|5508k 20M|5377k 111k| 0 0 | 334k 7998
7 2 88 3 0 0|5628k 115M|4713k 104k| 0 0 | 280k 7392
4 1 95 0 0 0| 0 732k|2940k 85k| 0 76k| 189k 7682
3 1 96 0 0 0| 0 800k|1809k 68k| 0 16k| 181k 9640
7 2 76 14 0 1|6300k 38M|3834k 132k| 0 0 | 333k 7502
7 2 90 1 0 0|3896k 19M|3786k 93k| 0 0 | 357k 7578
4 1 94 0 0 0|5732k 29M|2906k 806k| 0 0 | 338k 8966
4 1 94 1 0 0|6044k 17M|2202k 95k| 0 0 | 327k 7573
4 1 95 1 0 0|3524k 17M|2277k 88k| 0 0 | 299k 6462
4 1 96 0 0 0| 456k 14M|2770k 91k| 60k 0 | 252k 6644
6 2 92 0 0 0| 0 12M|4251k 847k| 0 0 | 264k 10k
3 1 92 4 0 0| 788k 204M|1555k 43k| 0 0 | 249k 6215
6 1 86 6 0 0|7180k 20M|2073k 92k| 0 0 | 303k 7028
11 4 84 1 0 0|6116k 29M|3079k 99k| 28k 0 | 263k 6605

磁盘util 100%和CLOSE_WAIT 强相关,也和理论比较符合,CLOSE_WAIT 就是连接被动关闭端的应用没调 socket.close

img

原因推断:

1)新发布的代码需要消耗更多的CPU,代码增加了新的逻辑 //这只是一个微小的诱因

2)机器本身资源(CPU /IO)很紧张 这两个条件下导致应用响应缓慢。 目前看到的稳定重现条件就是重启一个业务节点,重启会触发业务节点之间重新同步数据,以及重新推送很多数据到客户端的新连接上,这两件事情都会让应用CPU占用飙升响应缓慢,响应慢了之后会导致更多的心跳失效进一步加剧数据同步,然后就雪崩恶化了。最后表现就是看到系统卡死了,也就是 tcp buffer 中的数据也不读走、连接也不 close,连接大量堆积在 close_wait状态

img

CLOSE_WAIT的原因分析

先看TCP连接状态图

这是网络、书本上凡是描述TCP状态一定会出现的状态图,理论上看这个图能解决任何TCP状态问题。

image.png

反复看这个图的右下部分的CLOSE_WAIT ,从这个图里可以得到如下结论:

CLOSE_WAIT 是被动关闭端在等待应用进程的关闭

基本上这一结论要能帮助解决所有CLOSE_WAIT相关的问题,如果不能说明对这个知识点理解的不够。

案例1结论

机器超卖严重、IO卡顿,导致应用线程卡顿,来不及调用 socket.close()

案例2:server端大量close_wait

用实际案例来检查自己对CLOSE_WAIT 理论(CLOSE_WAIT是被动关闭端在等待应用进程的关闭)的掌握 – 能不能用这个结论来解决实际问题。同时也可以看看自己从知识到问题的推理能力(跟前面的知识效率呼应一下)。

问题描述:

服务端出现大量CLOSE_WAIT ,并且个数正好 等于 somaxconn(调整somaxconn大小后 CLOSE_WAIT 也会跟着变成一样的值)

根据这个描述先不要往下看,自己推理分析下可能的原因。

我的推理如下:

从这里看起来,client跟server成功建立了 somaxconn个连接(somaxconn小于backlog,所以accept queue只有这么大),但是应用没有accept这些连接(连接建立三次握手不需要应用参与),导致这些连接一直在accept queue中。但是这些连接的状态已经是ESTABLISHED了,也就是client可以发送数据了,数据发送到server 后OS ack了,并放在os的tcp buffer中,应用一直没有accept也就没法读取数据。client 于是发送fin(可能是超时、也可能是简单发送数据任务完成了得结束连接),这时 Server上这个连接变成了CLOSE_WAIT .

也就是从开始到结束这些连接都在 accept queue中,没有被应用 accept,很快他们又因为client 发送 fin 包变成了CLOSE_WAIT ,所以始终看到的是服务端出现大量 CLOSE_WAIT 并且个数正好等于somaxconn(调整somaxconn后 CLOSE_WAIT 也会跟着变成一样的值)。

如下图所示,在连接进入accept queue后状态就是ESTABLISED了,也就是可以正常收发数据和fin了。client是感知不到 server是否accept()了,只是发了数据后server的 OS 代为保存在OS的TCP buffer中,因为应用没来取自然在CLOSE_WAIT 后应用也没有close(),所以一直维持CLOSE_WAIT 。

得检查server 应用为什么没有accept。

Recv-Q和Send-Q

如上是老司机的思路靠经验缺省了一些理论推理,缺省还是对理论理解不够, 这个分析抓住了 大量CLOSE_WAIT 个数正好 等于somaxconn(调整somaxconn后 CLOSE_WAIT 也会跟着变成一样的值)但是没有抓住 CLOSE_WAIT 背后的核心原因

更简单的推理

如果没有任何实战经验,只看上面的状态图的学霸应该是这样推理的:

看到server上有大量的CLOSE_WAIT说明 client主动断开了连接,server的OS收到client 发的fin,并回复了ack,这个过程不需要应用感知,进而连接从ESTABLISHED进入CLOSE_WAIT,此时在等待server上的应用调用close连关闭连接(处理完所有收发数据后才会调close()) —- 结论:server上的应用一直卡着没有调close().

CLOSE_WAIT 状态拆解

通常,CLOSE_WAIT 状态在服务器停留时间很短,如果你发现大量的 CLOSE_WAIT 状态,那么就意味着被动关闭的一方没有及时发出 FIN 包,一般有如下几种可能:

  • 程序问题:如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;或者代码不严谨,出现死循环之类的问题,导致即便后面写了 close 也永远执行不到。
  • 响应太慢或者超时设置过小:如果连接双方不和谐,一方不耐烦直接 timeout,另一方却还在忙于耗时逻辑,就会导致 close 被延后。响应太慢是首要问题,不过换个角度看,也可能是 timeout 设置过小。
  • BACKLOG 太大:此处的 backlog 不是 syn backlog,而是 accept 的 backlog,如果 backlog 太大的话,设想突然遭遇大访问量的话,即便响应速度不慢,也可能出现来不及消费的情况,导致多余的请求还在队列里就被对方关闭了。

如果你通过「netstat -ant」或者「ss -ant」命令发现了很多 CLOSE_WAIT 连接,请注意结果中的「Recv-Q」和「Local Address」字段,通常「Recv-Q」会不为空,它表示应用还没来得及接收数据,而「Local Address」表示哪个地址和端口有问题,我们可以通过「lsof -i:」来确认端口对应运行的是什么程序以及它的进程号是多少。

如果是我们自己写的一些程序,比如用 HttpClient 自定义的蜘蛛,那么八九不离十是程序问题,如果是一些使用广泛的程序,比如 Tomcat 之类的,那么更可能是响应速度太慢或者 timeout 设置太小或者 BACKLOG 设置过大导致的故障。

看完这段 CLOSE_WAIT 更具体深入点的分析后再来分析上面的案例看看,能否推导得到正确的结论。

一些疑问

连接都没有被accept(), client端就能发送数据了?

答:是的。只要这个连接在OS看来是ESTABLISHED的了就可以,因为握手、接收数据都是由内核完成的,内核收到数据后会先将数据放在内核的tcp buffer中,然后os回复ack。另外三次握手之后client端是没法知道server端是否accept()了。

CLOSE_WAIT与accept queue有关系吗?

答:没有关系。只是本案例中因为open files不够了,影响了应用accept(), 导致accept queue满了,同时因为即使应用不accept(三次握手后,server端是否accept client端无法感知),client也能发送数据和发 fin断连接,这些响应都是os来负责,跟上层应用没关系,连接从握手到ESTABLISHED再到CLOSE_WAIT都不需要fd,也不需要应用参与。CLOSE_WAIT只跟应用不调 close() 有关系。

CLOSE_WAIT与accept queue为什么刚好一致并且联动了?

答:这里他们的数量刚好一致是因为所有新建连接都没有accept,堵在queue中。同时client发现问题后把所有连接都fin了,也就是所有queue中的连接从来没有被accept过,但是他们都是ESTABLISHED,过一阵子之后client端发了fin所以所有accept queue中的连接又变成了 CLOSE_WAIT, 所以二者刚好一致并且联动了

CLOSE_WAIT与TIME_WAIT

  • 简单说就是CLOSE_WAIT出现在被动断开连接端,一般过多就不太正常;
  • TIME_WAIT出现在主动断开连接端,是正常现象,多出现在短连接场景下

openfiles 和 accept()的关系是?

答:accept()的时候才会创建文件句柄,消耗openfiles

一个连接如果在accept queue中了,但是还没有被应用 accept,那么这个时候在server上看这个连接的状态他是ESTABLISHED的吗?

答:是

如果server的os参数 open files到了上限(就是os没法打开新的文件句柄了)会导致这个accept queue中的连接一直没法被accept对吗?

答:对

如果通过gdb attach 应用进程,故意让进程 accept,这个时候client还能连上应用吗?

答: 能,这个时候在client和server两边看到的连接状态都是 ESTABLISHED,只是Server上的全连接队列占用加1。连接握手并切换到ESTABLISHED状态都是由OS来负责的,应用不参与,ESTABLISHED后应用才能accept,进而收发数据。也就是能放入到全连接队列里面的连接肯定都是 ESTABLISHED 状态的了

接着上面的问题,如果新连接继续连接进而全连接队列满了呢?

答:那就连不上了,server端的OS因为全连接队列满了直接扔掉第一个syn握手包,这个时候连接在client端是SYN_SENT,Server端没有这个连接,这是因为syn到server端就直接被OS drop 了。

1
2
3
//如下图,本机测试,只有一个client端发起的syn_send, 3306的server端没有任何连接
$netstat -antp |grep -i 127.0.0.1:3306
tcp 0 1 127.0.0.1:61106 127.0.0.1:3306 SYN_SENT 21352/telnet

能进入到accept queue中的连接都是 ESTABLISHED,不管用户态有没有accept,用户态accept后队列大小减1

如果一个连接握手成功进入到accept queue但是应用accept前被对方RESET了呢?

答: 如果此时收到对方的RESET了,那么OS会释放这个连接。但是内核认为所有 listen 到的连接, 必须要 accept 走, 因为用户有权利知道有过这么一个连接存在过。所以OS不会到全连接队列拿掉这个连接,全连接队列数量也不会减1,直到应用accept这个连接,然后read/write才发现这个连接断开了,报communication failure异常

什么时候连接状态变成 ESTABLISHED

三次握手成功就变成 ESTABLISHED 了,不需要用户态来accept,如果握手第三步的时候OS发现全连接队列满了,这时OS会扔掉这个第三次握手ack,并重传握手第二步的syn+ack, 在OS端这个连接还是 SYN_RECV 状态的,但是client端是 ESTABLISHED状态的了。

这是在4000(tearbase)端口上全连接队列没满,但是应用不再accept了,nc用12346端口去连4000(tearbase)端口的结果

1
2
3
4
5
6
# netstat -at |grep ":12346 "
tcp 0 0 dcep-blockchain-1:12346 dcep-blockchai:terabase ESTABLISHED //server
tcp 0 0 dcep-blockchai:terabase dcep-blockchain-1:12346 ESTABLISHED //client
[root@dcep-blockchain-1 cfl-sm2-sm3]# ss -lt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 73 1024 *:terabase *:*

这是在4000(tearbase)端口上全连接队列满掉后,nc用12346端口去连4000(tearbase)端口的结果

1
2
3
4
5
6
# netstat -at |grep ":12346 "  
tcp 0 0 dcep-blockchai:terabase dcep-blockchain-1:12346 SYN_RECV //server
tcp 0 0 dcep-blockchain-1:12346 dcep-blockchai:terabase ESTABLISHED //client
# ss -lt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 1025 1024 *:terabase *:*

Intel AMD 鲲鹏 海光 飞腾性能PK

前言

本文在sysbench、tpcc等实践场景下对多款CPU的性能进行对比,同时分析各款CPU的硬件指标,最后分析不同场景下的实际性能和核心参数的关系。

本文的姊妹篇:十年后数据库还是不敢拥抱NUMA? 主要讲述的是 同一块CPU的不同NUMA结构配置带来的几倍性能差异,这些性能差异原因也可以从本文最后时延测试数据得到印证,一起阅读效果更好。

性能定义

同一个平台下(X86、ARM是两个平台)编译好的程序可以认为他们的 指令 数是一样的,那么执行效率就是每个时钟周期所能执行的指令数量了。

执行指令数量第一取决的就是CPU主频了,但是目前主流CPU都是2.5G左右,另外就是单核下的并行度(多发射)以及多核,再就是分支预测等,这些基本归结到了访问内存的延时。

X86和ARM这两不同平台首先指令就不一样了,然后还有上面所说的主频、内存时延的差异

IPC的说明:

IPC: insns per cycle insn/cycles 也就是每个时钟周期能执行的指令数量,越大程序跑的越快

程序的执行时间 = 指令数/(主频*IPC) //单核下,多核的话再除以核数

参与比较的几款CPU参数

先来看看测试所用到的几款CPU的主要指标,大家关注下主频、各级cache大小、numa结构

Hygon 7280

Hygon 7280 就是AMD Zen架构,最大IPC能到5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
架构:                           x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
Address sizes: 43 bits physical, 48 bits virtual
CPU: 128
在线 CPU 列表: 0-127
每个核的线程数: 2
每个座的核数: 32
座: 2
NUMA 节点: 8
厂商 ID: HygonGenuine
CPU 系列: 24
型号: 1
型号名称: Hygon C86 7280 32-core Processor
步进: 1
CPU MHz: 2194.586
BogoMIPS: 3999.63
虚拟化: AMD-V
L1d 缓存: 2 MiB
L1i 缓存: 4 MiB
L2 缓存: 32 MiB
L3 缓存: 128 MiB
NUMA 节点0 CPU: 0-7,64-71
NUMA 节点1 CPU: 8-15,72-79
NUMA 节点2 CPU: 16-23,80-87
NUMA 节点3 CPU: 24-31,88-95
NUMA 节点4 CPU: 32-39,96-103
NUMA 节点5 CPU: 40-47,104-111
NUMA 节点6 CPU: 48-55,112-119
NUMA 节点7 CPU: 56-63,120-127

AMD EPYC 7H12

AMD EPYC 7H12 64-Core(ECS,非物理机),最大IPC能到5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 64
On-line CPU(s) list: 0-63
Thread(s) per core: 2
Core(s) per socket: 16
座: 2
NUMA 节点: 2
厂商 ID: AuthenticAMD
CPU 系列: 23
型号: 49
型号名称: AMD EPYC 7H12 64-Core Processor
步进: 0
CPU MHz: 2595.124
BogoMIPS: 5190.24
虚拟化: AMD-V
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 32K
L1i 缓存: 32K
L2 缓存: 512K
L3 缓存: 16384K
NUMA 节点0 CPU: 0-31
NUMA 节点1 CPU: 32-63

Intel

这次对比测试用到了两块Intel CPU,分别是 8163、8269 。他们的信息如下,最大IPC 是4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 96
On-line CPU(s) list: 0-95
Thread(s) per core: 2
Core(s) per socket: 24
Socket(s): 2
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz
Stepping: 4
CPU MHz: 2499.121
CPU max MHz: 3100.0000
CPU min MHz: 1000.0000
BogoMIPS: 4998.90
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 33792K
NUMA node0 CPU(s): 0-95

-----8269CY
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 104
On-line CPU(s) list: 0-103
Thread(s) per core: 2
Core(s) per socket: 26
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Platinum 8269CY CPU @ 2.50GHz
Stepping: 7
CPU MHz: 3200.000
CPU max MHz: 3800.0000
CPU min MHz: 1200.0000
BogoMIPS: 4998.89
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 36608K
NUMA node0 CPU(s): 0-25,52-77
NUMA node1 CPU(s): 26-51,78-103

鲲鹏920

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[root@ARM 19:15 /root/lmbench3]
#numactl -H
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
node 0 size: 192832 MB
node 0 free: 146830 MB
node 1 cpus: 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 1 size: 193533 MB
node 1 free: 175354 MB
node 2 cpus: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
node 2 size: 193533 MB
node 2 free: 175718 MB
node 3 cpus: 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
node 3 size: 193532 MB
node 3 free: 183643 MB
node distances:
node 0 1 2 3
0: 10 12 20 22
1: 12 10 22 24
2: 20 22 10 12
3: 22 24 12 10

node 0 <------------ socket distance ------------> node 2
| (die distance) | (die distance)
node 1 node 3


#lscpu
Architecture: aarch64
Byte Order: Little Endian
CPU(s): 96
On-line CPU(s) list: 0-95
Thread(s) per core: 1
Core(s) per socket: 48
Socket(s): 2
NUMA node(s): 4
Model: 0
CPU max MHz: 2600.0000
CPU min MHz: 200.0000
BogoMIPS: 200.00
L1d cache: 64K
L1i cache: 64K
L2 cache: 512K
L3 cache: 24576K //一个Die下24core共享24M L3,每个core 1MB
NUMA node0 CPU(s): 0-23
NUMA node1 CPU(s): 24-47
NUMA node2 CPU(s): 48-71
NUMA node3 CPU(s): 72-95
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma dcpop asimddp asimdfhm

飞腾2500

飞腾2500用nop去跑IPC的话,只能到1,但是跑其它代码能到2.33,理论值据说也是4但是我没跑到过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#lscpu
Architecture: aarch64
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 1
Core(s) per socket: 64
Socket(s): 2
NUMA node(s): 16
Model: 3
BogoMIPS: 100.00
L1d cache: 32K
L1i cache: 32K
L2 cache: 2048K
L3 cache: 65536K
NUMA node0 CPU(s): 0-7
NUMA node1 CPU(s): 8-15
NUMA node2 CPU(s): 16-23
NUMA node3 CPU(s): 24-31
NUMA node4 CPU(s): 32-39
NUMA node5 CPU(s): 40-47
NUMA node6 CPU(s): 48-55
NUMA node7 CPU(s): 56-63
NUMA node8 CPU(s): 64-71
NUMA node9 CPU(s): 72-79
NUMA node10 CPU(s): 80-87
NUMA node11 CPU(s): 88-95
NUMA node12 CPU(s): 96-103
NUMA node13 CPU(s): 104-111
NUMA node14 CPU(s): 112-119
NUMA node15 CPU(s): 120-127
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid

单核以及超线程计算Prime性能比较

测试命令,这个测试命令无论在哪个CPU下,用2个物理核用时都是一个物理核的一半,所以这个计算是可以完全并行的

1
taskset -c 1 /usr/bin/sysbench --num-threads=1 --test=cpu --cpu-max-prime=50000 run //单核绑一个core; 2个thread就绑一对HT

测试结果为耗时,单位秒

测试项 AMD EPYC 7H12 2.5G CentOS 7.9 Hygon 7280 2.1GHz CentOS Hygon 7280 2.1GHz 麒麟 Intel 8269 2.50G Intel 8163 CPU @ 2.50GHz Intel E5-2682 v4 @ 2.50GHz
单核 prime 50000 耗时 59秒 IPC 0.56 77秒 IPC 0.55 89秒 IPC 0.56; 83 0.41 105秒 IPC 0.41 109秒 IPC 0.39
HT prime 50000 耗时 57秒 IPC 0.31 74秒 IPC 0.29 87秒 IPC 0.29 48 0.35 60秒 IPC 0.36 74秒 IPC 0.29

从上面的测试结果来看,简单纯计算场景下 AMD/海光 的单核能力还是比较强的,但是超线程完全不给力(数据库场景超线程就给力了);而Intel的超线程非常给力,一对超线程能达到单物理core的1.8倍,并且从E5到8269更是好了不少。
ARM基本都没有超线程所有没有跑鲲鹏、飞腾。

计算Prime毕竟太简单,让我们来看看他们在数据库下的真实能力吧

对比MySQL sysbench和tpcc性能

MySQL 默认用5.7.34社区版,操作系统默认是centos,测试中所有mysqld都做了绑核,一样的压力配置尽量将CPU跑到100%, HT表示将mysqld绑定到一对HT核。

sysbench点查

测试命令类似如下:

1
sysbench --test='/usr/share/doc/sysbench/tests/db/select.lua' --oltp_tables_count=1 --report-interval=1 --oltp-table-size=10000000  --mysql-port=3307 --mysql-db=sysbench_single --mysql-user=root --mysql-password='Bj6f9g96!@#'  --max-requests=0   --oltp_skip_trx=on --oltp_auto_inc=on  --oltp_range_size=5  --mysql-table-engine=innodb --rand-init=on   --max-time=300 --mysql-host=x86.51 --num-threads=4 run

测试结果分别取QPS/IPC两个数据(测试中的差异AMD、Hygon CPU跑在CentOS7.9, intel CPU、Kunpeng 920 跑在AliOS上, xdb表示用集团的xdb替换社区的MySQL Server, 麒麟是国产OS):

测试核数 AMD EPYC 7H12 2.5G Hygon 7280 2.1G Hygon 7280 2.1GHz 麒麟 Intel 8269 2.50G Intel 8163 2.50G Intel 8163 2.50G XDB5.7 鲲鹏 920-4826 2.6G 鲲鹏 920-4826 2.6G XDB8.0 FT2500 alisql 8.0 本地–socket
单核 24674 0.54 13441 0.46 10236 0.39 28208 0.75 25474 0.84 29376 0.89 9694 0.49 8301 0.46 3602 0.53
一对HT 36157 0.42 21747 0.38 19417 0.37 36754 0.49 35894 0.6 40601 0.65 无HT 无HT 无HT
4物理核 94132 0.52 49822 0.46 38033 0.37 90434 0.69 350% 87254 0.73 106472 0.83 34686 0.42 28407 0.39 14232 0.53
16物理核 325409 0.48 171630 0.38 134980 0.34 371718 0.69 1500% 332967 0.72 446290 0.85 //16核比4核好! 116122 0.35 94697 0.33 59199 0.6 8core:31210 0.59
32物理核 542192 0.43 298716 0.37 255586 0.33 642548 0.64 2700% 588318 0.67 598637 0.81 CPU 2400% 228601 0.36 177424 0.32 114020 0.65
说明:麒麟OS下CPU很难跑满,大致能跑到90%-95%左右,麒麟上装的社区版MySQL-5.7.29;飞腾要特别注意mysqld所在socket,同时以上飞腾数据都是走--socket压测锁的,32core走网络压测QPS为:99496(15%的网络损耗)

从上面的结果先看单物理核能力ARM 和 X86之间的差异还是很明显的

tpcc 1000仓

测试结果(测试中Hygon 7280分别跑在CentOS7.9和麒麟上, 鲲鹏/intel CPU 跑在AliOS、麒麟是国产OS):

tpcc测试数据,结果为1000仓,tpmC (NewOrders) ,未标注CPU 则为跑满了

测试核数 Intel 8269 2.50G Intel 8163 2.50G Hygon 7280 2.1GHz 麒麟 Hygon 7280 2.1G CentOS 7.9 鲲鹏 920-4826 2.6G 鲲鹏 920-4826 2.6G XDB8.0
1物理核 12392 9902 4706 7011 6619 4653
一对HT 17892 15324 8950 11778 无HT 无HT
4物理核 51525 40877 19387 380% 30046 23959 20101
8物理核 100792 81799 39664 750% 60086 42368 40572
16物理核 160798 抖动 140488 CPU抖动 75013 1400% 106419 1300-1550% 70581 1200% 79844
24物理核 188051 164757 1600-2100% 100841 1800-2000% 130815 1600-2100% 88204 1600% 115355
32物理核 195292 185171 2000-2500% 116071 1900-2400% 142746 1800-2400% 102089 1900% 143567
48物理核 19969l 195730 2100-2600% 128188 2100-2800% 149782 2000-2700% 116374 2500% 206055 4500%

测试过程CPU均跑满(未跑满的话会标注出来),IPC跑不起来性能就必然低,超线程虽然总性能好了但是会导致IPC降低(参考前面的公式)。可以看到对本来IPC比较低的场景,启用超线程后一般对性能会提升更大一些。

tpcc并发到一定程度后主要是锁导致性能上不去,所以超多核意义不大,可以做分库分表搞多个mysqld实例

比如在Hygon 7280 2.1GHz 麒麟上起两个MySQLD实例,每个实例各绑定32物理core,性能刚好翻倍:image-20210823082702539

32核的时候对比下MySQL 社区版在Hygon7280和Intel 8163下的表现,IPC的差异还是很明显的,基本和TPS差异一致:

image-20210817181752243

从sysbench和tpcc测试结果来看AMD和Intel差异不大,ARM和X86差异比较大,国产CPU还有很大的进步空间。就像前面所说抛开指令集的差异,主频差不多,内存管够为什么还有这么大的性能差别呢?

三款CPU的性能指标

下面让我们回到硬件本身的数据来看这个问题

先记住这个图,描述的是CPU访问寄存器、L1 cache、L2 cache等延时,关键记住他们的差异
各级延时

接下来用lmbench来测试各个机器的内存延时

stream主要用于测试带宽,对应的时延是在带宽跑满情况下的带宽。

lat_mem_rd用来测试操作不同数据大小的时延。

飞腾2500

用stream测试带宽和latency,可以看到带宽随着numa距离不断减少、对应的latency不断增加,到最近的numa node有10%的损耗,这个损耗和numactl给出的距离完全一致。跨socket访问内存latency是node内的3倍,带宽是三分之一,但是socket1性能和socket0性能完全一致。从这个延时来看如果要是跑一个32core的实例性能一定不会太好,并且抖动剧烈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
time for i in $(seq 7 8 128); do echo $i; numactl -C $i -m 0 ./bin/stream -W 5 -N 5 -M 64M; done

#numactl -C 7 -m 0 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 2.84 nanoseconds
STREAM copy bandwidth: 5638.21 MB/sec
STREAM scale latency: 2.72 nanoseconds
STREAM scale bandwidth: 5885.97 MB/sec
STREAM add latency: 2.26 nanoseconds
STREAM add bandwidth: 10615.13 MB/sec
STREAM triad latency: 4.53 nanoseconds
STREAM triad bandwidth: 5297.93 MB/sec

#numactl -C 7 -m 1 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 3.16 nanoseconds
STREAM copy bandwidth: 5058.71 MB/sec
STREAM scale latency: 3.15 nanoseconds
STREAM scale bandwidth: 5074.78 MB/sec
STREAM add latency: 2.35 nanoseconds
STREAM add bandwidth: 10197.36 MB/sec
STREAM triad latency: 5.12 nanoseconds
STREAM triad bandwidth: 4686.37 MB/sec

#numactl -C 7 -m 2 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 3.85 nanoseconds
STREAM copy bandwidth: 4150.98 MB/sec
STREAM scale latency: 3.95 nanoseconds
STREAM scale bandwidth: 4054.30 MB/sec
STREAM add latency: 2.64 nanoseconds
STREAM add bandwidth: 9100.12 MB/sec
STREAM triad latency: 6.39 nanoseconds
STREAM triad bandwidth: 3757.70 MB/sec

#numactl -C 7 -m 3 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 3.69 nanoseconds
STREAM copy bandwidth: 4340.24 MB/sec
STREAM scale latency: 3.62 nanoseconds
STREAM scale bandwidth: 4422.18 MB/sec
STREAM add latency: 2.47 nanoseconds
STREAM add bandwidth: 9704.82 MB/sec
STREAM triad latency: 5.74 nanoseconds
STREAM triad bandwidth: 4177.85 MB/sec

[root@101a05001.cloud.a05.am11 /root/lmbench3]
#numactl -C 7 -m 7 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 3.95 nanoseconds
STREAM copy bandwidth: 4051.51 MB/sec
STREAM scale latency: 3.94 nanoseconds
STREAM scale bandwidth: 4060.63 MB/sec
STREAM add latency: 2.54 nanoseconds
STREAM add bandwidth: 9434.51 MB/sec
STREAM triad latency: 6.13 nanoseconds
STREAM triad bandwidth: 3913.36 MB/sec

[root@101a05001.cloud.a05.am11 /root/lmbench3]
#numactl -C 7 -m 10 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 8.80 nanoseconds
STREAM copy bandwidth: 1817.78 MB/sec
STREAM scale latency: 8.59 nanoseconds
STREAM scale bandwidth: 1861.65 MB/sec
STREAM add latency: 5.55 nanoseconds
STREAM add bandwidth: 4320.68 MB/sec
STREAM triad latency: 13.94 nanoseconds
STREAM triad bandwidth: 1721.76 MB/sec

[root@101a05001.cloud.a05.am11 /root/lmbench3]
#numactl -C 7 -m 11 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 9.27 nanoseconds
STREAM copy bandwidth: 1726.52 MB/sec
STREAM scale latency: 9.31 nanoseconds
STREAM scale bandwidth: 1718.10 MB/sec
STREAM add latency: 5.65 nanoseconds
STREAM add bandwidth: 4250.89 MB/sec
STREAM triad latency: 14.09 nanoseconds
STREAM triad bandwidth: 1703.66 MB/sec

//在另外一个socket上测试本numa,和node0性能完全一致
[root@101a0500 /root/lmbench3]
#numactl -C 88 -m 11 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 2.93 nanoseconds
STREAM copy bandwidth: 5454.67 MB/sec
STREAM scale latency: 2.96 nanoseconds
STREAM scale bandwidth: 5400.03 MB/sec
STREAM add latency: 2.28 nanoseconds
STREAM add bandwidth: 10543.42 MB/sec
STREAM triad latency: 4.52 nanoseconds
STREAM triad bandwidth: 5308.40 MB/sec

[root@101a0500 /root/lmbench3]
#numactl -C 7 -m 15 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 8.73 nanoseconds
STREAM copy bandwidth: 1831.77 MB/sec
STREAM scale latency: 8.81 nanoseconds
STREAM scale bandwidth: 1815.13 MB/sec
STREAM add latency: 5.63 nanoseconds
STREAM add bandwidth: 4265.21 MB/sec
STREAM triad latency: 13.09 nanoseconds
STREAM triad bandwidth: 1833.68 MB/sec

Lat_mem_rd 用cpu7访问node0和node15对比结果,随着数据的加大,延时在加大,64M时能有3倍差距,和上面测试一致

下图 第一列 表示读写数据的大小(单位M),第二列表示访问延时(单位纳秒),一般可以看到在L1/L2/L3 cache大小的地方延时会有跳跃,远超过L3大小后,延时就是内存延时了

image-20210924185044090

测试命令如下

1
numactl -C 7 -m 0 ./bin/lat_mem_rd -W 5 -N 5 -t 64M  //-C 7 cpu 7, -m 0 node0, -W 热身 -t stride

同样的机型,开关numa的测试结果,关numa 时延、带宽都差了几倍,所以一定要开NUMA

image-20210924192330025

鲲鹏920

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#for i in $(seq 0 15); do echo core:$i; numactl -N $i -m 7 ./bin/stream  -W 5 -N 5 -M 64M; done
STREAM copy latency: 1.84 nanoseconds
STREAM copy bandwidth: 8700.75 MB/sec
STREAM scale latency: 1.86 nanoseconds
STREAM scale bandwidth: 8623.60 MB/sec
STREAM add latency: 2.18 nanoseconds
STREAM add bandwidth: 10987.04 MB/sec
STREAM triad latency: 3.03 nanoseconds
STREAM triad bandwidth: 7926.87 MB/sec

#numactl -C 7 -m 1 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 2.05 nanoseconds
STREAM copy bandwidth: 7802.45 MB/sec
STREAM scale latency: 2.08 nanoseconds
STREAM scale bandwidth: 7681.87 MB/sec
STREAM add latency: 2.19 nanoseconds
STREAM add bandwidth: 10954.76 MB/sec
STREAM triad latency: 3.17 nanoseconds
STREAM triad bandwidth: 7559.86 MB/sec

#numactl -C 7 -m 2 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 3.51 nanoseconds
STREAM copy bandwidth: 4556.86 MB/sec
STREAM scale latency: 3.58 nanoseconds
STREAM scale bandwidth: 4463.66 MB/sec
STREAM add latency: 2.71 nanoseconds
STREAM add bandwidth: 8869.79 MB/sec
STREAM triad latency: 5.92 nanoseconds
STREAM triad bandwidth: 4057.12 MB/sec

[root@ARM 19:14 /root/lmbench3]
#numactl -C 7 -m 3 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 3.94 nanoseconds
STREAM copy bandwidth: 4064.25 MB/sec
STREAM scale latency: 3.82 nanoseconds
STREAM scale bandwidth: 4188.67 MB/sec
STREAM add latency: 2.86 nanoseconds
STREAM add bandwidth: 8390.70 MB/sec
STREAM triad latency: 4.78 nanoseconds
STREAM triad bandwidth: 5024.25 MB/sec

#numactl -C 24 -m 3 ./bin/stream -W 5 -N 5 -M 64M
STREAM copy latency: 4.10 nanoseconds
STREAM copy bandwidth: 3904.63 MB/sec
STREAM scale latency: 4.03 nanoseconds
STREAM scale bandwidth: 3969.41 MB/sec
STREAM add latency: 3.07 nanoseconds
STREAM add bandwidth: 7816.08 MB/sec
STREAM triad latency: 5.06 nanoseconds
STREAM triad bandwidth: 4738.66 MB/sec

海光7280

可以看到跨numa(一个numa也就是一个socket,等同于跨socket)RT从1.5上升到2.5,这个数据比鲲鹏920要好很多。
这里还会测试同一块CPU设置不同数量的numa node对性能的影响,所以接下来的测试会列出numa node数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
[root@hygon8 14:32 /root/lmbench-master]
#lscpu
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
Address sizes: 43 bits physical, 48 bits virtual
CPU: 128
在线 CPU 列表: 0-127
每个核的线程数: 2
每个座的核数: 32
座: 2
NUMA 节点: 8
厂商 ID: HygonGenuine
CPU 系列: 24
型号: 1
型号名称: Hygon C86 7280 32-core Processor
步进: 1
CPU MHz: 2194.586
BogoMIPS: 3999.63
虚拟化: AMD-V
L1d 缓存: 2 MiB
L1i 缓存: 4 MiB
L2 缓存: 32 MiB
L3 缓存: 128 MiB
NUMA 节点0 CPU: 0-7,64-71
NUMA 节点1 CPU: 8-15,72-79
NUMA 节点2 CPU: 16-23,80-87
NUMA 节点3 CPU: 24-31,88-95
NUMA 节点4 CPU: 32-39,96-103
NUMA 节点5 CPU: 40-47,104-111
NUMA 节点6 CPU: 48-55,112-119
NUMA 节点7 CPU: 56-63,120-127

//可以看到7号core比15、23、31号core明显要快,就近访问node 0的内存,跨numa node(跨Die)没有内存交织分配
[root@hygon8 14:32 /root/lmbench-master]
#time for i in $(seq 7 8 64); do echo $i; numactl -C $i -m 0 ./bin/stream -W 5 -N 5 -M 64M; done
7
STREAM copy latency: 1.38 nanoseconds
STREAM copy bandwidth: 11559.53 MB/sec
STREAM scale latency: 1.16 nanoseconds
STREAM scale bandwidth: 13815.87 MB/sec
STREAM add latency: 1.40 nanoseconds
STREAM add bandwidth: 17145.85 MB/sec
STREAM triad latency: 1.44 nanoseconds
STREAM triad bandwidth: 16637.18 MB/sec
15
STREAM copy latency: 1.67 nanoseconds
STREAM copy bandwidth: 9591.77 MB/sec
STREAM scale latency: 1.56 nanoseconds
STREAM scale bandwidth: 10242.50 MB/sec
STREAM add latency: 1.45 nanoseconds
STREAM add bandwidth: 16581.00 MB/sec
STREAM triad latency: 2.00 nanoseconds
STREAM triad bandwidth: 12028.83 MB/sec
23
STREAM copy latency: 1.65 nanoseconds
STREAM copy bandwidth: 9701.49 MB/sec
STREAM scale latency: 1.53 nanoseconds
STREAM scale bandwidth: 10427.98 MB/sec
STREAM add latency: 1.42 nanoseconds
STREAM add bandwidth: 16846.10 MB/sec
STREAM triad latency: 1.97 nanoseconds
STREAM triad bandwidth: 12189.72 MB/sec
31
STREAM copy latency: 1.64 nanoseconds
STREAM copy bandwidth: 9742.86 MB/sec
STREAM scale latency: 1.52 nanoseconds
STREAM scale bandwidth: 10510.80 MB/sec
STREAM add latency: 1.45 nanoseconds
STREAM add bandwidth: 16559.86 MB/sec
STREAM triad latency: 1.92 nanoseconds
STREAM triad bandwidth: 12490.01 MB/sec
39
STREAM copy latency: 2.55 nanoseconds
STREAM copy bandwidth: 6286.25 MB/sec
STREAM scale latency: 2.51 nanoseconds
STREAM scale bandwidth: 6383.11 MB/sec
STREAM add latency: 1.76 nanoseconds
STREAM add bandwidth: 13660.83 MB/sec
STREAM triad latency: 3.68 nanoseconds
STREAM triad bandwidth: 6523.02 MB/sec

如果这种芯片在bios里设置Die interleaving,4块die当成一个numa node吐出来给OS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#lscpu
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
Address sizes: 43 bits physical, 48 bits virtual
CPU: 128
在线 CPU 列表: 0-127
每个核的线程数: 2
每个座的核数: 32
座: 2
NUMA 节点: 2
厂商 ID: HygonGenuine
CPU 系列: 24
型号: 1
型号名称: Hygon C86 7280 32-core Processor
步进: 1
CPU MHz: 2108.234
BogoMIPS: 3999.45
虚拟化: AMD-V
L1d 缓存: 2 MiB
L1i 缓存: 4 MiB
L2 缓存: 32 MiB
L3 缓存: 128 MiB
//注意这里bios配置了Die Interleaving Enable
//表示每路内多个Die内存交织分配,这样整个一个socket就是一个大Die
NUMA 节点0 CPU: 0-31,64-95
NUMA 节点1 CPU: 32-63,96-127


//enable die interleaving 后继续streaming测试
//最终测试结果表现就是7/15/23/31 core性能一致,因为默认一个numa内内存交织分配
//可以看到同一路下的四个die内存交织访问,所以4个node内存延时一样了(被平均),都不如8node就近快
[root@hygon3 16:09 /root/lmbench-master]
#time for i in $(seq 7 8 64); do echo $i; numactl -C $i -m 0 ./bin/stream -W 5 -N 5 -M 64M; done
7
STREAM copy latency: 1.48 nanoseconds
STREAM copy bandwidth: 10782.58 MB/sec
STREAM scale latency: 1.20 nanoseconds
STREAM scale bandwidth: 13364.38 MB/sec
STREAM add latency: 1.46 nanoseconds
STREAM add bandwidth: 16408.32 MB/sec
STREAM triad latency: 1.53 nanoseconds
STREAM triad bandwidth: 15696.00 MB/sec
15
STREAM copy latency: 1.51 nanoseconds
STREAM copy bandwidth: 10601.25 MB/sec
STREAM scale latency: 1.24 nanoseconds
STREAM scale bandwidth: 12855.87 MB/sec
STREAM add latency: 1.46 nanoseconds
STREAM add bandwidth: 16382.42 MB/sec
STREAM triad latency: 1.53 nanoseconds
STREAM triad bandwidth: 15691.48 MB/sec
23
STREAM copy latency: 1.50 nanoseconds
STREAM copy bandwidth: 10700.61 MB/sec
STREAM scale latency: 1.27 nanoseconds
STREAM scale bandwidth: 12634.63 MB/sec
STREAM add latency: 1.47 nanoseconds
STREAM add bandwidth: 16370.67 MB/sec
STREAM triad latency: 1.55 nanoseconds
STREAM triad bandwidth: 15455.75 MB/sec
31
STREAM copy latency: 1.50 nanoseconds
STREAM copy bandwidth: 10637.39 MB/sec
STREAM scale latency: 1.25 nanoseconds
STREAM scale bandwidth: 12778.99 MB/sec
STREAM add latency: 1.46 nanoseconds
STREAM add bandwidth: 16420.65 MB/sec
STREAM triad latency: 1.61 nanoseconds
STREAM triad bandwidth: 14946.80 MB/sec
39
STREAM copy latency: 2.35 nanoseconds
STREAM copy bandwidth: 6807.09 MB/sec
STREAM scale latency: 2.32 nanoseconds
STREAM scale bandwidth: 6906.93 MB/sec
STREAM add latency: 1.63 nanoseconds
STREAM add bandwidth: 14729.23 MB/sec
STREAM triad latency: 3.36 nanoseconds
STREAM triad bandwidth: 7151.67 MB/sec
47
STREAM copy latency: 2.31 nanoseconds
STREAM copy bandwidth: 6938.47 MB/sec

intel 8269CY

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 104
On-line CPU(s) list: 0-103
Thread(s) per core: 2
Core(s) per socket: 26
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Platinum 8269CY CPU @ 2.50GHz
Stepping: 7
CPU MHz: 3200.000
CPU max MHz: 3800.0000
CPU min MHz: 1200.0000
BogoMIPS: 4998.89
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 36608K
NUMA node0 CPU(s): 0-25,52-77
NUMA node1 CPU(s): 26-51,78-103

[root@numaopen.cloud.et93 /home/ren/lmbench3]
#time for i in $(seq 0 8 51); do echo $i; numactl -C $i -m 0 ./bin/stream -W 5 -N 5 -M 64M; done
0
STREAM copy latency: 1.15 nanoseconds
STREAM copy bandwidth: 13941.80 MB/sec
STREAM scale latency: 1.16 nanoseconds
STREAM scale bandwidth: 13799.89 MB/sec
STREAM add latency: 1.31 nanoseconds
STREAM add bandwidth: 18318.23 MB/sec
STREAM triad latency: 1.56 nanoseconds
STREAM triad bandwidth: 15356.72 MB/sec
16
STREAM copy latency: 1.12 nanoseconds
STREAM copy bandwidth: 14293.68 MB/sec
STREAM scale latency: 1.13 nanoseconds
STREAM scale bandwidth: 14162.47 MB/sec
STREAM add latency: 1.31 nanoseconds
STREAM add bandwidth: 18293.27 MB/sec
STREAM triad latency: 1.53 nanoseconds
STREAM triad bandwidth: 15692.47 MB/sec
32
STREAM copy latency: 1.52 nanoseconds
STREAM copy bandwidth: 10551.71 MB/sec
STREAM scale latency: 1.52 nanoseconds
STREAM scale bandwidth: 10508.33 MB/sec
STREAM add latency: 1.38 nanoseconds
STREAM add bandwidth: 17363.22 MB/sec
STREAM triad latency: 2.00 nanoseconds
STREAM triad bandwidth: 12024.52 MB/sec
40
STREAM copy latency: 1.49 nanoseconds
STREAM copy bandwidth: 10758.50 MB/sec
STREAM scale latency: 1.50 nanoseconds
STREAM scale bandwidth: 10680.17 MB/sec
STREAM add latency: 1.34 nanoseconds
STREAM add bandwidth: 17948.34 MB/sec
STREAM triad latency: 1.98 nanoseconds
STREAM triad bandwidth: 12133.22 MB/sec
48
STREAM copy latency: 1.49 nanoseconds
STREAM copy bandwidth: 10736.56 MB/sec
STREAM scale latency: 1.50 nanoseconds
STREAM scale bandwidth: 10692.93 MB/sec
STREAM add latency: 1.34 nanoseconds
STREAM add bandwidth: 17902.85 MB/sec
STREAM triad latency: 1.96 nanoseconds
STREAM triad bandwidth: 12239.44 MB/sec

Intel(R) Xeon(R) CPU E5-2682 v4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#time for i in $(seq 0 8 51); do echo $i; numactl -C $i -m 0 ./bin/stream -W 5 -N 5 -M 64M; done
0
STREAM copy latency: 1.59 nanoseconds
STREAM copy bandwidth: 10092.31 MB/sec
STREAM scale latency: 1.57 nanoseconds
STREAM scale bandwidth: 10169.16 MB/sec
STREAM add latency: 1.31 nanoseconds
STREAM add bandwidth: 18360.83 MB/sec
STREAM triad latency: 2.28 nanoseconds
STREAM triad bandwidth: 10503.81 MB/sec
8
STREAM copy latency: 1.55 nanoseconds
STREAM copy bandwidth: 10312.14 MB/sec
STREAM scale latency: 1.56 nanoseconds
STREAM scale bandwidth: 10283.70 MB/sec
STREAM add latency: 1.30 nanoseconds
STREAM add bandwidth: 18416.26 MB/sec
STREAM triad latency: 2.23 nanoseconds
STREAM triad bandwidth: 10777.08 MB/sec
16
STREAM copy latency: 2.02 nanoseconds
STREAM copy bandwidth: 7914.25 MB/sec
STREAM scale latency: 2.02 nanoseconds
STREAM scale bandwidth: 7919.85 MB/sec
STREAM add latency: 1.39 nanoseconds
STREAM add bandwidth: 17276.06 MB/sec
STREAM triad latency: 2.92 nanoseconds
STREAM triad bandwidth: 8231.18 MB/sec
24
STREAM copy latency: 1.99 nanoseconds
STREAM copy bandwidth: 8032.18 MB/sec
STREAM scale latency: 1.98 nanoseconds
STREAM scale bandwidth: 8061.12 MB/sec
STREAM add latency: 1.39 nanoseconds
STREAM add bandwidth: 17313.94 MB/sec
STREAM triad latency: 2.88 nanoseconds
STREAM triad bandwidth: 8318.93 MB/sec

#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 64
On-line CPU(s) list: 0-63
Thread(s) per core: 2
Core(s) per socket: 16
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 79
Model name: Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz
Stepping: 1
CPU MHz: 2500.000
CPU max MHz: 3000.0000
CPU min MHz: 1200.0000
BogoMIPS: 5000.06
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 40960K
NUMA node0 CPU(s): 0-15,32-47
NUMA node1 CPU(s): 16-31,48-63

stream对比数据

总结下几个CPU用stream测试访问内存的RT以及抖动和带宽对比数据

最小RT 最大RT 最大copy bandwidth 最小copy bandwidth
申威3231(2numa node) 7.09 8.75 2256.59 MB/sec 1827.88 MB/sec
飞腾2500(16 numa node) 2.84 10.34 5638.21 MB/sec 1546.68 MB/sec
鲲鹏920(4 numa node) 1.84 3.87 8700.75 MB/sec 4131.81 MB/sec
海光7280(8 numa node) 1.38 2.58 11591.48 MB/sec 6206.99 MB/sec
海光5280(4 numa node) 1.22 2.52 13166.34 MB/sec 6357.71 MB/sec
Intel8269CY(2 numa node) 1.12 1.52 14293.68 MB/sec 10551.71 MB/sec
Intel E5-2682(2 numa node) 1.58 2.02 10092.31 MB/sec 7914.25 MB/sec

从以上数据可以看出这5款CPU性能一款比一款好,飞腾2500慢的core上延时快到intel 8269的10倍了,平均延时5倍以上了。延时数据基本和单核上测试sysbench TPS一致。

lat_mem_rd对比数据

用不同的node上的core 跑lat_mem_rd测试访问node0内存的RT,只取最大64M的时延,时延和node距离完全一致,这里就不再列出测试原始数据了。

RT变化
飞腾2500(16 numa node) core:0 149.976
core:8 168.805
core:16 191.415
core:24 178.283
core:32 170.814
core:40 185.699
core:48 212.281
core:56 202.479
core:64 426.176
core:72 444.367
core:80 465.894
core:88 452.245
core:96 448.352
core:104 460.603
core:112 485.989
core:120 490.402
鲲鹏920(4 numa node) core:0 117.323
core:24 135.337
core:48 197.782
core:72 219.416
海光7280(8 numa node) numa0 106.839
numa1 168.583
numa2 163.925
numa3 163.690
numa4 289.628
numa5 288.632
numa6 236.615
numa7 291.880
分割行
enabled die interleaving
core:0 153.005
core:16 152.458
core:32 272.057
core:48 269.441
海光5280(4 numa node) core:0 102.574
core:8 160.989
core:16 286.850
core:24 231.197
Intel 8269CY(2 numa node) core:0 69.792
core:26 93.107
申威3231(2numa node) core:0 215.146
core:32 282.443

测试命令:

1
for i in $(seq 0 8 127); do echo core:$i; numactl -C $i -m 0 ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1

测试结果和numactl -H 看到的node distance完全一致,芯片厂家应该就是这样测试然后把这个延迟当做距离写进去了

最后用一张实际测试Inte E5 L1 、L2、L3的cache延时图来加深印象,可以看到在每级cache大小附近时延有个跳跃:
undefined
纵坐标是访问延时 纳秒,横坐标是cache大小 M,为什么上图没放内存延时,因为延时太大,放出来就把L1、L2的跳跃台阶压平了

结论

  • X86比ARM性能要好
  • AMD和Intel单核基本差别不大,Intel适合要求核多的大实例,AMD适合云上拆分售卖
  • 国产CPU还有比较大的进步空间
  • 性能上的差异在数据库场景下归因下来主要在CPU访问内存的时延上
  • 跨Numa Node时延差异很大,一定要开NUMA 就近访问内存
  • 数据库场景下大实例因为锁导致CPU很难跑满,建议 分库分表搞多个mysqld实例

如果你一定要知道一块CPU性能的话先看 内存延时 而不是 主频,各种CPU自家打榜一般都是简单计算场景,内存访问不多,但是实际业务中大部分时候又是高频访问内存的。

参考资料

十年后数据库还是不敢拥抱NUMA?
Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的
lmbench测试要考虑cache等
CPU的制造和概念
CPU 性能和Cache Line
Perf IPC以及CPU性能
CPU性能和CACHE

海光CPU

海光物理机CPU相关信息

总共有16台如下的海光服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 64
On-line CPU(s) list: 0-63
Thread(s) per core: 2 //每个物理core有两个超线程
Core(s) per socket: 16 //每路16个物理core
Socket(s): 2 //2路
NUMA node(s): 4
Vendor ID: HygonGenuine
CPU family: 24
Model: 1
Model name: Hygon C86 5280 16-core Processor
Stepping: 1
CPU MHz: 2455.552
CPU max MHz: 2500.0000
CPU min MHz: 1600.0000
BogoMIPS: 4999.26
Virtualization: AMD-V
L1d cache: 32K
L1i cache: 64K
L2 cache: 512K
L3 cache: 8192K
NUMA node0 CPU(s): 0-7,32-39
NUMA node1 CPU(s): 8-15,40-47
NUMA node2 CPU(s): 16-23,48-55
NUMA node3 CPU(s): 24-31,56-63
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid amd_dcm aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb hw_pstate sme ssbd sev ibpb vmmcall fsgsbase bmi1 avx2 smep bmi2 MySQLeed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 xsaves clzero irperf xsaveerptr arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif overflow_recov succor smca

#numactl -H
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3 4 5 6 7 32 33 34 35 36 37 38 39
node 0 size: 128854 MB
node 0 free: 89350 MB
node 1 cpus: 8 9 10 11 12 13 14 15 40 41 42 43 44 45 46 47
node 1 size: 129019 MB
node 1 free: 89326 MB
node 2 cpus: 16 17 18 19 20 21 22 23 48 49 50 51 52 53 54 55
node 2 size: 128965 MB
node 2 free: 86542 MB
node 3 cpus: 24 25 26 27 28 29 30 31 56 57 58 59 60 61 62 63
node 3 size: 129020 MB
node 3 free: 98227 MB
node distances:
node 0 1 2 3
0: 10 16 28 22
1: 16 10 22 28
2: 28 22 10 16
3: 22 28 16 10

AMD Zen 架构的CPU是胶水核,也就是把两个die拼一块封装成一块CPU,所以一块CPU内跨die之间延迟还是很高的。

7260 系列的hygon CPU(关掉了超线程)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 43 bits physical, 48 bits virtual
CPU(s): 48
On-line CPU(s) list: 0-47
Thread(s) per core: 1
Core(s) per socket: 24
Socket(s): 2
NUMA node(s): 8
Vendor ID: HygonGenuine
CPU family: 24
Model: 1
Model name: Hygon C86 7260 24-core Processor
Stepping: 1
Frequency boost: enabled
CPU MHz: 1065.890
CPU max MHz: 2200.0000
CPU min MHz: 1200.0000
BogoMIPS: 4399.38
Virtualization: AMD-V
L1d cache: 1.5 MiB
L1i cache: 3 MiB
L2 cache: 24 MiB
L3 cache: 128 MiB
NUMA node0 CPU(s): 0-5
NUMA node1 CPU(s): 6-11
NUMA node2 CPU(s): 12-17
NUMA node3 CPU(s): 18-23
NUMA node4 CPU(s): 24-29
NUMA node5 CPU(s): 30-35
NUMA node6 CPU(s): 36-41
NUMA node7 CPU(s): 42-47

7280

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 43 bits physical, 48 bits virtual
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 2
Core(s) per socket: 32
Socket(s): 2
NUMA node(s): 8
Vendor ID: HygonGenuine
CPU family: 24
Model: 1
Model name: Hygon C86 7280 32-core Processor
Stepping: 1
CPU MHz: 2313.699
BogoMIPS: 3999.47
Virtualization: AMD-V
L1d cache: 2 MiB
L1i cache: 4 MiB
L2 cache: 32 MiB
L3 cache: 128 MiB
NUMA node0 CPU(s): 0-7,64-71
NUMA node1 CPU(s): 8-15,72-79
NUMA node2 CPU(s): 16-23,80-87
NUMA node3 CPU(s): 24-31,88-95
NUMA node4 CPU(s): 32-39,96-103
NUMA node5 CPU(s): 40-47,104-111
NUMA node6 CPU(s): 48-55,112-119
NUMA node7 CPU(s): 56-63,120-127

64 个 core 的分配策略

1
2
3
4
5
physical         core      processor
0 0~15 0~15
1 0~15 16~31
0 0~15 32~47
1 0~15 48~63

海光bios配置

1
2
3
4
5
6
在grub.conf里面加入noibrs noibpb nopti nospectre_v2 nospectre_v1 l1tf=off nospec_store_bypass_disable no_stf_barrier mds=off tsx=on tsx_async_abort=off mitigations=off iommu.passthrough=1;持久化ip;挂盘参数defaults,noatime,nodiratime,lazytime,delalloc,nobarrier,data=writeback(因为后面步骤要重启,把一些OS优化也先做了)
2. bios设置里面
配置 Hygon 设定 --- DF选项 --- 内存交错 --- Channel
--- NB选项 --- 关闭iommu
打开CPB
风扇模式设置为高性能模式

海光简介

公司成立于2016年3月,当前送测处理器为其第一代1.0版本的7185对标处理器为Intel的E5-2680V4,其服务器样机为曙光H620-G30。

海光CPU的命名规则:
型号71xx
7:高端
1:海光1号
xx:sku

其后续roadmap如下图

image-20221026100149808

img

海光其产品规格如下,产品相对密集,但是产品之间差异化很小,频率总体接近。

img

AMD授权Zen IP给海光的操作是先成立合资公司,授权给合资公司基于Zen 研发新的 CPU,而且转让给中国的所有信息都符合美国出口法规**。**天津海光和AMD成立的合资公司可以修改AMD的CPU核,变相享有X86授权,而海光公司可以通过购买合资公司研发的CPU核,开发服务器CPU,不过仅仅局限于中国市场。

AMD与国内公司A成立合资公司B,合资公司B由AMD控股,负责开发CPU核(其实就是拿AMD现成的内核),然后公司A购买合资公司B开发的CPU核,以此为基础开发CPU,最终实现ARM卖IP核的翻版。

image-20221026100539350

image-20221026100646800

海光与AMD 的 Ryzen/EPYC 比较

由于在 Zen 1 的基础上进行了大量的修改,海光 CPU 可以不用简单地称之为换壳 AMD 处理器了。但其性能相比同代原版 CPU 略差:整数性能基本相同,浮点性能显著降低——普通指令吞吐量只有基准水平的一半。海光 CPU 的随机数生成机制也被修改,加密引擎已被替换,不再对常见的 AES 指令进行加速,但覆盖了其他面向国内安全性的指令如 SM2、SM3 和 SM4。

相同

与 AMD 的 Ryzen/EPYC 相比,海光处理器究竟有哪些不同?总体而言,核心布局是相同的,缓存大小、TLB 大小和端口分配都相同,在基础级别上两者没有差异。CPU 仍然是 64KB 四路 L1 指令缓存,32KB 八路 L1 数据缓存,512KB 八路 L2 缓存以及 8MB 十六路 L3 缓存,与 Zen 1 核心完全相同。

不同

加密方式变化**

在 Linux 内核升级中有关加密变化的信息已经明示。这些更新围绕 AMD 虚拟化功能(SEV)的安全加密进行。通常对于 EPYC 处理器来说,SEV 由 AMD 定义的加密协议控制,在这种情况下为 RSA、ECDSA、ECDH、SHA 和 AES。

但在海光 Dhyana 处理器中,SEV 被设计为使用 SM2、SM3 和 SM4 算法。在更新中有关 SM2 的部分声明道,这种算法基于椭圆曲线加密法,且需要其他私钥/公钥交换;SM3 是一种哈希算法,类似于 SHA-256;而 SM4 是类似于 AES-128 的分组密码算法。为支持这些算法所需的额外功能,其他指令也被加入到了 Linux 内核中。在说明文件中指出,这些算法已在 Hygon Dhyana Plus 处理器上成功进行测试,也已在 AMD 的 EPYC CPU 上成功测试。

此外,海光与 AMD 原版芯片最大的设计区别在于吞吐量,尽管整数性能相同,但海光芯片对于某些浮点指令并未做流水线处理,这意味着吞吐量和延迟都减小了:

img

这些对于最基础的任务来说也会有所影响,降低吞吐量的设计会让 CPU 在并行计算时性能受限。另外一个最大的变化,以及 Dhyana 与服务器版的「Dhyana Plus」版本之间的不同在于随机数生成的能力。

Openjdk 对海光的支持

https://github.com/openjdk/jdk/commit/d03cf75344fccba375881f0dab4ad169254e650c

https://bugs.openjdk.org/browse/JDK-8222090

https://github.com/dragonwell-project/dragonwell11/pull/517

比较不同 NUMA 方式

bios on and os cmdline off

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
lscpu
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
Address sizes: 43 bits physical, 48 bits virtual
CPU: 96
在线 CPU 列表: 0-95
每个核的线程数: 2
每个座的核数: 24
座: 2
NUMA 节点: 1
厂商 ID: HygonGenuine
CPU 系列: 24
型号: 1
型号名称: Hygon C86 7260 24-core Processor
步进: 1
Frequency boost: enabled
CPU MHz: 1603.426
CPU 最大 MHz: 2200.0000
CPU 最小 MHz: 1200.0000
BogoMIPS: 4399.55
虚拟化: AMD-V
L1d 缓存: 1.5 MiB
L1i 缓存: 3 MiB
L2 缓存: 24 MiB
L3 缓存: 128 MiB
NUMA 节点0 CPU: 0-95

# uname -r
4.19.90-23.8.v2101.ky10.x86_64

测试命令和结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//以下多个测试方式的结果一样
for i in $(seq 0 6 47); do echo core:$i; taskset -c $i ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1
for i in $(seq 0 6 47); do echo core:$i; numactl -C $i -m 0 ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1

cat lat.log |grep -E "core:|64.0000"
core:0
64.00000 270.555
core:6
64.00000 231.677
core:12
64.00000 268.527
core:18
64.00000 268.878
core:24
64.00000 158.644
core:30
64.00000 159.796
core:36
64.00000 162.938
core:42
64.00000 112.052


//不绑核会一直慢,因为刚好内存在高地址,程序大概率在低core上运行
for i in $(seq 0 6 47); do echo core:$i; numactl -C $i -m 0 ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1

#cat lat.log |grep -E "core:|64.0000"
core:0
64.00000 267.904
core:6
64.00000 266.112
core:12
64.00000 265.657
core:18
64.00000 266.033
core:24
64.00000 269.574
core:30
64.00000 269.640
core:36
64.00000 269.639
core:42
64.00000 266.373

如果绑核,看起来还是能识别距离远近,但是需要同时绑内存,默认绑核不绑核内存达不到就近分配

内置分配默认从高地址开始,所以core 0总是最慢的。

不绑核的话内存默认是在高地址,程序大概率远程访问内存,所以极慢

bios off

测试命令和结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//以下三个命令结果一致
for i in $(seq 0 6 47); do echo core:$i; taskset -c $i ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1
for i in $(seq 0 6 47); do echo core:$i; numactl -C $i -m 0 ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1
for i in $(seq 0 6 47); do echo core:$i; ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1

cat lat.log |grep -E "core:|64.0000"
core:0
64.00000 197.570
core:6
64.00000 204.362
core:12
64.00000 198.356
core:18
64.00000 197.049
core:24
64.00000 202.469
core:30
64.00000 199.367
core:36
64.00000 197.790
core:42
64.00000 197.757

rt稳定在200,之所以不符合短板原理是测试中多次取平均导致的,慢的还是慢,有的在近有的在远的地址,但平均值稳定

交错编址的时候不会把一个cacheline拆分到多个node下的内存条上

测试结果和OS的启动参数是否numa=off无关

bios off后没有机会识别内存远近,也就是反复循环分配内存不可能一直分配到本node内

bios on and os on

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 43 bits physical, 48 bits virtual
CPU(s): 48
On-line CPU(s) list: 0-47
Thread(s) per core: 1
Core(s) per socket: 24
Socket(s): 2
NUMA node(s): 8
Vendor ID: HygonGenuine
CPU family: 24
Model: 1
Model name: Hygon C86 7260 24-core Processor
Stepping: 1
Frequency boost: enabled
CPU MHz: 1069.030
CPU max MHz: 2200.0000
CPU min MHz: 1200.0000
BogoMIPS: 4399.35
Virtualization: AMD-V
L1d cache: 1.5 MiB
L1i cache: 3 MiB
L2 cache: 24 MiB
L3 cache: 128 MiB
NUMA node0 CPU(s): 0-5
NUMA node1 CPU(s): 6-11
NUMA node2 CPU(s): 12-17
NUMA node3 CPU(s): 18-23
NUMA node4 CPU(s): 24-29
NUMA node5 CPU(s): 30-35
NUMA node6 CPU(s): 36-41
NUMA node7 CPU(s): 42-47

测试命令和参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
for i in $(seq 0 6 47); do echo core:$i; numactl -C $i -m 0 ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1

# cat lat.log |grep -E "core:|64.0000"
core:0
64.00000 113.048
core:6
64.00000 167.637
core:12
64.00000 164.398
core:18
64.00000 163.328
core:24
64.00000 277.176
core:30
64.00000 277.157
core:36
64.00000 226.747
core:42
64.00000 278.472


绑核不绑内存或者不绑核运行结果是一样的
for i in $(seq 0 6 47); do echo core:$i; taskset -c $i ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1
for i in $(seq 0 6 47); do echo core:$i; taskset -c $i ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1

#cat lat.log |grep -E "core:|64.0000"
core:0
64.00000 112.990
core:6
64.00000 113.358
core:12
64.00000 114.146
core:18
64.00000 112.288
core:24
64.00000 114.103
core:30
64.00000 113.331
core:36
64.00000 114.151
core:42
64.00000 113.117

结论

  • 只要是bios numa off后用 lat_mem_rd 测试的 rt 是一个大规模次数后的平均值,但是远近内存问题仍然存在,会导致抖动和卡顿
  • 如果 bios numa on,但是 OS numa off,绑核的话会分别看到不同核访问内存差异极大
  • 如果 bios numa on,同时 OS numa on,这种情况绑核后会出现完美就近访问,性能最佳
  • 默认地址分配从高地址开始,如果numa off 那么core 0 最慢;如果 numa on 且绑核会一直快;如果 numa on 但是不绑核,多次测试也是一直快

一次海光物理机资源竞争压测的记录

问题描述

问题描述如下

sysbench 压200个服务节点(每个4c16G,总共800core), 发现qps不能线性增加(200节点比100节点好1.2倍而已)。

如果压单个服务节点节点QPS 2.4万,CPU跑到390%(每个服务节点独占4个核),如果压200个服务节点(分布在16台64核的海光物理机上)平均每个服务节点节点QPS才1.2万。但是每个服务节点的CPU也跑到了390%左右。 现在的疑问就是为什么CPU跑上去了QPS打了个5折。

机器集群为16*64core 为1024core,也就是每个服务节点独占4core还有冗余

因为服务节点还需要通过LVS调用后端的多个MySQL集群,所以需要排除LVS、网络等链路瓶颈,然后找到根因是什么。

海光物理机CPU相关信息

总共有16台如下的海光服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 64
On-line CPU(s) list: 0-63
Thread(s) per core: 2 //每个物理core有两个超线程
Core(s) per socket: 16 //每路16个物理core
Socket(s): 2 //2路
NUMA node(s): 4
Vendor ID: HygonGenuine
CPU family: 24
Model: 1
Model name: Hygon C86 5280 16-core Processor
Stepping: 1
CPU MHz: 2455.552
CPU max MHz: 2500.0000
CPU min MHz: 1600.0000
BogoMIPS: 4999.26
Virtualization: AMD-V
L1d cache: 32K
L1i cache: 64K
L2 cache: 512K
L3 cache: 8192K
NUMA node0 CPU(s): 0-7,32-39
NUMA node1 CPU(s): 8-15,40-47
NUMA node2 CPU(s): 16-23,48-55
NUMA node3 CPU(s): 24-31,56-63
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid amd_dcm aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb hw_pstate sme ssbd sev ibpb vmmcall fsgsbase bmi1 avx2 smep bmi2 MySQLeed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 xsaves clzero irperf xsaveerptr arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif overflow_recov succor smca

#numactl -H
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3 4 5 6 7 32 33 34 35 36 37 38 39
node 0 size: 128854 MB
node 0 free: 89350 MB
node 1 cpus: 8 9 10 11 12 13 14 15 40 41 42 43 44 45 46 47
node 1 size: 129019 MB
node 1 free: 89326 MB
node 2 cpus: 16 17 18 19 20 21 22 23 48 49 50 51 52 53 54 55
node 2 size: 128965 MB
node 2 free: 86542 MB
node 3 cpus: 24 25 26 27 28 29 30 31 56 57 58 59 60 61 62 63
node 3 size: 129020 MB
node 3 free: 98227 MB
node distances:
node 0 1 2 3
0: 10 16 28 22
1: 16 10 22 28
2: 28 22 10 16
3: 22 28 16 10

AMD Zen 架构的CPU是胶水核,也就是把两个die拼一块封装成一块CPU,所以一块CPU内跨die之间延迟还是很高的。

验证是否是上下游的瓶颈

需要先分析问题是否在LVS调用后端的多个MySQL集群上。

先写一个简单的测试程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#cat Test.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/*
* 目录:/home/admin/jdbc
*
* 编译:
* javac -cp /home/admin/lib/*:. Test.java
*
* 运行:
* java -cp /home/admin/MySQL-server/lib/*:. Test "jdbc:mysql://172.16.160.1:4261/qc_pay_0xwd_0002" "myhhzi0d" "jOXaC1Lbif-k" "select count(*) from pay_order where user_id=1169257092557639682 and order_no='201909292111250000102'" "100"
* */
public class Test {

public static void main(String args[]) throws NumberFormatException, InterruptedException, ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
String url = args[0];
String user = args[1];
String pass = args[2];
String sql = args[3];
String interval = args[4];
try {
Connection conn = DriverManager.getConnection(url, user, pass);
while (true) {
long start = System.currentTimeMillis();
for(int i=0; i<1000; ++i){
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
}
rs.close();
stmt.close();
Thread.sleep(Long.valueOf(interval));
}
long end = System.currentTimeMillis();
System.out.println("rt : " + (end - start));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

然后通过传入不同的jdbc参数跑2组测试:

  1. 走服务节点执行指定id的点查;
  2. 直接从服务节点节点连MySQL指定id点查

上述2组测试同时跑在三组场景下:

  • A) 服务节点和MySQL都没有压力;
  • B) 跑1、2测试的服务节点没有压力,但是sysbench 在压别的服务节点,这样后端的MySQL是有sysbench压侧压力,LVS也有流量压力的;
  • C) sysbench压所有服务节点, 包含运行 1、2测试程序节点)

这样2组测试3个场景组合可以得到6组响应时间的测试数据

从最终得到6组数据来看可以排除链路以及MySQL的问题,瓶颈似乎还是在服务节点上

image.png

单独压一个服务节点节点并在上面跑测试,服务节点 CPU被压到 390%(每个服务节点 节点固定绑到4核), 这个时候整个宿主机压力不大,但是这四个核比较紧张了

1
2
3
4
5
6
7
#cat rt.log  | awk '{ print $3 }'  | awk '{if(min==""){min=max=$1}; if($1>max) {max=$1}; if($1<min) {min=$1}; total+=$1; count+=1} END {print "avg " total/count," | max "max," | min " min, "| count ", count}' ; cat MySQL.log  | awk '{ print $3 }'  | awk '{if(min==""){min=max=$1}; if($1>max) {max=$1}; if($1<min) {min=$1}; total+=$1; count+=1} END {print "avg " total/count," | max "max," | min " min, "| count ", count }';
avg 2589.13 | max 3385 | min 2502 | count 69
avg 1271.07 | max 1405 | min 1254 | count 141

[root@d42a01107.cloud.a02.am78 /root]
#taskset -pc 48759
pid 48759's current affinity list: 19,52-54

通过这6组测试数据可以看到,只有在整个系统都有压力(服务节点所在物理机、LVS、MySQL)的时候rt飙升最明显(C组数据),如果只是LVS、MySQL有压力,服务节点没有压力的时候可以看到数据还是很好的(B组数据)

分析宿主机资源竞争

perf分析

只压单个服务节点

image.png

image.png

从以上截图,可以看到关键的 insn per cycle 能到0.51和0.66(这个数值越大性能越好)

如果同时压物理机上的所有服务节点

image.png

image.png

从以上截图,可以看到关键的 insn per cycle 能降到了0.27和0.31(这个数值越大性能越好),基本相当于单压的5折

通过 perf list 找出所有Hardware event,然后对他们进行perf:

1
sudo perf stat -e branch-instructions,branch-misses,cache-references,cpu-cycles,instructions,stalled-cycles-backend,stalled-cycles-frontend,L1-dcache-load-misses,L1-dcache-loads,L1-dcache-prefetches,L1-icache-load-misses,L1-icache-loads,branch-load-misses,branch-loads,dTLB-load-misses,dTLB-loads,iTLB-load-misses,iTLB-loads -a -- `pidof java`

尝试不同的绑核后的一些数据

通过以上perf数据以及numa结构,尝试将不同服务进程绑定到指定的4个核上

试了以下三种绑核的办法:

1)docker swarm随机绑(以上测试都是用的这种默认方案);

2)一个服务节点绑连续4个core,这4个core都在同一个node;

3)一个服务节点绑4个core,这个4个core都在在同一个node,同时尽量HT在一起,也就是0,1,32,33 ; 2,3,34,35 这种绑法

结果是绑法2性能略好.

如果是绑法2,压单个服务节点 QPS能到2.3万;绑法1和3,压单个服务节点性能差别不明显,都是2万左右。

尝试将Java进程开启HugePage

从perf数据来看压满后tlab miss比较高,得想办法降低这个值

修改JVM启动参数

JVM启动参数增加如下三个(-XX:LargePageSizeInBytes=2m, 这个一定要,有些资料没提这个,在我的JDK8.0环境必须要):

-XX:+UseLargePages -XX:LargePageSizeInBytes=2m -XX:+UseHugeTLBFS

修改机器系统配置

设置HugePage的大小

cat /proc/sys/vm/nr_hugepages

nr_hugepages设置多大参考如下计算方法:

If you are using the option -XX:+UseSHM or -XX:+UseHugeTLBFS, then specify the number of large pages. In the following example, 3 GB of a 4 GB system are reserved for large pages (assuming a large page size of 2048kB, then 3 GB = 3 * 1024 MB = 3072 MB = 3072 * 1024 kB = 3145728 kB and 3145728 kB / 2048 kB = 1536):

echo 1536 > /proc/sys/vm/nr_hugepages

透明大页是没有办法减少系统tlab,tlab是对应于进程的,系统分给进程的透明大页还是由物理上的4K page组成。

Java进程用上HugePages后iTLB-load-misses从80%下降到了14%左右, dTLB也从30%下降到了20%,但是ipc变化不明显,QPS有不到10%的增加(不能确定是不是抖动所致)

image.png

在公有云ecs虚拟机上测试对性能没啥帮助,实际看到用掉的HuagPage不多,如果/proc/sys/vm/nr_hugepages 设置比较大的话JVM会因为内存不足起不来,两者内存似乎是互斥的

用sysbench验证一下海光服务器的多core能力

Intel E5 2682 2.5G VS hygon 7280 2.0G(Zen1)

image-20210813095409553

image-20210813095757299

由以上两个测试结果可以看出单核能力hygon 7280 强于 Intel 2682,但是hygon超线程能力还是没有任何提升。Intel用超线程计算能将耗时从109秒降到74秒。但是hygon(Zen1) 只是从89秒降到了87秒,基本没有变化。

再补充一个Intel(R) Xeon(R) Platinum 8269CY CPU @ 2.50GHz 对比数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#taskset -c 1,53 /usr/bin/sysbench --num-threads=2 --test=cpu --cpu-max-prime=50000 run
sysbench 0.5: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 2
Random number generator seed is 0 and will be ignored


Primer numbers limit: 50000

Threads started!


General statistics:
total time: 48.5571s
total number of events: 10000
total time taken by event execution: 97.0944s
response time:
min: 8.29ms
avg: 9.71ms
max: 20.88ms
approx. 95 percentile: 9.71ms

Threads fairness:
events (avg/stddev): 5000.0000/2.00
execution time (avg/stddev): 48.5472/0.01

#taskset -c 1 /usr/bin/sysbench --num-threads=1 --test=cpu --cpu-max-prime=50000 run
sysbench 0.5: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1
Random number generator seed is 0 and will be ignored


Primer numbers limit: 50000

Threads started!


General statistics:
total time: 83.2642s
total number of events: 10000
total time taken by event execution: 83.2625s
response time:
min: 8.27ms
avg: 8.33ms
max: 10.03ms
approx. 95 percentile: 8.36ms

Threads fairness:
events (avg/stddev): 10000.0000/0.00
execution time (avg/stddev): 83.2625/0.00

#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 104
On-line CPU(s) list: 0-103
Thread(s) per core: 2
Core(s) per socket: 26
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Platinum 8269CY CPU @ 2.50GHz
Stepping: 7
CPU MHz: 3200.097
CPU max MHz: 3800.0000
CPU min MHz: 1200.0000
BogoMIPS: 4998.89
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 36608K
NUMA node0 CPU(s): 0-25,52-77
NUMA node1 CPU(s): 26-51,78-103
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch ida arat epb invpcid_single pln pts dtherm spec_ctrl ibpb_support tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm mpx rdt avx512f avx512dq rdseed adx smap clflushopt avx512cdavx512bw avx512vl xsaveopt xsavec xgetbv1 cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local cat_l3 mba

用sysbench 测试Hygon C86 5280 16-core Processor,分别1、8、16、24、32、40、48、56、64 个thread,32个thread前都是完美的线性增加,32core之后基本不增长了,这个应该能说明这个服务器就是32core的能力

sysbench –threads=1 –cpu-max-prime=50000 cpu run

image.png

对比下intel的 Xeon 104core,也是物理52core,但是性能呈现完美线性

image.png

openssl场景多核能力验证

1
openssl speed aes-256-ige -multi N

intel 52 VS 26,可以看到52个线程的性能大概是26个的1.8倍

image.png

intel 104 VS 52 线程,性能还能提升1.4倍

image.png

海光32 VS 16, 性能能提升大概1.8倍,跟intel一致

image.png

海光64 VS 32, 性能能提升大概1.2倍

image.png

总结下就是,在物理core数以内的线程数intel和海光性能基本增加一致;但如果超过物理core数开始使用HT后海光明显相比Intel差了很多。

intel超线程在openssl场景下性能能提升40%,海光就只能提升20%了。

对比一下鲲鹏920 ARM架构的芯片

1
2
3
4
5
6
7
8
#numactl -H
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
node 0 size: 773421 MB
node 0 free: 756092 MB
node distances:
node 0
0: 10

96核一起跑openssl基本就是1核的96倍,完美线性,这是因为鲲鹏就没有超线程,都是物理核。如果并发增加到192个,性能和96个基本一样的。

image.png

用Sysbench直接压MySQL oltp_read_only的场景

image.png

从1到10个thread的时候完美呈现线性,到20个thread就只比10个thread增加50%了,30thread比20增加40%,过了32个thread后增加10个core性能加不到10%了。

在32thread前,随着并发的增加 IPC也有所减少,这也是导致thread翻倍性能不能翻倍的一个主要原因。

基本也和openssl 场景一致,海光的HT基本可以忽略,做的不是很好。超过32个thread后(物理core数)性能增加及其微弱

结论

海光的一个core只有一个fpu,所以超线程算浮点完全没用.

FP处理所有矢量操作。简单的整数向量运算(例如shift,add)都可以在一个周期内完成,是AMD以前架构延迟的一半。基本浮点数学运算具有三个周期的延迟,其中包括乘法(用于双精度需要一个额外周期)。融合乘加是五个周期。

FP具有用于128位加载操作的单个管道。实际上,整个FP端都针对128位操作进行了优化。 Zen支持所有最新指令,例如SSE和AVX1/2。 256位AVX的设计方式是可以将它们作为两个独立的128位操作来执行。 Zen通过将这些指令作为两个操作。也就是说,Zen将256位操作分为两个µOP。同样,存储也是在128位块上完成的,从而使256位加载的有效吞吐量为每两个周期一个存储。这些管道之间的平衡相当好,因此大多数操作将安排至少两个管道,以保持每个周期至少一个这样的指令的吞吐量。暗示着,**256位操作将占用两倍的资源来完成操作(即2x寄存器,调度程序和端口)。这是AMD采取的一种折衷方案,有助于节省芯片空间和功耗。**相比之下,英特尔的竞争产品Skylake确实具有专用的256位电路。还应注意的是,英特尔的现代服务器级型号进一步扩展了此功能,以纳入支持AVX-512的专用512位电路,而性能最高的型号则具有二个专用的AVX-512单元。

此外,Zen还支持SHA和AES(并实现了2个AES单元),以提高加密性能。这些单位可以在浮点调度程序的管道0和1上找到。

这个也是为什么浮点比Intel X86会弱的原因。

一些其他对比结论

  • 对纯CPU 运算场景,并发不超过物理core时,比如Prime运算,比如DRDS(CPU bound,IO在网络,可以加并发弥补)
    • 海光的IPC能保持稳定;
    • intel的IPC有所下降,但是QPS在IPC下降后还能完美线性
  • 在openssl和MySQL oltp_read_only场景下
    • 如果并发没超过物理core数时,海光和Intel都能随着并发的翻倍性能能增加80%
    • 如果并发超过物理core数后,Intel还能随着并发的翻倍性能增加50%,海光增加就只有20%了
    • 简单理解在这两个场景下Intel的HT能发挥半个物理core的作用,海光的HT就只能发挥0.2个物理core的作用了
  • 海光5280/7280 是Zen1/Zen2的AMD 架构,每个core只有一个fpu,综上在多个场景下HT基本上都可以忽略

系列文章

CPU的制造和概念

[CPU 性能和Cache Line](/2021/05/16/CPU Cache Line 和性能/)

[Perf IPC以及CPU性能](/2021/05/16/Perf IPC以及CPU利用率/)

Intel、海光、鲲鹏920、飞腾2500 CPU性能对比

飞腾ARM芯片(FT2500)的性能测试

十年后数据库还是不敢拥抱NUMA?

一次海光物理机资源竞争压测的记录

[Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的](/2019/12/16/Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的/)

参考资料

How to use Huge Pages with Java and Linux这个资料中提到了Java使用HugePage的时候启动进程的用户权限问题,在我的docker容器中用的admin启动的进程,测试验证是不需要按资料中的设置。

Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的

华为TaiShan服务器ARMNginx应用调优案例 大量绑核、中断、Numa等相关调优信息

macOS下如何使用iTerm2访问水木社区

关键字: macOS、iTerm 、Dracula、ssh、bbs.newsmth.net

windows下有各种Term软件来帮助我们通过ssh访问bbs.newsmth.net, 但是工作环境切换到macOS后发现FTerm、CTerm这样的工具都没有对应的了。但是term下访问 bbs.newsmth.net 简直是太爽了,所以本文希望解决这个问题。

问题

ssh 访问 bbs.newsmth.net 是没问题的,但是要解决配色和字符编码问题

解决编码

在iTerm2的配置中增加一个profile,如下图 smth,主要是改字符编码集为 GB 18030,然后修改配色方案,我喜欢的Dracula不适合SMTH,十大完全看不了。

image-20210602133111201

执行脚本如下:

1
2
3
4
#cat /usr/local/bin/smth
echo -e "\033]50;SetProfile=smth\a" //切换到smth的profile,也就是切换到了 GB18030
sshpass -p'密码' ssh -o ServerAliveInterval=60 水木id@bbs.newsmth.net
echo -e "\033]50;SetProfile=Default\a" //切换回UTF8

SetProfile=smth用来解决profile切换,连smth term前切换成GB 18030,断开的时候恢复成UTF-8,要不然的话正常工作的命令行就乱码了。

解决配色问题

然后还是在profile里面把smth的配色方案改成:Tango Dark, 一切简直是完美,工作灌水两不误,别人还发现不了

最终效果

目录(右边是工作窗口):

image.png

十大,这个十大颜色和右边工作模式的配色方案不一样

image.png

断开后恢复成 Dracula 配色和UTF-8编码,不影响工作,别的工作tab也还是正常使用utf8

image.png

别的term网站也是类似,比如小百合、byr、ptt等

TCP疑难问题案例汇总

碰到各种奇葩的TCP相关问题,所以汇总记录一下。分析清楚这些问题的所有来龙去脉,就能帮你在TCP知识体系里建立几个坚固的抓手,让TCP知识慢慢在抓手之间生长和互通

服务不响应的现象或者奇怪异常的原因分析

一个黑盒程序奇怪行为的分析 listen端口上很快就全连接队列溢出了,导致整个程序不响应了

举三反一–从理论知识到实际问题的推导 服务端出现大量CLOSE_WAIT 个数正好 等于somaxconn(调整somaxconn大小后 CLOSE_WAIT 也会跟着变成一样的值)

活久见,TCP连接互串了 应用每过一段时间总是会抛出几个连接异常的错误,需要查明原因。排查后发现是TCP连接互串了,这个案例实在是很珍惜,所以记录一下。

如何创建一个自己连自己的TCP连接

传输速度分析

案例:TCP传输速度案例分析(长肥网络、rt升高、delay ack的影响等)

原理:就是要你懂TCP–性能和发送接收Buffer的关系:发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响。BDP、RT、带宽对传输速度又是怎么影响的

就是要你懂TCP–最经典的TCP性能问题 Nagle和Delay ack

就是要你懂TCP–性能优化大全

TCP队列问题以及连接数

到底一台服务器上最多能创建多少个TCP连接

就是要你懂TCP队列–通过实战案例来展示问题

就是要你懂TCP–半连接队列和全连接队列

就是要你懂TCP–握手和挥手

防火墙和reset定位分析

对ttl、identification等的运用

关于TCP连接的Keepalive和reset

就是要你懂网络–谁动了我的TCP连接

TCP相关参数

TCP相关参数解释

网络通不通是个大问题–半夜鸡叫

网络丢包

工具技巧篇

netstat定位性能案例

[netstat timer keepalive explain](/2017/08/28/netstat –timer/)

就是要你懂网络监控–ss用法大全

就是要你懂抓包–WireShark之命令行版tshark

[通过tcpdump对Unix Domain Socket 进行抓包解析](/2018/01/01/通过tcpdump对Unix Socket 进行抓包解析/)

如何追踪网络流量

一个黑盒程序奇怪行为的分析

问题描述:

从银行金主baba手里拿到一个区块链程序,监听4000,在我们的环境中4000端口上很快就全连接队列溢出了,导致整个程序不响应了。这个程序是黑盒子,没有源代码,但是在金主baba自己的环境运行正常(一样的OS)

如下图所示:

image.png

ss -lnt 看到全连接队列增长到了39,但是netstat -ant找不到这39个连接,本来是想看看队列堆了这么多连接,都是哪些ip连过来的,实际看不到这就奇怪了

同时验证过程发现我们的环境 4000端口上开了slb,也就是slb会不停滴探活4000端口,关掉slb探活后一切正常了。

所以总结下来问题就是:

  1. 为什么全连接队列里面的连接netstat看不到这些连接,但是ss能看到总数

  2. 为什么关掉slb就正常了

  3. 为什么应用不accept连接,也不close(应用是个黑盒子)

分析

为什么全连接队列里面的连接netstat/ss都看不到(ss能看到总数)

这是因为这些连接都是探活连接,三次握手后很快被slb reset了,在OS层面这个连接已经被释放,所以肯定看不见。反过来想要是netstat能看见这个连接,那么它的状态是什么? reset吗?tcp连接状态里肯定是没有reset状态的。

ss看到的总数是指只要这个连接没有被accept,那么连接队列里就还有这个连接,通过ss也能看到连接队列数量。

为什么会产生这个错误理解–全连接队列里面的连接netstat一定要能看到?

那是因为正常情况都是能看到的,从没有考虑过握手后很快reset的情况。也没反问过如果能看到这个连接该是什么状态呢?

这个连接被reset后,kernel会将全连接队列数量减1吗?

不会,按照我们的理解连接被reset释放后,那么kernel要释放全连接队列里面的这个连接,因为这些动作都是kernel负责,上层没法处理这个reset。实际上内核认为所有 listen 到的连接, 必须要 accept 走, 用户有权利知道存在过这么一个连接。

也就是reset后,连接在内核层面释放了,所以netstat/ss看不到,但是全连接队列里面的应用数不会减1,只有应用accept后队列才会减1,accept这个空连接后读写会报错。基本可以认为全连接队列溢出了,主要是应用accept太慢导致的。

当应用从accept队列读取到已经被reset了的连接的时候应用层会得到一个报错信息。

什么时候连接状态变成 ESTABLISHED

三次握手成功就变成 ESTABLISHED 了,三次握手成功的第一是收到第三步的ack并且全连接队列没有满,不需要用户态来accept,如果握手第三步的时候OS发现全连接队列满了,这时OS会扔掉这个第三次握手ack,并重传握手第二步的syn+ack, 在OS端这个连接还是 SYN_RECV 状态的,但是client端是 ESTABLISHED状态的了。

下面是在4000(tearbase)端口上全连接队列没满,但是应用不再accept了,nc用12346端口去连4000(tearbase)端口的结果

1
2
3
4
5
6
# netstat -at |grep ":12346 "
tcp 0 0 dcep-blockchain-1:12346 dcep-blockchai:terabase ESTABLISHED //server
tcp 0 0 dcep-blockchai:terabase dcep-blockchain-1:12346 ESTABLISHED //client
[root@dcep-blockchain-1 cfl-sm2-sm3]# ss -lt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 73 1024 *:terabase *:*

这是在4000(tearbase)端口上全连接队列满掉后,nc用12346端口去连4000(tearbase)端口的结果

1
2
3
4
5
6
# netstat -at |grep ":12346 "  
tcp 0 0 dcep-blockchai:terabase dcep-blockchain-1:12346 SYN_RECV //server
tcp 0 0 dcep-blockchain-1:12346 dcep-blockchai:terabase ESTABLISHED //client
# ss -lt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 1025 1024 *:terabase *:*

为什么关掉slb就正常了

slb探活逻辑是向监听端口发起三次握手,握手成功后立即发送一个reset断开连接

这是一个完整的探活过程:

image.png

关掉就正常后要结合第三个问题来讲

为什么应用不accept连接,也不close(应用是个黑盒子)

因为应用是个黑盒子,看不到源代码,只能从行为来分析了

从行为来看,这个应用在三次握手后,会主动给client发送一个12字节的数据,但是这个逻辑写在了accept主逻辑内部,一旦主动给client发12字节数据失败(比如这个连接reset了)那么一直卡在这里导致应用不再accept也不再close。

正确的实现逻辑是,accept在一个单独的线程里,一旦accept到一个新连接,那么就开启一个新的线程来处理这个新连接的读写。accept线程专注accept。

关掉slb后应用有机会发出这12个字节,然后accept就能继续了,否则就卡死了。

一些验证

nc测试连接4000端口

1
2
3
4
5
6
7
8
9
10
11
# nc -p 12346 dcep-blockchain-1 4000
 //握手后4000返回的内容

抓包:
11:03:16.762547 IP dcep-blockchain-1.12346 > dcep-blockchain-1.terabase: Flags [S], seq 397659761, win 43690, options [mss 65495,sackOK,TS val 2329725964 ecr 0,nop,wscale 7], length 0
04:42:24.466211 IP dcep-blockchain-1.terabase > dcep-blockchain-1.12346: Flags [S.], seq 4239354556, ack 397659762, win 43690, options [mss 65495,sackOK,TS val 2329725964 ecr 2329725964,nop,wscale 7], length 0
11:03:16.762571 IP dcep-blockchain-1.12346 > dcep-blockchain-1.terabase: Flags [.], ack 1, win 342, options [nop,nop,TS val 2329725964 ecr 2329725964], length 0

----到这三次握手完毕,下面是隔了大概1.5ms,4000发了12字节给nc
11:03:16.763893 IP dcep-blockchain-1.terabase > dcep-blockchain-1.12346: Flags [P.], seq 1:13, ack 1, win 342, options [nop,nop,TS val 2329725966 ecr 2329725964], length 12
11:03:16.763904 IP dcep-blockchain-1.12346 > dcep-blockchain-1.terabase: Flags [.], ack 13, win 342, options [nop,nop,TS val 2329725966 ecr 2329725966], length 0

如果在上面的1.5ms之间nc reset了这个连接,那么这12字节就发不出来了

握手后Server主动发数据的行为非常像MySQL Server

MySQL Server在收到mysql client连接后会主动发送 Server Greeting、版本号、认证方式等给client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#nc -p 12345 127.0.0.1 3306
J
5.6.29�CuaV9v0xo�!
qCHRrGRIJqvzmysql_native_password

#tcpdump -i any port 12345 -ennt
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
In 00:00:00:00:00:00 ethertype IPv4 (0x0800), length 76: 127.0.0.1.12345 > 127.0.0.1.3306: Flags [S], seq 3186409724, win 43690, options [mss 65495,sackOK,TS val 3967896050 ecr 0,nop,wscale 7], length 0
In 00:00:00:00:00:00 ethertype IPv4 (0x0800), length 76: 127.0.0.1.3306 > 127.0.0.1.12345: Flags [S.], seq 4188709983, ack 3186409725, win 43690, options [mss 65495,sackOK,TS val 3967896051 ecr 3967896050,nop,wscale 7], length 0
In 00:00:00:00:00:00 ethertype IPv4 (0x0800), length 68: 127.0.0.1.12345 > 127.0.0.1.3306: Flags [.], ack 1, win 342, options [nop,nop,TS val 3967896051 ecr 3967896051], length 0 // 握手完毕
In 00:00:00:00:00:00 ethertype IPv4 (0x0800), length 146: 127.0.0.1.3306 > 127.0.0.1.12345: Flags [P.], seq 1:79, ack 1, win 342, options [nop,nop,TS val 3967896051 ecr 3967896051], length 78 //Server 发出Greeting
In 00:00:00:00:00:00 ethertype IPv4 (0x0800), length 68: 127.0.0.1.12345 > 127.0.0.1.3306: Flags [.], ack 79, win 342, options [nop,nop,TS val 3967896051 ecr 3967896051], length 0
In 00:00:00:00:00:00 ethertype IPv4 (0x0800), length 68: 127.0.0.1.3306 > 127.0.0.1.12345: Flags [F.], seq 79, ack 1, win 342, options [nop,nop,TS val 3967913551 ecr 3967896051], length 0
In 00:00:00:00:00:00 ethertype IPv4 (0x0800), length 68: 127.0.0.1.12345 > 127.0.0.1.3306: Flags [.], ack 80, win 342, options [nop,nop,TS val 3967913591 ecr 3967913551], length 0

如下是Server发出的长度为 78 的 Server Greeting信息内容

image.png

理论上如果slb探活连接检查MySQL Server的状态的时候也是很快reset了,如果MySQL Server程序写得烂的话也会出现同样的情况。

但是比如我们有实验验证MySQL Server 是否正常的时候会用 nc 去测试,一般以能看到

5.6.29�CuaV9v0xo�!
qCHRrGRIJqvzmysql_native_password

就认为MySQL Server是正常的。但是真的是这样吗?我们看看 nc 的如下案例

nc 6.4 快速fin

#nc –version
Ncat: Version 6.40 ( http://nmap.org/ncat )

用 nc 测试发现有一定的概率没有出现上面的Server Greeting信息,那么这是因为MySQL Server服务不正常了吗?

image.png

nc -i 3 10.97.170.11 3306 -w 4 -p 1234

-i 3 表示握手成功后 等三秒钟nc退出(发fin)

nc 6.4 握手后立即发fin断开连接,导致可能收不到Greeting,换成7.5或者mysql client就OK了

nc 7.5的抓包,明显可以看到nc在发fin前会先等4秒钟:

image.png

tcpping 模拟slb 探活

1
python tcpping.py -R -i 0.1 -t 1 dcep-blockchain-1 4000

-i 间隔0.1秒

-R reset断开连接

-t 超时时间1秒

执行如上代码,跟4000端口握手,然后立即发出reset断开连接(完全模拟slb探活行为),很快重现了问题

增加延时

-D 0.01表示握手成功后10ms后再发出reset(让应用有机会成功发出那12个字节),应用工作正常

1
python tcpping.py -R -i 0.1 -t 1 -D 0.01 dcep-blockchain-1 4000

总结

最大的错误认知就是 ss 看到的全连接队列数量,netstat也能看到。实际是不一定,而这个快速reset+应用不accept就导致了看不到这个现象

journald和rsyslogd

碰到rsyslog-8.24.0-34.1.al7.x86_64 的 rsyslogd 占用内存过高,于是分析了一下原因并学习了一下系统日志、rsyslog、journald之间的关系,流水账记录此文。

rsyslogd 占用内存过高的分析

rsyslogd使用了大概1.6-2G内存,不正常(正常情况下内存占用30-50M之间)

现象:

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
KiB Mem :  7971268 total,   131436 free,  7712020 used,   127812 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 43484 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
24850 admin 20 0 8743896 5.1g 0 S 2.0 66.9 1413:55 java
1318 root 20 0 2380404 1.6g 536 S 0.0 21.6 199:09.36 rsyslogd

# systemctl status rsyslog
● rsyslog.service - System Logging Service
Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2020-10-20 16:01:01 CST; 3 months 8 days ago
Docs: man:rsyslogd(8)
http://www.rsyslog.com/doc/
Main PID: 1318 (rsyslogd)
CGroup: /system.slice/rsyslog.service
└─1318 /usr/sbin/rsyslogd -n

Jan 28 09:10:07 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: sd_journal_get_cursor() failed: 'Cannot assign requested address' [v8.24.0-34.1.al7]
Jan 28 09:10:07 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: imjournal: journal reloaded... [v8.24.0-34.1.al7 try http://www.rsyslog.com/e/0 ]
Jan 28 10:27:48 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: sd_journal_get_cursor() failed: 'Cannot assign requested address' [v8.24.0-34.1.al7]
Jan 28 10:27:49 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: imjournal: journal reloaded... [v8.24.0-34.1.al7 try http://www.rsyslog.com/e/0 ]
Jan 28 11:45:23 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: sd_journal_get_cursor() failed: 'Cannot assign requested address' [v8.24.0-34.1.al7]
Jan 28 11:45:24 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: imjournal: journal reloaded... [v8.24.0-34.1.al7 try http://www.rsyslog.com/e/0 ]
Jan 28 13:03:00 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: sd_journal_get_cursor() failed: 'Cannot assign requested address' [v8.24.0-34.1.al7]
Jan 28 13:03:01 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: imjournal: journal reloaded... [v8.24.0-34.1.al7 try http://www.rsyslog.com/e/0 ]
Jan 28 14:20:42 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: sd_journal_get_cursor() failed: 'Cannot assign requested address' [v8.24.0-34.1.al7]
Jan 28 14:20:42 iZwz95gaul6x9167sqdqz4Z rsyslogd[1318]: imjournal: journal reloaded... [v8.24.0-34.1.al7 try http://www.rsyslog.com/e/0 ]


# grep HUPed /var/log/messages
Jan 24 03:39:15 iZwz95gaul6x9167sqdqz4Z rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-34.1.al7" x-pid="1318" x-info="http://www.rsyslog.com"] rsyslogd was HUPed

# journalctl --verify
PASS: /var/log/journal/20190829214900434421844640356160/system@efef6fd56e2e4c9f861d0be25c8c0781-0000000001567546-0005b9e2e02a0a4f.journal
PASS: /var/log/journal/20190829214900434421844640356160/system@efef6fd56e2e4c9f861d0be25c8c0781-00000000015ae56b-0005b9ea76e922e9.journal
1be1e0: Data object references invalid entry at 1d03018
File corruption detected at /var/log/journal/20190829214900434421844640356160/system.journal:1d02d80 (of 33554432 bytes, 90%).
FAIL: /var/log/journal/20190829214900434421844640356160/system.journal (Bad message)

journalctl --verify命令检查发现系统日志卷文件损坏

问题根因

来自redhat官网的描述

image.png

以下是现场收集到的日志:

image.png

主要是rsyslogd的sd_journal_get_cursor报错,然后导致内存泄露。

journald 报Bad message, 跟rsyslogd内存泄露完全没关系,实际上升级rsyslogd后也有journald bad message,但是rsyslogd的内存一直稳定在30M以内

这个CSDN的文章中有完全一样的症状 但是作者的结论是:这是systemd的bug,在journald需要压缩的时候就会发生这个问题。实际上我用的是 systemd-219-62.6.al7.9.x86_64 比他描述的已经修复的版本还要要新,也还是有这个问题,所以这个结论是不对的

解决办法

1、重启rsyslog systemctl restart rsyslog 可以释放内存

2、升级rsyslog到rsyslog-8.24.0-38.1.al7.x86_64或更新的版本才能彻底修复这个问题

一些配置方法

修改配置/etc/rsyslog.conf,增加如下两行,然后重启systemctl restart rsyslog

1
2
3
$imjournalRatelimitInterval 0
$imjournalRatelimitBurst 0
12

1、关掉journal压缩配置

vi /etc/systemd/journald.conf,把#Compress=yes改成Compress=no,之后systemctl restart systemd-journald即可

2、限制rsyslogd 内存大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat /etc/systemd/system/multi-user.target.wants/rsyslog.service

在Service配置中添加MemoryAccounting=yes,MemoryMax=80M,MemoryHigh=8M三项如下所示。
[Service]
Type=notify
EnvironmentFile=-/etc/sysconfig/rsyslog
ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS
Restart=on-failure
UMask=0066
StandardOutput=null
Restart=on-failure
MemoryAccounting=yes
MemoryMax=80M
MemoryHigh=8M

OOM kill

rsyslogd内存消耗过高后导致了OOM Kill

image.png

RSS对应物理内存,单位是4K(page大小),红框两个进程用了5G+2G,总内存是8G,所以触发OOM killer了

每次OOM Kill日志前后总带着systemd-journald的重启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z journal: Permanent journal is using 520.0M (max allowed 500.0M, trying to leave 4.0G free of 83.7G available → current limit 520.0M).
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z journal: Journal started
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: AliYunDun invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), nodemask=(null), order=0, oom_score_adj=0
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: AliYunDun cpuset=/ mems_allowed=0
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: CPU: 3 PID: 13296 Comm: AliYunDun Tainted: G OE 4.19.57-15.1.al7.x86_64 #1
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: Hardware name: Alibaba Cloud Alibaba Cloud ECS, BIOS 8c24b4c 04/01/2014
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: Call Trace:
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: dump_stack+0x5c/0x7b
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: dump_header+0x77/0x29f
***
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: [ 18118] 0 18118 28218 255 245760 0 0 sshd
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: Out of memory: Kill process 18665 (java) score 617 or sacrifice child
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: Killed process 18665 (java) total-vm:8446992kB, anon-rss:4905856kB, file-rss:0kB, shmem-rss:0kB
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z kernel: oom_reaper: reaped process 18665 (java), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z systemd: systemd-journald.service watchdog timeout (limit 3min)!
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z rsyslogd: sd_journal_get_cursor() failed: 'Cannot assign requested address' [v8.24.0-34.1.al7]
Jan 28 19:03:04 iZwz95gaul6x9167sqdqz5Z rsyslogd: imjournal: journal reloaded... [v8.24.0-34.1.al7 try http://www.rsyslog.com/e/0 ]
Jan 28 20:14:38 iZwz95gaul6x9167sqdqz5Z rsyslogd: imjournal: journal reloaded... [v8.24.0-57.1.al7 try http://www.rsyslog.com/e/0 ]

image.png

OOM kill前大概率伴随着systemd-journald 重启是因为watch dog timeout(limit 3min),造成timeout的原因是journald定期要把日志刷到磁盘上,然后要么是内存不够,要么是io负载太重,导致刷磁盘这个过程非常慢,于是就timeout了。

当然systemd-journald 重启也不一定意味着OOM Killer,只是肯定是内存比较紧张了。

What is the difference between syslog, rsyslog and syslog-ng?

Basically, they are all the same, in the way they all permit the logging of data from different types of systems in a central repository.

But they are three different project, each project trying to improve the previous one with more reliability and functionalities.

The Syslog project was the very first project. It started in 1980. It is the root project to Syslog protocol. At this time Syslog is a very simple protocol. At the beginning it only supports UDP for transport, so that it does not guarantee the delivery of the messages.

Next came syslog-ng in 1998. It extends basic syslog protocol with new features like:

  • content-based filtering
  • Logging directly into a database
  • TCP for transport
  • TLS encryption

Next came Rsyslog in 2004. It extends syslog protocol with new features like:

  • RELP Protocol support
  • Buffered operation support

rsyslog和journald的基础知识

systemd-journald是用来协助rsyslog记录系统启动服务和服务启动失败的情况等等. systemd-journald使用内存保存记录, 系统重启记录会丢失. 所有还要用rsyslog来记录分类信息, 如上面/etc/rsyslog.d/listen.conf中的syslog分类.

systemd-journald跟随systemd开机就启动,能及时记录所有日志:

1
2
3
4
5
6
7
# systemd-analyze critical-chain systemd-journald.service
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.

systemd-journald.service +13ms
└─system.slice
└─-.slice

systemd-journald 由于是使用于内存的登录文件记录方式,因此重新开机过后,开机前的登录文件信息当然就不会被记载了。 为此,我们还是建议启动 rsyslogd 来协助分类记录!也就是说, systemd-journald 用来管理与查询这次开机后的登录信息,而 rsyslogd 可以用来记录以前及现在的所以数据到磁盘文件中,方便未来进行查询喔!

Tips 虽然 systemd-journald 所记录的数据其实是在内存中,但是系统还是利用文件的型态将它记录到 /run/log/ 下面! 不过我们从前面几章也知道, /run 在 CentOS 7 其实是内存内的数据,所以重新开机过后,这个 /run/log 下面的数据当然就被刷新,旧的当然就不再存在了!

其实鸟哥是这样想的,既然我们还有 rsyslog.service 以及 logrotate 的存在,因此这个 systemd-journald.service 产生的登录文件, 个人建议最好还是放置到 /run/log 的内存当中,以加快存取的速度!而既然 rsyslog.service 可以存放我们的登录文件, 似乎也没有必要再保存一份 journal 登录文件到系统当中就是了。单纯的建议!如何处理,依照您的需求即可喔!

system-journal服务监听 /dev/log socket获取日志, 保存在内存中, 并间歇性的写入/var/log/journal目录中.

rsyslog服务启动后监听/run/systemd/journal/socket 获取syslog类型日志, 并写入/var/log/messages文件中.

获取日志时需要记录日志条目的position/var/lib/rsyslog/imjournal.state文件中.

比如haproxy日志配置:

1
2
3
4
# cat /etc/haproxy/haproxy.cfg
global
# log发给journald(journald监听 /dev/log)
log /dev/log local1 warning

以下是drds 的iptables日志配置,将tcp reset包记录下来,默认iptable日志输出到/varlog/messages中(dmesg也能看到),然后可以通过rsyslog.d 配置将这部分日志输出到单独的文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 配置iptables 日志,增加 [drds] 标识
# cat /home/admin/drds-worker/install/drds_filter.conf
# Generated by iptables-save v1.4.21 on Wed Apr 1 11:39:31 2020
*filter
:INPUT ACCEPT [557:88127]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [527:171711]
-A INPUT -p tcp -m tcp ! --sport 3406 --tcp-flags RST RST -j LOG --log-prefix "[drds] " --log-level 7 --log-tcp-sequence --log-tcp-options --log-ip-options
# -A INPUT -p tcp -m tcp ! --dport 3406 --tcp-flags RST RST -j LOG --log-prefix "[drds] " --log-level7 --log-tcp-sequence --log-tcp-options --log-ip-options
-A OUTPUT -p tcp -m tcp ! --sport 3406 --tcp-flags RST RST -j LOG --log-prefix "[drds] " --log-level 7 --log-tcp-sequence --log-tcp-options --log-ip-options
COMMIT
# Completed on Wed Apr 1 11:39:31 2020

#通过rsyslogd将日志写出到指定位置(不配置的话默认输出到 dmesg)
# cat /etc/rsyslog.d/drds_filter_log.conf
:msg, startswith, "[drds]" -/home/admin/logs/tcp-rt/drds-tcp.log

journald log持久化

创建 /var/log/journal 文件夹后默认会持久化,设置持久化后 /run/log 里面就没有日志了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# cat /etc/systemd/journald.conf
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Entries in this file show the compile time defaults.
# You can change settings by editing this file.
# Defaults can be restored by simply deleting this file.
#
# See journald.conf(5) for details.

[Journal]
#Storage=auto //默认如果有 /var/log/journal 目录就会持久化到这里
Compress=no
#Seal=yes
#SplitMode=uid
#SyncIntervalSec=5m
#RateLimitInterval=30s
#RateLimitBurst=1000
SystemMaxUse=500M //最多保留500M日志文件,免得撑爆磁盘
#SystemKeepFree=
#SystemMaxFileSize=
#RuntimeMaxUse=
#RuntimeKeepFree=
#RuntimeMaxFileSize=
#MaxRetentionSec=
#MaxFileSec=1month
#ForwardToSyslog=yes
#ForwardToKMsg=no
#ForwardToConsole=no
#ForwardToWall=yes
#TTYPath=/dev/console
#MaxLevelStore=debug
#MaxLevelSyslog=debug
#MaxLevelKMsg=notice
#MaxLevelConsole=info
#MaxLevelWall=emerg
#LineMax=48K

清理日志保留1M:journalctl –vacuum-size=1M

设置最大保留500M日志: journalctl –vacuum-size=500

rsyslogd

以下内容来自鸟哥的书:

CentOS 7 除了保有既有的 rsyslog.service 之外,其实最上游还使用了 systemd 自己的登录文件日志管理功能喔!他使用的是 systemd-journald.service 这个服务来支持的。基本上,系统由 systemd 所管理,那所有经由 systemd 启动的服务,如果再启动或结束的过程中发生一些问题或者是正常的讯息, 就会将该讯息由 systemd-journald.service 以二进制的方式记录下来,之后再将这个讯息发送给 rsyslog.service 作进一步的记载。

基本上, rsyslogd 针对各种服务与讯息记录在某些文件的配置文件就是 /etc/rsyslog.conf, 这个文件规定了“(1)什么服务 (2)的什么等级讯息 (3)需要被记录在哪里(设备或文件)” 这三个咚咚,所以设置的语法会是这样:

1
2
3
4
5
6
$cat /etc/rsyslog.conf
服务名称[.=!]讯息等级 讯息记录的文件名或设备或主机
# 下面以 mail 这个服务产生的 info 等级为例:
mail.info /var/log/maillog_info
# 这一行说明:mail 服务产生的大于等于 info 等级的讯息,都记录到
# /var/log/maillog_info 文件中的意思。

syslog 所制订的服务名称与软件调用的方式

CentOS 7.x 默认的 rsyslogd 本身就已经具有远程日志服务器的功能了, 只是默认并没有启动该功能而已。你可以通过 man rsyslogd 去查询一下相关的选项就能够知道啦! 既然是远程日志服务器,那么我们的 Linux 主机当然会启动一个端口来监听了,那个默认的端口就是 UDP 或 TCP 的 port 514

image.png

Server配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ cat /etc/rsyslog.conf
# 找到下面这几行:
# Provides UDP syslog reception
#$ModLoad imudp
#$UDPServerRun 514

# Provides TCP syslog reception
#$ModLoad imtcp
#$InputTCPServerRun 514
# 上面的是 UDP 端口,下面的是 TCP 端口!如果你的网络状态很稳定,就用 UDP 即可。
# 不过,如果你想要让数据比较稳定传输,那么建议使用 TCP 啰!所以修改下面两行即可!
$ModLoad imtcp
$InputTCPServerRun 514

# 2\. 重新启动与观察 rsyslogd 喔!
[root@study ~]# systemctl restart rsyslog.service
[root@study ~]# netstat -ltnp &#124; grep syslog
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:514 0.0.0.0:* LISTEN 2145/rsyslogd
tcp6 0 0 :::514 :::* LISTEN 2145/rsyslogd
# 嘿嘿!你的登录文件主机已经设置妥当啰!很简单吧!

client配置:

1
2
3
$ cat /etc/rsyslog.conf
*.* @@192.168.1.100
#*.* @192.168.1.100 # 若用 UDP 传输,设置要变这样!

常见的几个系统日志有哪些呢?一般而言,有下面几个:

  • /var/log/boot.log: 开机的时候系统核心会去侦测与启动硬件,接下来开始各种核心支持的功能启动等。这些流程都会记录在 /var/log/boot.log 里面哩! 不过这个文件只会存在这次开机启动的信息,前次开机的信息并不会被保留下来!
  • /var/log/cron: 还记得第十五章例行性工作调度吧?你的 crontab 调度有没有实际被进行? 进行过程有没有发生错误?你的 /etc/crontab 是否撰写正确?在这个登录文件内查询看看。
  • /var/log/dmesg: 记录系统在开机的时候核心侦测过程所产生的各项信息。由于 CentOS 默认将开机时核心的硬件侦测过程取消显示, 因此额外将数据记录一份在这个文件中;
  • /var/log/lastlog: 可以记录系统上面所有的帐号最近一次登陆系统时的相关信息。第十三章讲到的 lastlog 指令就是利用这个文件的记录信息来显示的。
  • /var/log/maillog 或 /var/log/mail/*: 记录邮件的往来信息,其实主要是记录 postfix (SMTP 协定提供者) 与 dovecot (POP3 协定提供者) 所产生的讯息啦。 SMTP 是发信所使用的通讯协定, POP3 则是收信使用的通讯协定。 postfix 与 dovecot 则分别是两套达成通讯协定的软件。
  • /var/log/messages: 这个文件相当的重要,几乎系统发生的错误讯息 (或者是重要的信息) 都会记录在这个文件中; 如果系统发生莫名的错误时,这个文件是一定要查阅的登录文件之一。
  • /var/log/secure: 基本上,只要牵涉到“需要输入帐号密码”的软件,那么当登陆时 (不管登陆正确或错误) 都会被记录在此文件中。 包括系统的 login 程序、图形接口登陆所使用的 gdm 程序、 su, sudo 等程序、还有网络连线的 ssh, telnet 等程序, 登陆信息都会被记载在这里;
  • /var/log/wtmp, /var/log/faillog: 这两个文件可以记录正确登陆系统者的帐号信息 (wtmp) 与错误登陆时所使用的帐号信息 (faillog) ! 我们在第十章谈到的 last 就是读取 wtmp 来显示的, 这对于追踪一般帐号者的使用行为很有帮助!
  • /var/log/httpd/, /var/log/samba/: 不同的网络服务会使用它们自己的登录文件来记载它们自己产生的各项讯息!上述的目录内则是个别服务所制订的登录文件。

journalctl 常用参数

1
2
3
4
5
6
7
-n or –lines= Show the most recent **n** number of log lines

-f or –follow Like a tail operation for viewing live updates

-S, –since=, -U, –until= Search based on a date. “2019-07-04 13:19:17”, “00:00:00”, “yesterday”, “today”, “tomorrow”, “now” are valid formats. For complete time and date specification, see systemd.time(7)

-u service unit

清理journald日志

journalctl –vacuum-size=1M && journalctl –vacuum-size=500

logrotate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/var/log/cron
{
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}

执行:
sudo /usr/sbin/logrotate --force --verbose /etc/logrotate.d/drds
debug:
sudo /usr/sbin/logrotate -d --verbose /etc/logrotate.d/drds
查看日志:
cat /var/lib/logrotate/logrotate.status

kill -HUP

Generally services keep the log files opened while they are running. This mean that they do not care if the log files are renamed/moved or deleted they will continue to write to the open file handled.

When logrotate move the files, the services keep writing to the same file.

Example: syslogd will write to /var/log/cron.log. Then logrotate will rename the file to /var/log/cron.log.1, so syslogd will keep writing to the open file /var/log/cron.log.1.

Sending the HUP signal to syslogd will force him to close existing file handle and open new file handle to the original path /var/log/cron.log which will create a new file.

The use of the HUP signal instead of another one is at the discretion of the program. Some services like php-fpm will listen to the USR1 signal to reopen it’s file handle without terminating itself.

不过还得看应用是否屏蔽了 HUP 信号

systemd

sudo systemctl list-unit-files –type=service | grep enabled //列出启动项

journalctl -b -1 //复审前一次启动, -2 复审倒数第 2 次启动. 重演你的系统启动的所有消息

sudo systemd-analyze blame sudo systemd-analyze critical-chain

systemd-analyze critical-chain –fuzz 1h

sudo systemd-analyze blame networkd

systemd-analyze critical-chain network.target local-fs.target

img

参考资料

一模一样的症状,但是根因找错了:rsyslog占用内存高

https://access.redhat.com/solutions/3705051

https://sunsea.im/rsyslogd-systemd-journald-high-memory-solution.html

鸟哥 journald 介绍

journalctl tail and cheatsheet

Journal的由来

TCP传输速度案例分析

前言

TCP传输速度受网络带宽和传输窗口的影响(接收、发送、拥塞窗口),带宽我们没办法改变,以下案例主要是讨论rt、窗口如何影响速度。

详细的buffer、rt对TCP传输速度的影响请看这篇:

就是要你懂TCP–性能和发送接收Buffer的关系:发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响。BDP、RT、带宽对传输速度又是怎么影响的

以及 就是要你懂TCP–最经典的TCP性能问题 Nagle和Delay ack

上面两篇以及下面几个案例读完,应该所有TCP传输速度问题都能解决了。

前后端rtt差异大+vip下载慢的案例

来源:https://mp.weixin.qq.com/s/er8vTKZUcahA6-Pf8DZBng 文章中的trace-cmd工具也不错

如下三个链路,有一个不正常了

image.png

首先通过 ss -it dst “ip:port” 来分析cwnd、ssthresh、buffer,到底是什么导致了传输慢

原因TCPLossProbe:

如果尾包发生了丢包,没有新包可发送触发多余的dup ack来实现快速重传,完全依赖RTO超时来重传,代价太大,那如何能优化解决这种尾丢包的情况。也就是在某些情况下一个可以的重传包就能触发ssthresh减半,从而导致传输速度上不来。

本案例中,因为client到TGW跨了地域,导致rtt增大,但是TGW和STGW之间的rtt很小,导致握手完毕后STGW认为和client的rtt很小,所以很快就触发了丢包重传,实际没有丢包,只是rtt变大了,所以触发了如上的TLP( PTO=max(2rtt, 10ms) , 因为只有一次重传并收到了 dup,还是不应该触发TLP,但是因为老版本kernel bug导致,4.0的kernel修复了这个问题, 函数 is_tlp_dupack)

握手完毕后第七号包很快重传了

image.png

观察:

netstat -s |grep TCPLossProbes

解决:

tcp_early_retrans可用于开启和关闭ER和TLP,默认是3(enable TLP and delayed ER),sysctl -w net.ipv4.tcp_early_retrans=2 关掉TLP

小结

kernel版本小于4.0+TLP开启+VIP代理导致RS认为rtt很小,实际比较大,这两个条件下就会出现如上问题。

这个问题一看就是跟client和VIP代理之间的rtt扩大有关系,不过不是因为扩大后发送窗口不够之类导致的。

长肥网络(高rtt)场景下tcp_metrics记录的ssthresh太小导致传输慢的案例

https://www.atatech.org/articles/109967

tcp_metrics会记录下之前已关闭tcp 连接的状态,包括发送端拥塞窗口和拥塞控制门限,如果之前网络有一段时间比较差或者丢包比较严重,就会导致tcp 的拥塞控制门限ssthresh降低到一个很低的值,这个值在连接结束后会被tcp_metrics cache 住,在新连接建立时,即使网络状况已经恢复,依然会继承 tcp_metrics 中cache 的一个很低的ssthresh 值,在长肥管道情况下,新连接经历短暂的“慢启动”后,随即进入缓慢的拥塞控制阶段, 导致连接速度很难在短时间内上去。而后面的连接,需要很特殊的场景之下才能将ssthresh 再次推到一个比较高的值缓存下来,因此很有很能在接下来的很长一段时间,连接的速度都会处于一个很低的水平

因为 tcp_metrics记录的ssthresh非常小,导致后面新的tcp连接传输数据时很快进入拥塞控制阶段,如果传输的文件不大的话就没有机会将ssthresh撑大。除非传输一个特别大的文件,忍受拥塞控制阶段的慢慢增长,最后tcp_metrics记录下撑大后的ssthresh,整个网络才会恢复正常。

所以关闭 tcp_metrics其实是个不错的选择: net.ipv4.tcp_no_metrics_save = 1

或者清除: sudo ip tcp_metrics flush all

从系统cache中查看 tcp_metrics item

$sudo ip tcp_metrics show | grep  100.118.58.7
100.118.58.7 age 1457674.290sec tw_ts 3195267888/5752641sec ago rtt 1000us rttvar 1000us ssthresh 361 cwnd 40 ----这两个值对传输性能很重要

192.168.1.100 age 1051050.859sec ssthresh 4 cwnd 2 rtt 4805us rttvar 4805us source 192.168.0.174 ---这条记录有问题,缓存的ssthresh 4 cwnd 2都太小,传输速度一定慢 

清除 tcp_metrics, sudo ip tcp_metrics flush all 
关闭 tcp_metrics 功能,net.ipv4.tcp_no_metrics_save = 1
sudo ip tcp_metrics delete 100.118.58.7

每个连接的ssthresh默认是个无穷大的值,但是内核会cache对端ip上次的ssthresh(大部分时候两个ip之间的拥塞窗口大小不会变),这样大概率到达ssthresh之后就基本拥塞了,然后进入cwnd的慢增长阶段。

长肥网络(rt很高、带宽也高)下接收窗口对传输性能的影响

最后通过一个实际碰到的案例,涉及到了接收窗口、发送Buffer以及高延时情况下的性能问题

案例描述:从中国访问美国的服务器下载图片,只能跑到220K,远远没有达到带宽能力,其中中美之间的网络延时时150ms,这个150ms已经不能再优化了。业务结构是:

client ——150ms—–>>>LVS—1ms–>>>美国的统一接入server—–1ms—–>>>nginx

通过下载一个4M的文件大概需要20秒,分别在client和nginx上抓包来分析这个问题(统一接入server没权限上去)

Nginx上抓包

image.png

从这里可以看到Nginx大概在60ms内就将4M的数据都发完了

client上抓包

image.png

从这个图上可以清楚看到大概每传输大概30K数据就有一个150ms的等待平台,这个150ms基本是client到美国的rt。

从我们前面的阐述可以清楚了解到因为rt比较高,统一接入server每发送30K数据后要等150ms才能收到client的ack,然后继续发送,猜是因为上面设置的发送buffer大概是30K。

检查统一接入server的配置,可以看到接入server的配置里面果然有个32K buffer设置

将buffer改大

速度可以到420K,但是还没有跑满带宽:

image.png

image.png

接着看一下client上的抓包

image.png

可以清楚看到 client的接收窗口是64K, 64K*1000/150=426K 这个64K很明显是16位的最大值,应该是TCP握手有一方不支持window scaling factor

那么继续分析一下握手包,syn:

image.png

说明client是支持的,再看 syn+ack:

image.png

可以看到服务端不支持,那就最大只能用到64K。需要修改服务端代理程序,这主要是LVS或者代理的锅。

如果内网之间rt很小这个锅不会爆发,一旦网络慢一点就把问题恶化了

比如这是这个应用的开发人员的反馈:

image.png

长肥网络就像是很长很宽的高速公路,上面可以同时跑很多车,而如果发车能力不够,就容易跑不满高速公路。
在rt很短的时候可以理解为高速公路很短,所以即使发车慢也还好,因为车很快就到了,到了后就又能发新车了。rt很长的话就要求更大的仓库了。

整个这个问题,我最初拿到的问题描述结构是这样的(不要笑程序员连自己的业务结构都描述不清):

client ——150ms—–>>>nginx

实际开发人员也不能完全描述清楚结构,从抓包中慢慢分析反推他们的结构,到最后问题的解决。

这个案例综合了发送窗口(32K)、接收窗口(64K,因为握手LVS不支持window scale)、rt很大将问题暴露出来(跨国网络,rt没法优化)。

nginx buffer 分析参考案例:https://juejin.cn/post/6875223721615818765 nginx上下游收发包速率不一致导致nginx buffer打爆, 关闭nginx proxy_buffering 可解 (作者:挖坑的张师傅)

image.png

应用层发包逻辑影响了BDP不能跑满

来自 dog250: 一行代码解决scp在Internet传输慢的问题(RT高的网络环境)

用scp在长链路上传输文件竟然慢到无法忍受!100~200毫秒往返时延的链路,wget下载文件吞吐可达40MBps,scp却只有9MBps。

这次不是因为buffer导致BDP跑不满,而是scp业务层有自己流控的逻辑导致发包慢了

SSH允许在一个TCP连接上复用多个channel,需要对每一个channel做流控以保证公平,所以每个channel必须自己做而不是使用TCP的流控,OpenSSH的实现有问题。

delay ack拉高实际rt的案例

这个案例跟速度没有关系,只是解析监控图表上的rt为什么不符合逻辑地偏高了。

如下业务监控图:实际处理时间(逻辑服务时间1ms,rtt2.4ms,加起来3.5ms),但是系统监控到的rt(蓝线)是6ms,如果一个请求分很多响应包串行发给client,这个6ms是正常的(1+2.4*N),但实际上如果send buffer足够的话,按我们前面的理解多个响应包会并发发出去,所以如果整个rt是3.5ms才是正常的。

image.png

抓包来分析原因:

image.png

实际看到大量的response都是3.5ms左右,符合我们的预期,但是有少量rt被delay ack严重影响了

从下图也可以看到有很多rtt超过3ms的,这些超长时间的rtt会最终影响到整个服务rt

image.png

参考资料

SSH Performance

Why when I transfer a file through SFTP, it takes longer than FTP?

mac 路由和DSN相关知识

Mac 下上网,尤其是在双网卡一起使用的时候, 一个网卡连内网,一个网卡连外网,经常会碰到ip不通(路由问题,比较好解决)或者dns解析不了问题. 或者是在通过VPN连公司网络会插入一些内网route,导致部分网络访问不了.

即使对Linux下的DNS解析无比熟悉了,但是在Mac下还是花了一些时间来折腾,配置不好路由和DNS是不配使用Mac的,所以记录下。

route

如果ip不通就看路由表, 根据内外网IP增加/删除相应的路由信息,常用命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sudo route -n add 10.176/16 192.168.3.1
sudo route -n add -net 10.176.0.0/16 192.168.3.1 //添加路由, 访问10.176.0.0/16 走192.168.3.1
sudo route -n delete -net 10.176.0.0/16 192.168.3.1
sudo route -n delete 0.0.0.0 192.168.184.1
sudo route -n add 0.0.0.0 192.168.184.1 //添加默认路由访问外网

sudo route -n delete 0.0.0.0 192.168.3.1
sudo route -n add 10.176/16 192.168.3.1
sudo route -n delete 0.0.0.0 192.168.184.1 -ifscope en0
sudo route -n add 0.0.0.0 192.168.184.1
sudo networksetup -setdnsservers 'Apple USB Ethernet Adapter' 202.106.196.115 202.106.0.20 114.114.114.114

sudo networksetup -setdnsservers 'USB 10/100/1000 LAN' 223.5.5.5 30.30.30.30 114.114.114.114

ip route get 8.8.8.8 //linux
route get 8.8.8.8 //macOS
netstat -rn //查看路由
netstat -nr -f inet //只看ipv4相关路由

如果本来IP能通,连上VPN后就通不了,那一定是VPN加入了一些更精细的路由导致原来的路由不通了,那么很简单停掉VPN就能恢复或者增加一条更精确的路有记录进去,或者删掉VPN增加的某条路由.

DNS 解析

mac下DNS解析问题搞起来比较费劲,相应的资料也不多, 经过上面的操作后如果IP能通,域名解析有问题,一般都是DNS解析出了问题

mac下 /etc/resolv.conf 不再用来解析域名, 只有nslookup能用到resolv.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
cat /etc/resolv.conf                                                
#
# macOS Notice
#
# This file is not consulted for DNS hostname resolution, address
# resolution, or the DNS query routing mechanism used by most
# processes on this system.
#
# To view the DNS configuration used by this system, use:
# scutil --dns

scutil --dns //查看DNS 解析器
scutil --nwi //查看网络

解析出了问题先检查nameserver

scutil –dns 一般会展示一大堆的resolver, 每个resolver又可以有多个nameserver

A scoped DNS query can use only specified network interfaces (e.g. Ethernet or WiFi), while non-scoped can use any available interface.

More verbosely, an application that wants to resolve a name, sends a request (either scoped or non-scoped) to a resolver (usually a DNS client application), if the resolver does not have the answer cached, it sends a DNS query to a particular nameserver (and this goes through one interface, so it is always “scoped”).

In your example resolver #1 “for scoped queries” can use only en0 interface (Ethernet).

修改 nameserver

默认用第一个resolver, 如果第一个resolver没有nameserver那么域名没法解析, 可以修改dns resolver的nameserver:

1
2
3
4
5
6
7
8
9
$networksetup -listallnetworkservices  //列出网卡service, 比如 wifi ,以下是我的 macOS 输出
An asterisk (*) denotes that a network service is disabled.
USB 10/100/1000 LAN
Apple USB Ethernet Adapter
Wi-Fi
Bluetooth PAN
Thunderbolt Bridge
$sudo networksetup -setdnsservers 'Wi-Fi' 202.106.196.115 202.106.0.20 114.114.114.114 //修改nameserver
$networksetup -getdnsservers Wi-Fi //查看对应的nameserver, 跟 scutil --dns 类似

如上, 只要是你的nameserver工作正常那么DNS就肯定回复了

删掉所有DNS nameserver:

One note to anyone wanting to remove the DNS, just write “empty” (without the quotes) instead of the DNS: sudo networksetup -setdnsservers <networkservice> empty

networksetup用法

查看设备和配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$networksetup -listallnetworkservices
An asterisk (*) denotes that a network service is disabled.
USB 10/100/1000 LAN
Apple USB Ethernet Adapter
Wi-Fi
Bluetooth PAN
Thunderbolt Bridge
Thunderbolt Bridge 2

#查看网卡配置
$networksetup -getinfo "USB 10/100/1000 LAN"
DHCP Configuration
IP address: 30.25.25.195
Subnet mask: 255.255.255.128
Router: 30.25.25.254
Client ID:
IPv6 IP address: none
IPv6 Router: none
Ethernet Address: 44:67:52:02:16:d4

$networksetup -listallhardwareports
Hardware Port: USB 10/100/1000 LAN
Device: en7
Ethernet Address: 44:67:52:02:16:d4

Hardware Port: Wi-Fi
Device: en0
Ethernet Address: 88:66:5a:10:e4:2b

Hardware Port: Thunderbolt Bridge
Device: bridge0
Ethernet Address: 82:0a:d5:01:b4:00

VLAN Configurations
===================
$networksetup -getinfo "Thunderbolt Bridge"
DHCP Configuration
Client ID:
IPv6: Automatic
IPv6 IP address: none
IPv6 Router: none

//查看wifi和热点
networksetup -listpreferredwirelessnetworks en0
networksetup -getairportnetwork "en0"

dhcp、route、domain配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[-setmanual networkservice ip subnet router]

[-setdhcp networkservice [clientid]]

[-setbootp networkservice]

[-setmanualwithdhcprouter networkservice ip]

[-getadditionalroutes networkservice]

[-setadditionalroutes networkservice [dest1 mask1 gate1] [dest2 mask2 gate2] ..

. [destN maskN gateN]]

#给网卡配置ip、网关
$ networksetup -getinfo "Apple USB Ethernet Adapter" DHCP Configuration
Client ID:
IPv6: Automatic
IPv6 IP address: none
IPv6 Router: none
Ethernet Address: (null)
$networksetup -setmanual "Apple USB Ethernet Adapter" 192.168.100.100 255.255.255.0 192.168.100.1
$networksetup -getinfo "Apple USB Ethernet Adapter"
Manual Configuration
IP address: 192.168.100.100
Subnet mask: 255.255.255.0
Router: 192.168.100.1
IPv6: Automatic
IPv6 IP address: none
IPv6 Router: none
Ethernet Address: (null)

代理配置

1
2
3
4
5
6
//ftp
[-getftpproxy networkservice]

[-setftpproxy networkservice domain portnumber authenticated username password]

[-setftpproxystate networkservice on | off]

网页

1
2
3
4
5
6
[-getwebproxy networkservice]
[-setwebproxy networkservice domain portnumber authenticated username password]
[-setwebproxystate networkservice on | off]

$networksetup -setwebproxy "Built-in Ethernet" proxy.company.com 80
$networksetup -setwebproxy "Built-In Ethernet" proxy.company.com 80 On authusername authpassword

Socks5 代理

1
2
3
4
5
6
$networksetup -setsocksfirewallproxy "USB 10/100/1000 LAN" 127.0.0.1 13659
$networksetup -getsocksfirewallproxy "USB 10/100/1000 LAN"
Enabled: Yes
Server: 127.0.0.1
Port: 13659
Authenticated Proxy Enabled: 0

总结

mac同时连wifi(外网或者vpn)和有线(内网), 如果内网干扰了访问外部ip, 就检查路由表,调整顺序. 如果内网干扰了dns,可以通过scutil –dns查看dns顺序到系统配置里去掉不必要的resolver

参考资料

macOS的networksetup命令来管理网络

在Mac下使用脚本重载proxy自动配置脚本(pac)

0%