linux排查
Linux性能优化实战 笔记 https://time.geekbang.org/column/intro/100020901
模拟工具
stress
stress 是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景
apk add stress-ng
# 一个 CPU 使用率 100%
stress --cpu 1 --timeout 600
# 模拟 I/O 压力
stress -i 1 --timeout 600
# 8个进程
stress -c 8 --timeout 600
sysbench
sysbench 是一个多线程的基准测试工具,一般用来评估不同系统参数下的数据库负载情况
# 以10个线程运行5分钟的基准测试,模拟多线程切换的问题
$ sysbench --threads=10 --max-time=300 threads run
ab
ab(apache bench)是一个常用的 HTTP 服务性能测试工具
# 并发10个请求测试Nginx性能,总共测试100个请求
$ ab -c 10 -n 100 http://192.168.0.10:10000/
排查工具
uptime 系统负载
了解系统的负载情况
$ uptime
14:42 up 56 days, 18:09, 2 users, load averages: 1.48 2.10 2.48
#{{当前时间}} {{系统运行时间}} {{正在登录用户数}} {{过去1分钟的平均负载}} {{过去5分钟的平均负载}} {{过去15分钟的平均负载}}
# 持续观察 -d 参数表示高亮显示变化的区域
watch -d uptime
mpstat CPU
mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有CPU的平均指标
# -P ALL 表示监控所有CPU,后面数字5表示间隔5秒后输出一组数据
mpstat -P ALL 5
pidstat 进程
pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标
apk add sysstat
# 间隔5秒后输出一组数据;-u 代表cpu指标
pidstat -u 5 1
# 每隔5秒输出1组数据; -w 查看每个进程上下文切换的情况
pidstat -w 5
# 每隔1秒输出1组数据(需要 Ctrl+C 才结束)
# -w参数表示输出进程切换指标,而-u参数则表示输出CPU使用指标
$ pidstat -w -u 1
# 每隔1秒输出一组数据(需要 Ctrl+C 才结束)
# -wt 参数表示输出线程的上下文切换指标
$ pidstat -wt 1
vmstat 系统性能
vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数
cs(context switch)是每秒上下文切换的次数。
in(interrupt)则是每秒中断的次数。
r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待CPU的进程数。
b(Blocked)则是处于不可中断睡眠状态的进程数。
cswch ,表示每秒自愿上下文切换(voluntary context switches)的次数
nvcswch ,表示每秒非自愿上下文切换(non voluntary context switches)的次数
apk add procps
# 每隔5秒输出1组数据
vmstat 5
# 间隔1秒后输出1组数据
$ vmstat 1 1
# 每隔1秒输出1组数据(需要Ctrl+C才结束)
$ vmstat 1
top
- user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
- nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
- system(通常缩写为sys),代表内核态 CPU 时间。
- idle(通常缩写为id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。
- iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。
- irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。
- softirq(通常缩写为 si),代表处理软中断的 CPU 时间。
- steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。
- guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。
- guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。
top运行时候按1
,切换到每个 CPU 的使用率
- VIRT 是进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内。
- RES 是常驻内存的大小,也就是进程实际使用的物理内存大小,但不包括 Swap 和共享内存。
- SHR 是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等。
- %MEM 是进程使用物理内存占系统总内存的百分比。
S列值意义
- R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
- D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
- Z 是 Zombie 的缩写,它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
- S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
- I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。
T 或者 t,也就是 Stopped 或 Traced 的缩写,表示进程处于暂停或者跟踪状态.
向一个进程发送 SIGSTOP 信号,它就会因响应这个信号变成暂停状态(Stopped);
再向它发送 SIGCONT 信号,进程又会恢复运行
(如果进程是终端里直接启动的,则需要你用 fg 命令,恢复到前台运行)。
而当你用调试器(如 gdb)调试一个进程时,在使用断点中断进程后,进程就会变成跟踪状态,
这其实也是一种特殊的暂停状态,只不过你可以用调试器来跟踪并按需要控制进程的运行。
X,也就是 Dead 的缩写,表示进程已经消亡
perf 热点函数
类似于 top,它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数
perf top
# -g开启调用关系分析,-p指定php-fpm的进程号21515
$ perf top -g -p 21515
# 记录性能事件,等待大约15秒后按 Ctrl+C 退出
$ perf record -g
# 查看报告
$ perf report
ps 进程
# 从所有进程中查找PID是24344的进程
$ ps aux | grep 24344
pstree 进程关系
用树状形式显示所有进程之间的关系
$ pstree | grep stress
strace 跟踪syscall
跟踪进程系统调用的工具
strace -p 6082
sar 网络收发
是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报告历史统计数据
# -n DEV 表示显示网络收发的报告,间隔1秒输出一组数据
$ sar -n DEV
item解释
- rxpck/s 和 txpck/s 分别表示每秒接收、发送的网络帧数,也就是 PPS
- rxkB/s 和 txkB/s 分别表示每秒接收、发送的千字节数,也就是 BPS
hping3 安全
是一个可以构造 TCP/IP 协议数据包的工具,可以对系统进行安全审计、防火墙测试等
# -S参数表示设置TCP协议的SYN(同步序列号),-p表示目的端口为80
# -i u100表示每隔100微秒发送一个网络帧
# 注:如果你在实践过程中现象不明显,可以尝试把100调小,比如调成10甚至1
$ hping3 -S -p 80 -i u100 192.168.0.30
tcpdump 抓包
是一个常用的网络抓包工具,常用来分析各种网络问题
# -i eth0 只抓取eth0网卡,-n不解析协议名和主机名
# tcp port 80表示只抓取tcp协议并且端口号为80的网络帧
$ tcpdump -i eth0 -n tcp port 80
其他工具
- execsnoop 专为短时进程设计的工具。它通过 ftrace 实时监控进程的 exec() 行为,并输出短时进程的基本信息,包括进程 PID、父进程 PID、命令行参数以及执行的结果 https://github.com/brendangregg/perf-tools/blob/master/execsnoop
- dstat 吸收了 vmstat、iostat、ifstat 等几种工具的优点
CPU
# cpu个数
grep 'model name' /proc/cpuinfo | wc -l
上下文切换
# -d 参数表示高亮显示变化的区域
watch -d cat /proc/interrupts
系统的 CPU 使用率很高
碰到常规问题无法解释的 CPU 使用率情况时,首先要想到有可能是短时应用导致的问题. pstree会很有用,找到它们的父进程,再从父进程所在的应用入手,排查问题的根源
中断
例子:
- 硬中断: 把网卡的数据读到内存中,然后更新一下硬件寄存器的状态;
- 软中断: 被软中断信号唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它送给应用程序;
硬中断
用来快速处理中断;在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作
cat /proc/interrupts
软中断
用来异步处理硬中断未完成的工作,包括网络收发、定时、调度、RCU锁等各种类型;通常以内核线程的方式运行
cat /proc/softirqs
存在item
- TIMER(定时中断)
- NET_RX(网络接收);
- SCHED(内核调度)
- RCU(RCU锁)
内存
case1 写文件
通过读取随机设备,生成一个500MB大小的文件
dd if=/dev/urandom of=/tmp/file bs=1M count=500
Cache在不停地增长,而Buffer基本保持不变;Cache是文件读的缓存;Cache也会缓存写文件时的数据
case2 写磁盘
写磁盘用到了大量的Buffer
case3 读取文件
Buffer保持不变,而Cache则在不停增长;Cache是对文件读的页缓存
case4 读磁盘
Buffer和Cache都在增长,但显然Buffer的增长快很多;
磁盘性能指标
- 使用率,是指磁盘处理I/O的时间百分比。过高的使用率(比如超过80%),通常意味着磁盘 I/O 存在性能瓶颈。
- 饱和度,是指磁盘处理 I/O 的繁忙程度。过高的饱和度,意味着磁盘存在严重的性能瓶颈。当饱和度为 100% 时,磁盘无法接受新的 I/O 请求。
- IOPS(Input/Output Per Second),是指每秒的 I/O 请求数。
- 吞吐量,是指每秒的 I/O 请求大小。
- 响应时间,是指 I/O 请求从发出到收到响应的间隔时间。
网络指标
- 带宽,表示链路的最大传输速率,单位通常为 b/s (比特/秒)。
- 吞吐量,表示单位时间内成功传输的数据量,单位通常为 b/s(比特/秒)或者 B/s(字节/秒)。吞吐量受带宽限制,而吞吐量/带宽,也就是该网络的使用率。
- 延时,表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟。在不同场景中,这一指标可能会有不同含义。比如,它可以表示,建立连接需要的时间(比如 TCP 握手延时),或一个数据包往返所需的时间(比如 RTT)。
- PPS,是 Packet Per Second(包/秒)的缩写,表示以网络包为单位的传输速率。PPS 通常用来评估网络的转发能力,比如硬件交换机,通常可以达到线性转发(即 PPS 可以达到或者接近理论最大值)。而基于 Linux 服务器的转发,则容易受网络包大小的影响。
- 网络的可用性(网络能否正常通信)
- 并发连接数(TCP连接数量)
- 丢包率(丢包百分比)
- 重传率(重新传输的网络包比例)
工具
- ifconfig
- netstat
- ss
- sar
- ping
NAT
分类
- 静态 NAT,即内网 IP 与公网 IP 是一对一的永久映射关系;
- 动态 NAT,即内网 IP 从公网 IP 池中,动态选择一个进行映射;
- 网络地址端口转换 NAPT(Network Address and Port Translation),即把内网 IP 映射到公网 IP 的不同端口上,让多个内网 IP 可以共享同一个公网 IP 地址。
网络优化
提高网络的吞吐量
- 增大每个套接字的缓冲区大小
net.core.optmem_max
; - 增大套接字接收缓冲区大小
net.core.rmem_max
和发送缓冲区大小net.core.wmem_max
; - 增大 TCP 接收缓冲区大小
net.ipv4.tcp_rmem
和发送缓冲区大小net.ipv4.tcp_wmem
- 为 TCP 连接设置
TCP_NODELAY
后,就可以禁用 Nagle 算法; - 为 TCP 连接开启
TCP_CORK
后,可以让小包聚合成大包后再发送(注意会阻塞小包的发送); - 使用
SO_SNDBUF
和SO_RCVBUF
,可以分别调整套接字发送缓冲区和接收缓冲区的大小。
请求数比较大
- 增大处于 TIME_WAIT 状态的连接数量
net.ipv4.tcp_max_tw_buckets
,并增大连接跟踪表的大小net.netfilter.nf_conntrack_max
- 减小
net.ipv4.tcp_fin_timeout
和net.netfilter.nf_conntrack_tcp_timeout_time_wait
,让系统尽快释放它们所占用的资源 - 开启端口复用
net.ipv4.tcp_tw_reuse
。这样,被 TIME_WAIT 状态占用的端口,还能用到新建的连接中。 - 增大本地端口的范围
net.ipv4.ip_local_port_range
。这样就可以支持更多连接,提高整体的并发能力 - 增加最大文件描述符的数量。你可以使用
fs.nr_open
和fs.file-max
,分别增大进程和系统的最大文件描述符数;或在应用程序的 systemd 配置文件中,配置LimitNOFILE
,设置应用程序的最大文件描述符数。
缓解 SYN FLOOD
- 增大 TCP 半连接的最大数量
net.ipv4.tcp_max_syn_backlog
,或者开启 TCP SYN Cookiesnet.ipv4.tcp_syncookies
,来绕开半连接数量限制的问题(注意,这两个选项不可同时使用) - 减少 SYN_RECV 状态的连接重传 SYN+ACK 包的次数
net.ipv4.tcp_synack_retries
长连接
- 缩短最后一次数据包到 Keepalive 探测包的间隔时间
net.ipv4.tcp_keepalive_time
- 缩短发送 Keepalive 探测包的间隔时间
net.ipv4.tcp_keepalive_intvl
; - 减少Keepalive 探测失败后,一直到通知应用程序前的重试次数
net.ipv4.tcp_keepalive_probes
UPD优化
- 增大套接字缓冲区大小以及 UDP 缓冲区范围
- 增大本地端口号的范围
- 根据 MTU 大小,调整 UDP 数据包的大小,减少或者避免分片的发生
路由
- 在需要转发的服务器中,比如用作 NAT 网关的服务器或者使用 Docker 容器时,开启 IP 转发,即设置 net.ipv4.ip_forward = 1。
- 调整数据包的生存周期 TTL,比如设置 net.ipv4.ip_default_ttl = 64。注意,增大该值会降低系统性能。
- 开启数据包的反向地址校验,比如设置 net.ipv4.conf.eth0.rp_filter = 1。这样可以防止 IP 欺骗,并减少伪造 IP 带来的 DDoS 问题。
分片
- 调整 MTU(Maximum Transmission Unit)的大小
ICMP
- 以禁止 ICMP 协议,即设置
net.ipv4.icmp_echo_ignore_all
= 1 - 禁止广播 ICMP,即设置
net.ipv4.icmp_echo_ignore_broadcasts
= 1