Linux系统频繁死机处理思路

故障背景

最近,某视频业务注册系统,云主机频繁出现死机假死现象,只能通过重启来处理,无法执行任何命令操作,ping不通;但重启后发现系统各日志中并没有记录到任何死机前后的信息,定位故障非常困难。

什么是假死现象???

所谓假死现象,是指 Linux 内核 Alive,但是其上的某个或所有操作的响应变得很慢的现象。具体比较常见的现象有如下几种:

●能 Ping 通访问的服务器。
●系统负载非常的高。
●SSH 不能登陆或者登陆比较慢。
●服务器上提供的服务都不能正常响应,比如:不能访问系统上部署的 Web 服务器所提供的页面。
●在系统上做任何其它操作都没有反应或者反应较慢。

处理排查思路

一、利用某些工具

1.1 Core dump

Core dump 通常用来调试应用程序错误,当某些应用程序运行出现异常崩溃时,可以开启系统的 core dump 功能,来得到一个程序崩溃时的内存信息,用来分析崩溃原因:
$vim /etc/profile //新增一行ulimit -c 0
运行命令:sysctl -w “kernel.core_name_format=/coredump/%n.core” //core文件放在/coredump目录下,文件名是进程名+.core

1.2Diskdump
diskdump工具提供了在单机上创建和采集vmcore(kernel dump)的能力,而无须使用网络。当内核本身出现崩溃的时候,当前的内存和CPU状态以及相关的信息都会被保存到一个支持diskdump的磁盘上的保留分区上。在下一次重新启动的时候,当系统重新启动,diskdump的初始化脚本会从保留分区中读取保存的信息并创建一个vcore文件,然后这个文件被再次存放到/var/crash/目录下,文件名为127.0.0.1-*;
开启过程:
#modprobe diskdump
#vim /etc/sysconfig/diskdump //新增或填写一个空设备用于存放相关信息,如DEVICE=/dev/cciss/c0d0p2
#service diskdump initialformat //初使化 dump 设备,该分区的所有数据会丢失。
#vi /etc/modprobe.conf //
修改alias scsi_hostadapter cciss为:
alias scsi_hostadapter cciss_dump
新增加一行:
options cciss_dump dump_drive=1

