导致cpu负载增高的三个场景:
1.cpu密集型进程
2io密集型,等待io也会导致负载升高,但是cpu使用率不一定很高
3.大量等待cpu的进程调度
cpu寄存器:是cpu内置的容量小,速度极快的内存【保存程序运行时的一些数据】
cpu计数器:用来保存cpu正在执行的指令位置或者即将执行的下一条指令位置
cpu上下文切换就是保存当前运行的cpu寄存器和计数器中的数据然后跳转到新的程序计数器位置执行其他进程
频繁的上下文切换会提高cpu负载。
系统调用通常称为特权模式的切换,从ring0切换到ring3,虽然系统调用也会发生上下文切换但是和进程的上下文切换是不一样的,进程上下文切换是一个进程切换到另一个进程运行,而系统调用过程一直是同一个进程在运行
stress 系统压测工具
sysbench 多进程下数据库性能测试工具,也可以用来多线程压测linux系统。
sysstat 系统检测工具软件包:可以对cpu,内存,io等维度监控linux
mpstat:多核cpu检测工具,实时查看每个cpu性能指标
mpstat -P ALL 5 #每5秒检测一次cpu并输出
pidstat:进程性能分析工具,查看进程cpu,内存,io以及上下文切换等指标
pidstat -u 5 1 #每5秒输出一次cpu检测数据
hcache: 查看哪些应用占用了多少系统的内存的cache
dstat: 同事查看cpu,disk io,net io
进程上下文切换分为资源切换和非自愿切换:
自愿切换:进程无法获取所需资源,如io,内存等资源不足
非自愿切换:由于时间片已到被系统强制调度,大量进程争夺cpu时容易发生非自愿切换
查看方式:
pidstat -u -w 1 #-u 输出进程切换指标,
cat cat /proc/interrupts
cpu上下文切换数百到一万以内都算正常,如果超过一万或者成数量级增长就很可能出现了cpu性能瓶颈
查看具体应用的哪个函数引起的cpu负载高:
perf top -g -p 21515 #-g 开启调用关系分析,-p 指定 php-fpm 的进程号...
节拍率 HZ 是内核的可配选项,可以设置为 100、250、1000 等。不同的系统可能设置不同数值,你可以通过查询 /boot/config 内核选项来查看它的配置值。比如在我的系统中,节拍率设置成了 250,也就是每秒钟触发 250 次时间中断。
$ grep 'CONFIG_HZ=' /boot/config-$(uname -r)
cat /proc/stat | grep ^cpu #查看cpu使用统计信息
cat /proc/[pid]/stat | grep ^cpu #查看指定进程cpu使用统计信息
不同工具测出的cpu使用率可能不一致, 比如,对比一下 top 和 ps 这两个工具报告的 CPU 使用率,默认的结果很可能不一样,因为 top 默认使用 3 秒时间间隔,而 ps 使用的却是进程的整个生命周期。
碰到常规问题无法解释的 CPU 使用率情况时,首先要想到有可能是短时应用导致的问题,比如有可能是下面这两种情况:
1.应用里直接调用了其他二进制程序,这些程序通常运行时间比较短,通过 top 等工具也不容易发现
2.应用本身在不停地崩溃重启,而启动过程的资源初始化,很可能会占用相当多的 CPU
对于这类进程,我们可以用 pstree 或者 execsnoop 找到它们的父进程,再从父进程所在的应用入手,排查问题的根源。
################################
strace -p PID #实时跟踪进程的系统调用
当iowait过多到只cpu负载过高时【dstat 1 4 #可以同时查看进程的io和cpu使用情况】:
1.用top找出cpu利用率高的进程
2.pidstat -d -p <PID> 1 4 #查看指定进程的磁盘io情况
iowait高不一定代表io有性能瓶颈,当系统中只有io进程运行时iowait也会高,但远远没有达到io的性能瓶颈。
僵尸进程的问题相对容易排查,使用 pstree 找出父进程后,去查看父进程的代码,检查 wait() / waitpid() 的调用,检查父进程是否遗漏了退出时子进程销毁
################################
cpu中断:
为了解决中断处理程序执行过长和中断丢失的问题,Linux 将中断处理过程分成了两个阶段,也就是上半部分和下半部分
上半部用来快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作。上半部直接处理硬件请求,也就是我们常说的硬中断,特点是快速执行;
下半部用来延迟处理上半部未完成的工作,通常以内核线程的方式运行,而下半部则是由内核触发,也就是我们常说的软中断,特点是延迟执行。
上半部会打断 CPU 正在执行的任务,然后立即执行中断处理程序。而下半部以内核线程的方式执行,并且每个 CPU 都对应一个软中断内核线程,名字为 “ksoftirqd/CPU 编号”,比如说, 0 号 CPU 对应的软中断内核线程的名字就是 ksoftirqd/0。
/proc/softirqs 提供了软中断的运行情况;
/proc/interrupts 提供了硬中断的运行情况。
一般来说,ps 的输出中,名字括在中括号里的,一般都是内核线程。
软中断过导致cpu利用率高的解决思路:
从系统的软中断使用率高这个现象出发,通过观察 /proc/softirqs 文件的变化情况,判断出软中断类型是网络接收中断
# -n DEV 表示显示网络收发的报告,间隔 1 秒输出一组数据
sar -n DEV 1
tcpdump 抓包找出可疑发包ip
防火墙禁用ip
##########
当物理内存不足的时候,内存的回收机制:
1.回收缓存(文件页),基于lru(最近最少使用原则)算法
2.回收匿名页,swap机制
3.oom,杀死占用大量内存的进程
OOM(OUT OF MEMORY):
echo -16 > /proc/$(pidof sshd)/oom_adj
oom_adj 的范围是 [-17, 15],数值越大,表示进程越容易被 OOM 杀死;数值越小,表示进程越不容易被 OOM 杀死,其中 -17 表示禁止 OOM。
cachetop #查看进程缓存使用情况
cachestat #查看系统缓存使用情况
/pro/zoneinfo #查看内存情况(page_min page_high page_low)
/proc/sys/vm/swappiness 选项,用来调整使用 Swap 的积极程度。swappiness 的范围是 0-100,数值越大,越积极使用 Swap,也就是更倾向于回收匿名页;数值越小,越消极使用 Swap,也就是更倾向于回收文件页。
#创建基于文件的swap
# 创建 Swap 文件
$ fallocate -l 8G /mnt/swapfile
# 修改权限只有根用户可以访问
$ chmod 600 /mnt/swapfile
# 配置 Swap 文件
$ mkswap /mnt/swapfile
# 开启 Swap
$ swapon /mnt/swapfile
IO优化:
linux为每个文件都分配了两个数据结构:
1.索引节点(inode)
2.目录项(dentry,文件系统的目录结构,是由内核维护的内存数据结构,通常成为目录项缓存)
内核使用slab机制管理目录项和索引节点(inode),/proc/meminfo只给出了slab的整体大小,具体到每一种缓存,要查看/proc/slabinfo (
cat /proc/slabinfo | grep -E '^#|dentry|inode'
)
3.逻辑块:是由连续磁盘扇区构成的最小读写单元,用来存储文件数据
4.超级块:用来记录文件系统的整体状态,如索引节点和逻辑块的使用情况。
目录项是一个内存缓存,而超级块/索引节点和逻辑块是存储在磁盘中的持久化数据。
iostat -d -x 1 . #查看磁盘io状态(iops,util等)
pidstat -d 1 #查看进程磁盘使用情况
iotop #根据io使用情况排序
案例一:找出狂打日志的应用程序:
1.top 命令查看进程资源利用率,发现iowait 高(初步确认是磁盘问题导致cpu利用率高)
2.pidstat -d 1 查看每个进程的磁盘利用率(找出磁盘利用率高的进程)
3.strace -p 进程号 跟踪系统调用,看到了write 调用,进程正在每秒300mb的速度写文件
4.lsof -p 进程号 查看进程打开了哪些文件
这跟刚才 strace 完我们猜测的结果一致,看来这就是问题的根源:进程 18940 以每次 300MB 的速度,在“疯狂”写日志,而日志文件的路径是 /tmp/logtest.txt。查看应用程序源码发现应用程序的日志级别为info,所以会频繁打日志,将日志级别改为warn后问题解决。
案例二:磁盘io延迟很高:
1.top命令查看资源利用率发现cpu的iowait 很高,内存充足
2.iostat -d -x 1 查看磁盘使用情况,发现磁盘利用率达到98%
3.pistat -d 1 查看进程io的利用情况
4.strace -p 进程号查看我们第三部找到的io利用率高的进程,但是未发现write 系统调用
5.使用新工具 filetop(跟踪内核的文件读写情况,输出线程id,读写大小及文件名称)
6.利用ps命令找出第五步读写文件线程所属的进程,发现就是我们第四部找到的cpu利用率高的进程
7.用opensnoop 命令跟踪内核中的open系统调用,可以得到打开文件的路径(filetop只给出文件名称,没有路径)
结论:结合前面的所有分析,我们基本可以判断,案例应用会动态生成一批文件,用来临时存储数据,用完就会删除它们。但不幸的是,正是这些文件读写,引发了 I/O 的性能瓶颈,导致整个处理过程非常慢,在项目中如果要临时缓存一些数据最好基于内存方式,或者redis之类的,尽量不要使用磁盘。
网络调优:
nethogs #查看进程实时的网络io
nethogs #查看网卡实时流量
iftop #查看主机实时流量(显示源和目的地址)
网络性能指标:带宽,吞吐量,延时,pps
netstat -s 查看协议栈统计信息
sar -n DEV 1 查看传输网卡相关参数(利用率,pps,吞吐量等)
ethtool eth0 查看网卡状态(speed 等)
网络性能测试(带宽,pps)
modprobe pktgen #加载模块
测试脚本:
# 定义一个工具函数,方便后面配置各种测试选项
function pgset() {
local result
echo $1 > $PGDEV
result=`cat $PGDEV | fgrep "Result: OK:"`
if [ "$result" = "" ]; then
cat $PGDEV | fgrep Result:
fi
}
# 为 0 号线程绑定 eth0 网卡
PGDEV=/proc/net/pktgen/kpktgend_0
pgset "rem_device_all" # 清空网卡绑定
pgset "add_device eth0" # 添加 eth0 网卡
# 配置 eth0 网卡的测试选项
PGDEV=/proc/net/pktgen/eth0
pgset "count 1000000" # 总发包数量
pgset "delay 5000" # 不同包之间的发送延迟 (单位纳秒)
pgset "clone_skb 0" # SKB 包复制
pgset "pkt_size 64" # 网络包大小
pgset "dst 192.168.0.30" # 目的 IP
pgset "dst_mac 11:11:11:11:11:11" # 目的 MAC
# 启动测试
PGDEV=/proc/net/pktgen/pgctrl
pgset "start"
测试tcp/udp性能(吞吐量):
iperf3:
安装:
# Ubuntu
apt-get install iperf3
# CentOS
yum install iperf3
# -s 表示启动服务端,-i 表示汇报间隔,-p 表示监听端口
$ iperf3 -s -i 1 -p 10000
# -c 表示启动客户端,192.168.0.30 为目标服务器的 IP
# -b 表示目标带宽 (单位是 bits/s)
# -t 表示测试时间
# -P 表示并发数,-p 表示目标服务器监听端口
$ iperf3 -c 192.168.0.30 -b 1G -t 15 -P 2 -p 10000
http性能测试:
安装ab:
# Ubuntu
$ apt-get install -y apache2-utils
# CentOS
$ yum install -y httpd-tools
# -c 表示并发请求数为 1000,-n 表示总的请求数为 10000
$ ab -c 1000 -n 10000 http://192.168.0.30/
应用负载能力:
wrk
dns解析相关:
1.nslookup --debug www.baidu.com
2.dig:
@114.114.114.114 #指定nameserver
+trace #查看解析流程
-x #反向解析(根据ip解析出域名)
如果dns解析失败,先用nslookup --debug 查看失败原因。配置dns服务器时可以ping dns服务器,可以根据ping的延迟选择最稳定的服务器,也可以dig 相关相关域名时查看所需查询时间等综合指标选择最合适的dns服务器。
dns解析不稳定可以增加dns缓存。最简单的是安装dnsmasq,然后将nameserver指向启动dnsmasq 的服务器。
ping 命令默认会将ip反向解析为域名(rtt)如果遇到ping命令很慢的情况可以加上选项-n(linux中)
防御DDOS:
怎样确认为ddos攻击:
1.cpu 负载变高
2.sar -n DEV 1 发现pps剧增,但网络实时流量很小(小包很多)
3.netstat -na 看到很多SYN_RECV状态的连接
缓解方法:
1.抓到指定异常ip,然后加入iptables 拒绝
2.
# 限制 syn 并发数为每秒 1 次
$ iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT
# 限制单个 IP 在 60 秒新建立的连接数为 10
$ iptables -I INPUT -p tcp --dport 80 --syn -m recent --name SYN_FLOOD --update --seconds 60 --hitcount 10 -j REJECT
3.增大半开连接数量:
sysctl -w net.ipv4.tcp_max_syn_backlog=1024
net.ipv4.tcp_max_syn_backlog = 1024
4.减少SYV_RECV失败重试次数:
sysctl -w net.ipv4.tcp_synack_retries=1
net.ipv4.tcp_synack_retries = 1
Note:Nagle 算法与cork算法以及tcp延迟确认
####### 网卡丢包问题排查 ##########
问题:nginx 服务器访问
1,hping3 -c 10 -S -p 80 192.168.0.30 #尝试nginx 端口,测试端口及返回时间是否正常
2.netstat -i #查看网卡丢包记录
3. tc -s qdisc show dev eth0 #查看是否有qos限制
4. netstat -s #查看协议收发汇总信息(重传,连接失败等信息)
5.sysctl net.netfilter.nf_conntrack_max #查看conntrack表信息
6.ulimit -n #查看系统文件打开数信息
7. iptables -Ln -v #查看是否有iptables 规则
8.tcpdump 抓包 #查看通信过程是否正常
9.netstat -i #查看网卡mtu设置是否正常
note: curl 与 hping 区别,hping只发送syn,只连接不发送实际数据,curl命令即发送syn建立tcp连接又要发送http包(发送mtu 大小的包,所以有时候hping能成功,而curl无法成功!)