服务器整体性能调优学习笔记
在服务器整机上部署的应用出现性能问题时,可先在服务器层面尝试调优。 本文记录了服务器硬件信息查询方法、性能指标的常用监测方法以及与性能相关的服务器配置等。
通用资源监控
nmon
是一个通用的系统资源监控工具,执行 nmon
后会显示命令帮助:
c
:CPU。m
:内存。d
:硬盘。- Busy(使用率):磁盘 I/O 请求的饱和程度。
- Read:读吞吐量。
- Write:写吞吐量。
n
:网络。
主板
# 查询主板型号
dmidecode -s system-product-name
CPU
硬件信息查询:
# 查询 CPU 信息:架构、型号、线程、核、路、频率等
lscpu
# NUMA 架构的 CPU 与内存分布
numactl -H
htop
htop
是一个系统监控与进程管理软件,能提供比 top
更详细的信息。
NUMA 架构设备通常包含几十甚至上百个 CPU 核心,如果需要分别监控它们的负载,使用 htop
会非常方便。
执行 htop
之后按 F2
可以进入交互式的配置菜单;也可以直接修改配置文件 ${HOME}/.config/htop/htoprc
,这里提供一个简单配置:
header_layout=two_50_50
show_cpu_usage=1
show_cpu_frequency=1
column_meters_0=LeftCPUs4 Memory Tasks Uptime
column_meter_modes_0=1 1 2 2
column_meters_1=RightCPUs4 Swap LoadAverage CPU
column_meter_modes_1=1 1 2 2
这套配置的效果:
- 排版是左右两列各占 50% 宽度。
- CPU 信息包含 CPU 使用率与频率。
- 左列自上往下分别为:
- CPU 信息,每行 4 个;条形图。
- 内存占用;条形图。
- 任务信息(进程数、线程数、on-CPU 的线程数);文本。
- 正常运行时间;文本。
- 右列自上往下分别为:
- CPU 信息,每行 4 个;条形图。
- 交换分区占用;条形图。
- 一段时间内 CPU 的平均负载(1 分钟、5 分钟、 15 分钟);文本。
- 总体的 CPU 平均使用率;文本。
输出大概是这样:
0[||||||||||||||61.0% 2895MHz] 32[||||||||||||||90.7%|2898MHz] 64[||||||||||||||84.1%|2897MHz] 96[||||||||||||||93.3%|2897MHz] 128[|||||||||||||||87.2%|2900MHz]160[|||||||||||||||91.1%|2900MHz]192[|||||||||||||||93.5%|2900MHz]224[|||||||||||||||88.9%|2900MHz]
1[||||||||||||||90.9%|2895MHz] 33[||||||||||||||91.1%|2898MHz] 65[||||||||||||||86.0%|2897MHz] 97[||||||||||||||88.4%|2897MHz] 129[|||||||||||||||86.7%|2900MHz]161[|||||||||||||||84.1%|2900MHz]193[|||||||||||||||91.3%|2900MHz]225[|||||||||||||||90.9%|2900MHz]
2[||||||||||||||88.9%|2895MHz] 34[||||||||||||||89.1%|2894MHz] 66[||||||||||||||88.6%|2896MHz] 98[||||||||||||||88.9%|2896MHz] 130[|||||||||||||||87.0%|2900MHz]162[|||||||||||||||84.4%|2900MHz]194[|||||||||||||||93.2%|2900MHz]226[|||||||||||||||89.1%|2900MHz]
3[||||||||||||||93.5%|2895MHz] 35[||||||||||||||91.3%|2894MHz] 67[||||||||||||||84.1%|2896MHz] 99[||||||||||||||89.1%|2896MHz] 131[|||||||||||||||91.1%|2900MHz]163[|||||||||||||||83.7%|2900MHz]195[|||||||||||||||90.9%|2900MHz]227[|||||||||||||||88.9%|2900MHz]
4[||||||||||||||87.5%|2899MHz] 36[||||||||||||||87.5%|2902MHz] 68[||||||||||||||88.9%|2896MHz] 100[||||||||||||||90.9%|2908MHz] 132[|||||||||||||||87.0%|2900MHz]164[|||||||||||||||93.6%|2900MHz]196[|||||||||||||||89.1%|2900MHz]228[|||||||||||||||90.7%|2900MHz]
5[||||||||||||||91.1%|2899MHz] 37[||||||||||||||93.3%|2902MHz] 69[||||||||||||||86.4%|2896MHz] 101[||||||||||||||88.9%|2908MHz] 133[|||||||||||||||88.9%|2900MHz]165[|||||||||||||||89.6%|2900MHz]197[|||||||||||||||89.6%|2900MHz]229[|||||||||||||||83.7%|2900MHz]
6[||||||||||||||86.7%|2902MHz] 38[||||||||||||||89.1%|2897MHz] 70[||||||||||||||87.0%|2895MHz] 102[||||||||||||||91.1%|2904MHz] 134[|||||||||||||||89.4%|2900MHz]166[|||||||||||||||89.1%|2900MHz]198[|||||||||||||||88.9%|2900MHz]230[|||||||||||||||91.5%|2900MHz]
7[||||||||||||||90.5%|2902MHz] 39[||||||||||||||86.4%|2897MHz] 71[||||||||||||||88.6%|2895MHz] 103[||||||||||||||88.4%|2904MHz] 135[|||||||||||||||88.6%|2900MHz]167[|||||||||||||||84.8%|2900MHz]199[|||||||||||||||91.3%|2900MHz]231[|||||||||||||||89.4%|2900MHz]
8[||||||||||||||88.9%|2902MHz] 40[||||||||||||||87.2%|2899MHz] 72[||||||||||||||88.6%|2898MHz] 104[||||||||||||||87.2%|2900MHz] 136[|||||||||||||||81.8%|2899MHz]168[|||||||||||||||87.0%|2900MHz]200[|||||||||||||||91.3%|2900MHz]232[|||||||||||||||90.9%|2900MHz]
9[||||||||||||||86.4%|2902MHz] 41[||||||||||||||88.6%|2899MHz] 73[||||||||||||||87.0%|2898MHz] 105[||||||||||||||88.9%|2900MHz] 137[|||||||||||||||91.5%|2899MHz]169[|||||||||||||||91.1%|2900MHz]201[|||||||||||||||93.6%|2900MHz]233[|||||||||||||||88.6%|2900MHz]
10[||||||||||||||87.0%|2903MHz] 42[||||||||||||||93.3%|2901MHz] 74[||||||||||||||84.8%|2900MHz] 106[||||||||||||||84.1%|2905MHz] 138[|||||||||||||||91.3%|2900MHz]170[|||||||||||||||91.3%|2900MHz]202[|||||||||||||||91.3%|2900MHz]234[|||||||||||||||91.3%|2900MHz]
11[||||||||||||||88.9%|2903MHz] 43[||||||||||||||87.0%|2901MHz] 75[||||||||||||||91.1%|2900MHz] 107[||||||||||||||90.9%|2905MHz] 139[|||||||||||||||87.2%|2900MHz]171[|||||||||||||||87.2%|2900MHz]203[|||||||||||||||90.7%|2900MHz]235[|||||||||||||||90.7%|2900MHz]
12[||||||||||||||86.4%|2900MHz] 44[||||||||||||||89.1%|2904MHz] 76[||||||||||||||89.4%|2897MHz] 108[||||||||||||||86.7%|2899MHz] 140[|||||||||||||||86.7%|2900MHz]172[|||||||||||||||91.1%|2900MHz]204[|||||||||||||||95.7%|2900MHz]236[|||||||||||||||89.4%|2900MHz]
13[||||||||||||||91.3%|2900MHz] 45[||||||||||||||89.1%|2904MHz] 77[||||||||||||||88.6%|2897MHz] 109[||||||||||||||89.1%|2899MHz] 141[|||||||||||||||89.6%|2900MHz]173[|||||||||||||||91.1%|2900MHz]205[|||||||||||||||93.2%|2900MHz]237[|||||||||||||||88.9%|2900MHz]
14[||||||||||||||88.1%|2899MHz] 46[||||||||||||||88.9%|2896MHz] 78[||||||||||||||90.9%|2900MHz] 110[||||||||||||||87.0%|2900MHz] 142[|||||||||||||||91.3%|2900MHz]174[|||||||||||||||87.0%|2900MHz]206[|||||||||||||||91.3%|2900MHz]238[|||||||||||||||86.7%|2900MHz]
15[||||||||||||||93.3%|2899MHz] 47[||||||||||||||93.5%|2896MHz] 79[||||||||||||||88.9%|2900MHz] 111[||||||||||||||90.9%|2900MHz] 143[|||||||||||||||89.1%|2900MHz]175[|||||||||||||||89.4%|2900MHz]207[|||||||||||||||91.7%|2900MHz]239[|||||||||||||||93.5%|2900MHz]
16[||||||||||||||90.7%|2896MHz] 48[||||||||||||||91.3%|2904MHz] 80[||||||||||||||88.4%|2892MHz] 112[||||||||||||||88.9%|2898MHz] 144[|||||||||||||||87.5%|2900MHz]176[|||||||||||||||91.5%|2900MHz]208[|||||||||||||||84.4%|2900MHz]240[|||||||||||||||93.5%|2900MHz]
17[||||||||||||||93.2%|2896MHz] 49[||||||||||||||90.7%|2904MHz] 81[||||||||||||||93.0%|2892MHz] 113[||||||||||||||88.6%|2898MHz] 145[|||||||||||||||88.4%|2900MHz]177[|||||||||||||||88.6%|2900MHz]209[|||||||||||||||89.1%|2900MHz]241[|||||||||||||||93.2%|2900MHz]
18[||||||||||||||86.7%|2896MHz] 50[||||||||||||||87.0%|2895MHz] 82[||||||||||||||80.4%|2902MHz] 114[||||||||||||||88.4%|2900MHz] 146[|||||||||||||||87.0%|2900MHz]178[|||||||||||||||86.7%|2900MHz]210[|||||||||||||||93.3%|2900MHz]242[|||||||||||||||88.6%|2900MHz]
19[||||||||||||||87.0%|2896MHz] 51[||||||||||||||89.4%|2895MHz] 83[||||||||||||||91.1%|2902MHz] 115[||||||||||||||84.1%|2900MHz] 147[|||||||||||||||91.3%|2900MHz]179[|||||||||||||||83.7%|2900MHz]211[|||||||||||||||95.7%|2900MHz]243[|||||||||||||||88.6%|2900MHz]
20[||||||||||||||93.5%|2902MHz] 52[||||||||||||||91.1%|2894MHz] 84[||||||||||||||85.1%|2901MHz] 116[||||||||||||||91.5%|2902MHz] 148[|||||||||||||||89.4%|2900MHz]180[|||||||||||||||89.1%|2900MHz]212[|||||||||||||||93.8%|2900MHz]244[|||||||||||||||89.1%|2900MHz]
21[||||||||||||||91.3%|2902MHz] 53[||||||||||||||89.8%|2894MHz] 85[||||||||||||||88.9%|2901MHz] 117[||||||||||||||86.7%|2902MHz] 149[|||||||||||||||86.4%|2900MHz]181[|||||||||||||||88.6%|2900MHz]213[|||||||||||||||88.6%|2900MHz]245[|||||||||||||||87.2%|2900MHz]
22[||||||||||||||84.1%|2898MHz] 54[||||||||||||||89.1%|2900MHz] 86[||||||||||||||89.4%|2906MHz] 118[||||||||||||||91.3%|2905MHz] 150[|||||||||||||||88.9%|2900MHz]182[|||||||||||||||91.3%|2900MHz]214[|||||||||||||||86.4%|2900MHz]246[|||||||||||||||91.5%|2900MHz]
23[||||||||||||||86.7%|2898MHz] 55[||||||||||||||81.4%|2900MHz] 87[||||||||||||||91.3%|2906MHz] 119[||||||||||||||89.4%|2905MHz] 151[|||||||||||||||90.9%|2900MHz]183[|||||||||||||||89.8%|2900MHz]215[|||||||||||||||88.6%|2900MHz]247[|||||||||||||||91.3%|2900MHz]
24[||||||||||||||91.1%|2896MHz] 56[||||||||||||||89.4%|2904MHz] 88[||||||||||||||90.9%|2900MHz] 120[||||||||||||||85.7%|2901MHz] 152[|||||||||||||||88.6%|2900MHz]184[|||||||||||||||88.6%|2900MHz]216[|||||||||||||||86.4%|2900MHz]248[|||||||||||||||87.2%|2900MHz]
25[||||||||||||||91.3%|2896MHz] 57[||||||||||||||91.1%|2904MHz] 89[||||||||||||||91.5%|2900MHz] 121[||||||||||||||89.4%|2901MHz] 153[|||||||||||||||83.7%|2900MHz]185[|||||||||||||||88.9%|2900MHz]217[|||||||||||||||91.3%|2900MHz]249[|||||||||||||||90.9%|2900MHz]
26[||||||||||||||88.6%|2904MHz] 58[||||||||||||||80.0%|2904MHz] 90[||||||||||||||89.1%|2899MHz] 122[||||||||||||||82.6%|2907MHz] 154[|||||||||||||||89.8%|2900MHz]186[|||||||||||||||77.8%|2900MHz]218[|||||||||||||||87.2%|2900MHz]250[|||||||||||||||75.6%|2900MHz]
27[||||||||||||||87.0%|2904MHz] 59[||||||||||||||78.3%|2904MHz] 91[||||||||||||||84.4%|2899MHz] 123[||||||||||||||68.9% 2907MHz] 155[|||||||||||||||86.7%|2900MHz]187[|||||||||||||||75.0%|2900MHz]219[|||||||||||||||88.9%|2900MHz]251[|||||||||||||||88.9%|2900MHz]
28[||||||||||||||90.9%|2900MHz] 60[||||||||||||||79.1%|2903MHz] 92[||||||||||||||84.1%|2899MHz] 124[||||||||||||||79.5%|2896MHz] 156[|||||||||||||||88.9%|2900MHz]188[|||||||||||||||77.8%|2900MHz]220[|||||||||||||||93.5%|2900MHz]252[|||||||||||||||91.3%|2900MHz]
29[||||||||||||||93.3%|2900MHz] 61[||||||||||||||82.2%|2903MHz] 93[||||||||||||||89.6%|2899MHz] 125[||||||||||||||75.6%|2896MHz] 157[|||||||||||||||91.7%|2900MHz]189[|||||||||||||||73.3%|2900MHz]221[|||||||||||||||86.7%|2900MHz]253[|||||||||||||||75.0%|2900MHz]
30[||||||||||||||88.6%|2901MHz] 62[||||||||||||||75.6%|2904MHz] 94[||||||||||||||86.7%|2897MHz] 126[||||||||||||||72.7%|2908MHz] 158[|||||||||||||||89.4%|2900MHz]190[|||||||||||||||82.2%|2900MHz]222[|||||||||||||||85.1%|2900MHz]254[|||||||||||||||80.4%|2900MHz]
31[||||||||||||||89.1%|2901MHz] 63[||||||||||||||68.9% 2904MHz] 95[||||||||||||||89.6%|2897MHz] 127[||||||||||||||68.2% 2908MHz] 159[|||||||||||||||84.4%|2900MHz]191[|||||||||||||||75.6%|2900MHz]223[|||||||||||||||91.3%|2900MHz]255[|||||||||||||||77.8%|2900MHz]
Mem[||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||193G/1006G] Swp[|| 12.6M/4.00G]
Tasks: 40, 1046 thr, 2048 kthr; 0 running Load average: 494.98 353.27 206.93
Uptime: 03:48:04 Avg: 63.9% sys: 24.0% low: 0.0% vir: 0.0% freq: 2899MHz
如果希望将 htop
的快照输出到文件中:
# 输出到文件
echo | htop > htop.out
# 打印文件
head -c -10 htop.out | tail -c +10
注意一下,CPU 使用率与 CPU 负载是两种不同的概念。
CPU 使用率是指在一个时间段内 CPU 处于忙碌状态的比例。
在某个时间戳时,CPU 的状态是离散的,只有忙碌和空闲两种状态。
因此统计出的 CPU 使用率不可能超过 100%。
htop
实际是访问文件 /proc/stat
获取 CPU 在不同状态下花费的时间(以 USER_HZ
为单位,通常是 10ms),通过时间段前后的差值计算出的比例作为 CPU 使用率。
/proc/stat
中 CPU 的状态包括:user(用户态)、nice(低优先级用户态)、system(内核态)、idle(空闲)、iowait(I/O 等待)、irq(中断处理)、softirq(软中断处理)等。
htop
是通过不同颜色区分展示这些状态在 CPU 使用率中的占比,支持基础模式(默认)与详细模式(Detailed CPU time)两种显示模式。
比如在默认的基础显示模式中,I/O 等待与 IRQ 处理会合并显示为同一种颜色;如果修改为详细显示模式,它们会被不同的颜色代表。
大部分情况下,我们可以使用默认的基础模式,能够粗略区分用户进程与内核空间代码的占比就行。
而 CPU 负载衡量的不仅仅是测量时的活动量,还包含了线程对 CPU 的需求程度。
在理想情况下,可以认为 CPU 负载测量的是 Linux 运行队列中标记为 runnable(可运行)与 uninterruptible sleep(不可中断睡眠)的线程数的移动平均值。
因此只要符合条件的线程足够多,CPU 负载是能够超过 100% 的。
多线程调度是以时间片为单位将线程分配给 CPU 执行,用户线程在进入系统调用或时间片结束时放弃控制并回到内核态。
这时内核会以固定频率依据运行队列中的线程状态统计 CPU 负载(计算移动平均值)。
有意思的是,内核在计算移动平均值时用了一点魔法,不过可以不用管。
一般情况下认为将 CPU 负载控制在 70% 以下是比较稳定的。
顺带一提,可以通过命令 cat /proc/loadavg
手动查询 CPU 负载。
总体来说 CPU 使用率衡量的是 CPU 自身花费的时间;而 CPU 负载衡量的是安排给 CPU 的任务。 比方说执行大量重 I/O 的线程可能会导致很高 CPU 负载高,但 CPU 使用率可能反而很低。
另外,对于多核 CPU(暂时不考虑超线程),衡量整机的 CPU 使用率与负载时,通常都是以核心数为比例进行缩放的。 比方说对于 8 核 CPU 而言,整机 CPU 使用率的上限是 800%。
提供一些参考资料:
-
关于
Tasks
https://superuser.com/questions/1160791/htop-what-is-task-thread-and-running
-
关于
LoadAverage
https://www.digitalocean.com/community/tutorials/load-average-in-linux
内存
# 查询当前内存占用情况
free -h
# 监控一段时间内内存占用变化情况
watch -n 1 --differences=cumulative 'free -h'
可以看到内存与交换分区的使用情况。
total
:总内存。used
:已使用的内存,比如malloc
分配的内存,满足used = total - free - buff/cache
。free
:完全空闲、未使用的内存,通常会注意到这个值比较小,这个是正常现象,因为 Linux 会充分利用空闲内存进行缓存以提高性能。shared
:进程间共享的内存,一个经典的例子就是 PostgreSQL 中的shared_buffers
。buff/cache
:一般来说是指临时使用的内存,在需要时可被内核回收。buffers
:用于内核缓存。cache
:用于页缓存与 slab,可以使用命令echo 3 > /proc/sys/vm/drop_caches
回收页缓存与 slab 对象。
available
:系统估算出的可供使用的内存,包括free
与可回收的buff/cache
。
各 NUMA 结点上的内存
可以参考 NUMA 相关命令速查。
# 监控一段时间内各 NUMA 节点内存分配的命中情况
watch -n 1 --differences=cumulative numastat
# 监控一段时间内各 NUMA 节点内存占用变化情况
watch -n 1 --differences=cumulative 'numastat -m -c | grep -e Node -e MemFree -e MemUsed'
硬盘
查询硬盘信息:
# 查询所有硬盘
fdisk -l
# 查询硬盘挂载
df -h
脏页回写
通过以下内核参数(对应的文件在 /proc/sys/vm
目录中)修改脏页回写策略:
vm.dirty_background_ratio
:脏页超过该比例时会被背景线程异步回写。vm.dirty_ratio
:脏页超过该比例时,写请求会被阻塞,直至部分脏页被回写到硬盘。vm.dirty_expire_centisecs
:脏页停留时间(厘秒),超过该时间后脏页会被背景线程异步回写。vm.dirty_writeback_centisecs
:负责回写的背景线程唤醒的周期(厘秒)。
例如:
sysctl -w vm.dirty_ratio=60
查询当前脏页数量:
grep nr_dirty /proc/vmstat
I/O 统计
可以用 iostat
查询硬盘的 I/O 统计信息。
比如下面的命令会查询 nvme0n1
与 nvme1n1
这两块盘的 I/O 统计信息,末尾两个数字用于指定每 2s 查询一次,共查询 5 次:
iostat nvme0n1 nvme1n1 2 5
输出大概像是这样:
avg-cpu: %user %nice %system %iowait %steal %idle
1.82 0.00 0.34 0.06 0.00 97.78
Device tps kB_read/s kB_wrtn/s kB_dscd/s kB_read kB_wrtn kB_dscd
nvme0n1 4243.82 73.92 433912.70 1853392.66 124665 731763388 3125616988
nvme1n1 233.50 3.91 29609.24 1853392.66 6601 49933904 3125616988
还可以带上 -x
参数以显示扩展信息:
iostat -x nvme0n1 nvme1n1 2 5
-
avg-cpu
:平均 CPU 使用率,可参考上文。 -
tps
:transfers per second,一个 transfer 就是一个 I/O 请求。 -
kB_read/s
:读吞吐量。 -
kB_wrtn/s
:写吞吐量。 -
kB_dscd/s
:设备每秒丢弃的数据量(以 kB 为单位)对于机械硬盘来说,硬盘空间可由软件维护,在写入时直接覆盖就行,操作系统在释放空间时不需要通知硬盘,这种情况下
kB_dscd/s
会恒定为零。 但固态硬盘就不一样,因为固态硬盘有一个写入放大的问题:写入的最小单位是一个数据块,即使少量字节的写入也会导致整个数据块的覆写。 因此释放固态硬盘上的空间时,操作系统需要向硬盘发送 trim 命令以指定需要释放的空间。 固态硬盘在后续对数据块进行覆盖写时就可以依据 trim 命令提供的信息减少覆写时的拷贝开销。具体可以参考 Trim (computing) - Wikipedia。 -
await
:I/O 请求从提交至设备到处理完成的平均等待时间,包括 I/O 请求在队列中的等待时间与设备实际处理时间。 -
r_await
:读请求的平均等待时间。 -
w_await
:写请求的平均等待时间。 -
%util
:设备在采样周期内处理 I/O 请求的时间比例。对于串行处理的设备来说,接近 100% 意味着该设备的饱和。 但对于具有并行处理能力的设备(比如 NVMe)来说,100% 并不能准确反映设备的性能瓶颈。
网络
查询网卡的硬件信息:
# 通过 ip 查询网络接口
dev="$(ip address | grep $ip | awk '{ print $NF }')"
# 查询网卡带宽等信息
ethtool "${dev}"
ping
确认两台设备间连接情况,可以使用 ping
:
ping <ip>
大致输出:
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=109 time=40.2 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=109 time=40.1 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=109 time=40.0 ms
-
ttl
:time to live。剩余跳数,每经过一跳路由会减 1,减至 0 时该数据包会被丢弃。 其初始值由目标系统决定,Windows 一般是 128,Linux 一般是 64。 在内网环境下分离部署应用时,需要尽量减少途径的路由。 如果剩余跳数偏小,说明经过的路由比较多,需要检查网络拓扑。
-
time
:往返时延。内网环境下,时延最好小于 0.1ms。
sar
sar
命令可用于监控网卡 I/O 统计,需要启动 sysstat
服务。
比如下面的命令会查询所有网卡的统计信息,末尾两个数字用于指定每 2s 查询一次,共查询 5 次:
sar -n DEV 2 5
rxpck/s
与txpck/s
:每秒接收与发送的包数。rxkB/s
与txkB/s
:接收与发送方向的吞吐量。rxcmp/s
与txcmp/s
:每秒接收与发送方向的数据包数量。%ifutil
:网络接口的使用率,是吞吐量与带宽的比值。