Contents

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_SNDBUFSO_RCVBUF ,可以分别调整套接字发送缓冲区和接收缓冲区的大小。

请求数比较大

  • 增大处于 TIME_WAIT 状态的连接数量 net.ipv4.tcp_max_tw_buckets,并增大连接跟踪表的大小 net.netfilter.nf_conntrack_max
  • 减小 net.ipv4.tcp_fin_timeoutnet.netfilter.nf_conntrack_tcp_timeout_time_wait ,让系统尽快释放它们所占用的资源
  • 开启端口复用 net.ipv4.tcp_tw_reuse。这样,被 TIME_WAIT 状态占用的端口,还能用到新建的连接中。
  • 增大本地端口的范围 net.ipv4.ip_local_port_range 。这样就可以支持更多连接,提高整体的并发能力
  • 增加最大文件描述符的数量。你可以使用 fs.nr_openfs.file-max ,分别增大进程和系统的最大文件描述符数;或在应用程序的 systemd 配置文件中,配置 LimitNOFILE ,设置应用程序的最大文件描述符数。

缓解 SYN FLOOD

  • 增大 TCP 半连接的最大数量 net.ipv4.tcp_max_syn_backlog ,或者开启 TCP SYN Cookies net.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