注:假设diskdump文件中配置的为 /dev/cciss/c0d[#a]p[#b], 请设置为:
options cciss_dump dump_drive=[#a]

#mv /boot/initrd-uname -r.img /boot/initrd-uname -r.img.old //重建 initrd 文件
#mkinitrd /boot/initrd-uname -r.img uname -r

设置 diskdump 服务能够开机自启动:
#chkconfig diskdump on

**注意:**建议使用 nice 命令将 SSHD 的进程优先级调高,这样当系统内存紧张时,还能勉强登陆服务器进行调试,然后分析故障。

二、排查应用进程导致的假死

2.1 利用strace命令进行进程跟踪

Strace是一个用来跟踪系统调用的简易工具。它最简单的用途就是跟踪一个程序整个生命周期里所有的系统调用,并把调用参数和返回值以文本的方式输出。

执行:#strace -p pid //跟踪进程执行时的系统调用和所接收的信号(即它跟踪到一个进程产生的系统调用,包括参数、返回值、执行消耗的时间等,观察是否允许正常或会卡在什么地方

如上述报一些读文件的数字被卡滞,可执行以下命令,查看进程文件描述符目录:
#cd /proc/pid/fd下,ll查看文件描述符的链接通道;

netstat -anoutp |grep pid //确认应用的端口

另外,strace还可辅助排查:
1>遇到读取文件的时被拒绝,执行下面的命令:
$ strace -e open,access 2>&1 | grep your-filename //查看open()和access()系统调用是否有异常

2>进程突然cpu占用率很高,进程莫名其妙被挂起,查看当前进程状态
strace -p 对应进程的pid
3>统计程序的调用时间
程序进行性能分析往往需要重新编译程序,并打开跟踪选项。用strace可以很容易的附加到进程上查看实时的时间消耗
strace -c -p pid
eg1:
root@dev:~# strace -c -p 11084 //按ctrl-c退出前程序的调用时间将会打印出来
Process 11084 attached - interrupt to quit
Process 11084 detached
% time seconds usecs/call calls errors syscall


94.59 0.001014 48 21 select
2.89 0.000031 1 21 getppid
2.52 0.000027 1 21 time


100.00 0.001072 63 total
4>跟踪一次程序的开始和结束
eg1:# strace -c >/dev/null ls
% time seconds usecs/call calls errors syscall


23.62 0.000205 103 2 getdents64
18.78 0.000163 15 11 1 open
15.09 0.000131 19 7 read
12.79 0.000111 7 16 old_mmap
7.03 0.000061 6 11 close
4.84 0.000042 11 4 munmap
4.84 0.000042 11 4 mmap2
4.03 0.000035 6 6 6 access
3.80 0.000033 3 11 fstat64
1.38 0.000012 3 4 brk
0.92 0.000008 3 3 3 ioctl
0.69 0.000006 6 1 uname
0.58 0.000005 5 1 set_thread_area
0.35 0.000003 3 1 write
0.35 0.000003 3 1 rt_sigaction
0.35 0.000003 3 1 fcntl64
0.23 0.000002 2 1 getrlimit
0.23 0.000002 2 1 set_tid_address
0.12 0.000001 1 1 rt_sigprocmask


100.00 0.000868 87 10 total
5>排查应用无法正常提供服务
eg1 strace -e poll,select,connect,recvfrom,sendto nc www.news.com :80 //跟踪“nc”命令连接到www.news.com的80端口

三、系统性能问题排查

3.1 top命令,vmstat查看负载在这里插入图片描述
第一行后面的三个值是系统在之前 1、5、15 的平均负载,也可以看出系统负载是上升、平稳、下降的趋势,当这个值超过 CPU 可执行单元的数目,则表示 CPU 的性能已经饱和成为瓶颈了。

第二行统计了系统的任务状态信息。running 很自然不必多说,包括正在 CPU 上运行的和将要被调度运行的;sleeping 通常是等待事件(比如 IO 操作)完成的任务,细分可以包括 interruptible 和 uninterruptible 的类型;stopped 是一些被暂停的任务,通常发送 SIGSTOP 或者对一个前台任务操作 Ctrl-Z 可以将其暂停;zombie 僵尸任务,虽然进程终止资源会被自动回收,但是含有退出任务的 task descriptor 需要父进程访问后才能释放,这种进程显示为 defunct 状态,无论是因为父进程提前退出还是未 wait 调用,出现这种进程都应该格外注意程序是否设计有误。

第三行 CPU 占用率根据类型有以下几种情况:

(us) user:CPU 在低 nice 值(高优先级)用户态所占用的时间(nice<=0)。正常情况下只要服务器不是很闲,那么大部分的 CPU 时间应该都在此执行这类程序
(sy) system:CPU 处于内核态所占用的时间,操作系统通过系统调用(system call)从用户态陷入内核态,以执行特定的服务;通常情况下该值会比较小,但是当服务器执行的 IO 比较密集的时候,该值会比较大
(ni) nice:CPU 在高 nice 值(低优先级)用户态以低优先级运行占用的时间(nice>0)。默认新启动的进程 nice=0,是不会计入这里的,除非手动通过 renice 或者 setpriority() 的方式修改程序的nice值
(id) idle:CPU 在空闲状态(执行 kernel idle handler )所占用的时间
(wa) iowait:等待 IO 完成做占用的时间
(hi) irq:系统处理硬件中断所消耗的时间
(si) softirq:系统处理软中断所消耗的时间,记住软中断分为 softirqs、tasklets (其实是前者的特例)、work queues,不知道这里是统计的是哪些的时间,毕竟 work queues 的执行已经不是中断上下文了
(st) steal:在虚拟机情况下才有意义,因为虚拟机下 CPU 也是共享物理 CPU 的,所以这段时间表明虚拟机等待 hypervisor 调度 CPU 的时间,也意味着这段时间 hypervisor 将 CPU 调度给别的 CPU 执行,这个时段的 CPU 资源被“stolen”了。这个值在我 KVM 的 VPS 机器上是不为 0 的,但也只有 0.1 这个数量级,是不是可以用来判断 VPS 超售的情况?
CPU 占用率高很多情况下意味着一些东西,这也给服务器 CPU 使用率过高情况下指明了相应地排查思路:

当 user 占用率过高的时候,通常是某些个别的进程占用了大量的 CPU,这时候很容易通过 top 找到该程序;此时如果怀疑程序异常,可以通过 perf 等思路找出热点调用函数来进一步排查;
当 system 占用率过高的时候,如果 IO 操作(包括终端 IO)比较多,可能会造成这部分的 CPU 占用率高,比如在 file server、database server 等类型的服务器上,否则(比如>20%)很可能有些部分的内核、驱动模块有问题;
当 nice 占用率过高的时候,通常是有意行为,当进程的发起者知道某些进程占用较高的 CPU,会设置其 nice 值确保不会淹没其他进程对 CPU 的使用请求;
当 iowait 占用率过高的时候,通常意味着某些程序的 IO 操作效率很低,或者 IO 对应设备的性能很低以至于读写操作需要很长的时间来完成;当 irq/softirq 占用率过高的时候,很可能某些外设出现问题,导致产生大量的irq请求,这时候通过检查 /proc/interrupts 文件来深究问题所在;当 steal 占用率过高的时候,黑心厂商虚拟机超售了吧!
第四行和第五行是物理内存和虚拟内存(交换分区)的信息:
total = free + used + buff/cache,现在buffers和cached Mem信息总和到一起了,但是buffers和cached

Mem 的关系很多地方都没说清楚。其实通过对比数据,这两个值就是 /proc/meminfo 中的 Buffers 和 Cached 字段:Buffers 是针对 raw disk 的块缓存,主要是以 raw block 的方式缓存文件系统的元数据(比如超级块信息等),这个值一般比较小(20M左右);而 Cached 是针对于某些具体的文件进行读缓存,以增加文件的访问效率而使用的,可以说是用于文件系统中文件缓存使用。

而 avail Mem 是一个新的参数值,用于指示在不进行交换的情况下,可以给新开启的程序多少内存空间,大致和 free + buff/cached 相当,而这也印证了上面的说法,free + buffers + cached Mem才是真正可用的物理内存。并且,使用交换分区不见得是坏事情,所以交换分区使用率不是什么严重的参数,但是频繁的 swap in/out 就不是好事情了,这种情况需要注意,通常表示物理内存紧缺的情况。

最后是每个程序的资源占用列表,其中 CPU 的使用率是所有 CPU core 占用率的总和。通常执行 top 的时候,本身该程序会大量的读取 /proc 操作,所以基本该 top 程序本身也会是名列前茅的。
在这里插入图片描述
参数说明:r 表示可运行进程数目,数据大致相符;而b表示的是 uninterruptible 睡眠的进程数目;swpd 表示使用到的虚拟内存数量,跟 top-Swap-used 的数值是一个含义,而如手册所说,通常情况下 buffers 数目要比 cached Mem 小的多,buffers 一般20M这么个数量级;io 域的 bi、bo 表明每秒钟向磁盘接收和发送的块数目(blocks/s);system 域的 in 表明每秒钟的系统中断数(包括时钟中断),cs表明因为进程切换导致上下文切换的数目。
在这里插入图片描述
mpstat,查看在 SMP 处理器上各个 Core 的工作量是否负载均衡,是否有某些热点线程占用 Core.
执行:$ mpstat -P ALL 1 //每个1s刷新,查看所有处理器负载
在这里插入图片描述
3.2 进程性能查看pidstat

对某个进程进行全面具体的追踪,没有什么比 pidstat 更合适的了——栈空间、缺页情况、主被动切换等信息尽收眼底。这个命令最有用的参数是-t,可以将进程中各个线程的详细信息罗列出来。
在这里插入图片描述
在这里插入图片描述
参数说明:-r: 显示缺页错误和内存使用状况,缺页错误是程序需要访问映射在虚拟内存空间中但是还尚未被加载到物理内存中的一个分页,缺页错误两个主要类型是minflt/s 指的 minor faults,当需要访问的物理页面因为某些原因(比如共享页面、缓存机制等)已经存在于物理内存中了,只是在当前进程的页表中没有引用,MMU 只需要设置对应的 entry 就可以了,这个代价是相当小的;majflt/s 指的 major faults,MMU 需要在当前可用物理内存中申请一块空闲的物理页面(如果没有可用的空闲页面,则需要将别的物理页面切换到交换空间去以释放得到空闲物理页面),然后从外部加载数据到该物理页面中,并设置好对应的 entry,这个代价是相当高的,和前者有几个数据级的差异。

-s:栈使用状况,包括 StkSize 为线程保留的栈空间,以及 StkRef 实际使用的栈空间。使用ulimit -s发现CentOS 6.x上面默认栈空间是10240K,而 CentOS 7.x、Ubuntu系列默认栈空间大小为8196K

-u:CPU使用率情况,参数同前面类似

-w:线程上下文切换的数目,还细分为cswch/s因为等待资源等因素导致的主动切换,以及nvcswch/s线程CPU时间导致的被动切换的统计

**技巧:**如果每次都先ps得到程序的pid后再操作pidstat会显得很麻烦,所以这个杀手锏的-C可以指定某个字符串,然后Command中如果包含这个字符串,那么该程序的信息就会被打印统计出来,-l可以显示完整的程序名和参数
eg1:pidstat -w - -C “ssh” -l|less //查看单个尤其是多线程的任务时候,pidstat比常用的ps更好使!
在这里插入图片描述
如果想直接监测某个进程占用的资源,既可以使用top -u taozj的方式过滤掉其他用户无关进程,也可以采用下面的方式进行选择
执行命令:$ while :; do ps -eo user,pid,ni,pri,pcpu,psr,comm | grep ‘watch’; sleep 1; done
在这里插入图片描述
3.3 进程磁盘IO类排查
iotop 可以直观的显示各个进程、线程的磁盘读取实时速率;lsof 不仅可以显示普通文件的打开信息(使用者),还可以操作 /dev/sda1 这类设备文件的打开信息,那么比如当分区无法 umount 的时候,就可以通过 lsof 找出磁盘该分区的使用状态了,而且添加 +fg 参数还可以额外显示文件打开 flag 标记。
eg1:iostat -xz 1
在这里插入图片描述
eg2: sar -d 1
在这里插入图片描述
参数说明:
avgqu-s: 发送给设备 I/O 请求的等待队列平均长度,对于单个磁盘如果值>1表明设备饱和,对于多个磁盘阵列的逻辑磁盘情况除外
await(r_await、w_await): 平均每次设备 I/O 请求操作的等待时间(ms),包含请求排列在队列中和被服务的时间之和;
svctm: 发送给设备 I/O 请求的平均服务时间(ms),如果 svctm 与 await 很接近,表示几乎没有 I/O 等待,磁盘性能很好,否则磁盘队列等待时间较长,磁盘响应较差;
%util: 设备的使用率,表明每秒中用于 I/O 工作时间的占比,单个磁盘当 %util>60% 的时候性能就会下降(体现在 await 也会增加),当接近100%时候就设备饱和了,但对于有多个磁盘阵列的逻辑磁盘情况除外;

3.4 网络排查

这里用sar命令,虽然其也可监控CPU、磁盘、页面交换等,这里使用 -n 主要用来分析网络活动,且网络中它可以监视 NFS、IP、ICMP、SOCK 等各种层次各种协议的数据信息,我们多只关心 TCP 和 UDP,执行命令:
在这里插入图片描述
参数说明:
active/s:本地发起的 TCP 连接,比如通过 connect(),TCP 的状态从CLOSED -> SYN-SENT
passive/s:由远程发起的 TCP 连接,比如通过 accept(),TCP 的状态从LISTEN -> SYN-RCVD
retrans/s(tcpRetransSegs):每秒钟 TCP 重传数目,通常在网络质量差,或者服务器过载后丢包的情况下,根据 TCP 的确认重传机制会发生重传操作
isegerr/s(tcpInErrs):每秒钟接收到出错的数据包(比如 checksum 失败)

其他IO命令:
$ iostat -kx 2

$ vmstat 2 10

$ mpstat 2 10

$ dstat --top-io --top-bio

UDP排查:执行sar -n UDP 1
在这里插入图片描述

noport/s(udpNoPorts):每秒钟接收到的但是却没有应用程序在指定目的端口的数据报个数
idgmerr/s(udpInErrors):除了上面原因之外的本机接收到但却无法派发的数据报个数

eg3、tcpdump命令

复原环境,使用 tcpdump 进行抓包,当问题复现(比如日志显示或者某个状态显现)的时候,就可以结束抓包了,而且 tcpdump 本身带有 -C/-W 参数,可以限制抓取包存储文件的大小,当达到这个这个限制的时候保存的包数据自动 rotate,所以抓包数量总体还是可控的,另可以指定网卡、主机、端口、协议等各项过滤参数,抓下来的包完整又带有时间戳。此后将数据包拿下线来,用 wireshark 再进行分析;
1>监视指定网络接口的数据包:
#tcpdump -i eth1 //默认tcpdump只会监视第一个网络接口,一般是eth0
2>监视指定主机的数据包
#tcpdump host blue //打印所有进入或离开主机blue的数据包.
#tcpdump host 202.27.48.2 //截获所有202.27.48.2 的主机收到的和发出的所有的数据包
#tcpdump host a and ( b or c ) //打印主机a与b 或者与 c 之间通信的数据包
#tcpdump host 202.27.48.2 and \ (202.27.48.5 or 202.27.50.1 ) //截获主机202.27.48.2 和主机202.27.48.1 或202.27.50.1的通信
#tcpdump ip host a and not b //打印a与任何其他主机之间通信的IP 数据包, 但不包括与b之间的数据包.
#tcpdump ip host 202.27.48.2 and !202.27.48.3 //如果想要获取主机202.27.48.2除了和主机202.27.48.3之外所有主机通信的ip包
#tcpdump -i eth0 src host hostname //截获主机hostname发送的所有数据
#tcpdump -i eth0 dst host hostname //监视所有送到主机hostname的数据包

3>监视指定主机和端口的数据包
#tcpdump tcp port 23 and host 210.27.48.1 //获取主机210.27.48.1接收或发出的telnet包
#tcpdump udp port 123 对本机的udp 123 // 端口进行监视 123 为ntp的服务端口
#tcpdump ‘gateway snup and (port ftp or ftp-data)’ //打印所有通过网关snup的ftp数据包(注意, 表达式被单引号括起来了, 这可以防止shell对其中的括号进行错误解析)
#tcpdump ip and not net localnet ///打印所有源地址或目标地址是本地主机的IP数据包(如果本地网络通过网关连到了另一网络, 则另一网络并不能算作本地网络.(nt: 此句翻译曲折,需补充).localnet 实际使用时要真正替换成本地网络的名字)

4>监视指定协议的数据包
eg1、打印TCP会话中的的开始和结束数据包, 并且数据包的源或目的不是本地网络上的主机
#tcpdump ‘tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net localnet’

eg2、打印所有源或目的端口是80, 网络层协议为IPv4, 并且含有数据,而不是SYN,FIN以及ACK-only等不含数据的数据包.
tcpdump ‘tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)’

其中,ip[2:2]表示整个ip数据包的长度, (ip[0]&0xf)<<2)表示ip数据包包头的长度(ip[0]&0xf代表包中的IHL域, 而此域的单位为32bit, 要换算成字节数需要乘以4, 即左移2. (tcp[12]&0xf0)>>4 表示tcp头的长度, 此域的单位也是32bit, 换算成比特数为 ((tcp[12]&0xf0) >> 4) << 2, 即 ((tcp[12]&0xf0)>>2). ((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0 表示: 整个ip数据包的长度减去ip头的长度,再减去tcp头的长度不为0, 这就意味着, ip数据包中确实是有数据.对于ipv6版本只需考虑ipv6头中的’Payload Length’ 与 'tcp头的长度’的差值, 并且其中表达方式’ip[]‘需换成’ip6[]’.)

eg3、打印长度超过576字节, 并且网关地址是snup的IP数据包
tcpdump ‘gateway snup and ip[2:2] > 576’

eg4、打印所有IP层广播或多播的数据包, 但不是物理以太网层的广播或多播数据报
tcpdump ‘ether[0] & 1 = 0 and ip[16] >= 224’

eg5、打印除’echo request’或者’echo reply’类型以外的ICMP数据包( 比如,需要打印所有非ping 程序产生的数据包时可用到此表达式 .
(nt: ‘echo reuqest’ 与 ‘echo reply’ 这两种类型的ICMP数据包通常由ping程序产生))
tcpdump ‘icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply’

eg6、组合命令
tcpdump tcp -i eth1 -t -s 0 -c 100 and dst port ! 22 and src net 192.168.1.0/24 -w ./target.cap
(1)tcp: ip icmp arp rarp 和 tcp、udp、icmp这些选项等都要放到第一个参数的位置,用来过滤数据报的类型
(2)-i eth1 : 只抓经过接口eth1的包
(3)-t : 不显示时间戳
(4)-s 0 : 抓取数据包时默认抓取长度为68字节。加上-S 0 后可以抓到完整的数据包
(5)-c 100 : 只抓取100个数据包
(6)dst port ! 22 : 不抓取目标端口是22的数据包
(7)src net 192.168.1.0/24 : 数据包的源网络地址为192.168.1.0/24
(8)-w ./target.cap : 保存成cap文件,方便用ethereal(即wireshark)分析

eg7、使用tcpdump抓取HTTP包
tcpdump -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854
说明:0x4745 为"GET"前两个字母"GE",0x4854 为"HTTP"前两个字母"HT"。

连接数排查
1>查看单个进程能打开的最大句柄数,如果太小需要进行修改;
查看:ulimit -a
修改:vi /etc/security/limits.conf
2>统计各状态的连接数量
netstat -n | awk ‘/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}’
如果ESTABLISHED占大多数,说明系统正常,已经达到单机极限,需增加机器数量;如果TIME_WAIT或者CLOSE_WAIT过多,查看博文进行排查修复。

3.5 内核、中断排查
$ sysctl -a | grep …

$ cat /proc/interrupts //中断请求是否是均衡地分配给CPU处理,还是会有某个CPU的核因为大量的网络中断请求或者RAID请求而过载了

$ cat /proc/net/ip_conntrack //conntrack_max是否设的足够大,能应付你服务器的流量

$ netstat //在不同状态下(TIME_WAIT, …)TCP连接时间的设置是怎样

$ ss -s

$ dmesg

$ less /var/log/messages

$ less /var/log/secure

$ less /var/log/auth
检查定时任务:
$ ls /etc/cron* + cat

$ for user in $(cat /etc/passwd | cut -f1-d:); do crontab -l -u $user; done

……未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

羌俊恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值