Linux系统故障定位与优化

欠伸展肢体,吟咏心自愉。这篇文章主要讲述Linux系统故障定位与优化相关的知识,希望能为你提供帮助。
内存查看 Ex1、内存使用紧张?排查思路:
1) 用户访问量增加,导致服务使用内存增加;
2) 程序异常,内存泄漏;
使用vmstat查看内存使用

[root@inf-c7-n1 ~]# vmstat 1 10 procs -----------memory-------------swap-- -----io---- -system-- ------cpu----- rbswpdfreebuffcachesisobiboincs us sy id wa st 100 157883882108 24073600005400 10000 000 157883882108 2407360000372300 10000 000 157883882108 2407360000433000 10000 000 157883882108 2407360000292700 10000 000 157883882108 2407360000291900 10000 000 157883882108 2407360000312400 10000 000 157883882108 2407360000191300 10000 000 157883882108 2407360000453900 10000 000 157882482108 2407360002555100 10000 000 157882482108 2407360000232000 10000

显示说明:
字段
含义
procs
进程信息字段:
· -r:等待运行的进程数,数量越大,系统越繁忙。
· -b:不可被唤醒的进程数量,数量越大,系统越繁忙。
memory
内存信息字段:
· -swpd:虚拟内存的使用情况,单位为 KB。
· -free:空闲的内存容量,单位为 KB。
· -buff:缓冲的内存容量,单位为 KB。
· -cache:缓存的内存容量,单位为 KB。
swap
交换分区信息字段:
· -si:从磁盘中交换到内存中数据的数量,单位为 KB。
· -so:从内存中交换到磁盘中数据的数量,单位为 KB。
这两个数越大,表明数据需要经常在磁盘和内存之间进行交换,系统性能越差。
io
磁盘读/写信息字段:
· -bi:从块设备中读入的数据的总量,单位是块。
· -bo:写到块设备的数据的总量,单位是块。
这两个数越大,代表系统的 I/O 越繁忙。
system
系统信息字段:
· -in:每秒被中断的进程次数。
· -cs:每秒进行的事件切换次数。
这两个数越大,代表系统与接口设备的通信越繁忙。
cpu
CPU信息字段:
· -us:非内核进程消耗 CPU 运算时间的百分比。
· -sy:内核进程消耗 CPU 运算时间的百分比。
· -id:空闲 CPU 的百分比。
· -wa:等待 I/O 所消耗的 CPU 百分比。
· -st:被虚拟机所盗用的 CPU 百分比。
查看网络服务使用的内存
[root@localhost vmfs]# ss -tmpio StateRecv-Q Send-QLocal Address:PortPeer Address:Port ESTAB0010.199.13.25:ssh10.199.5.128:50143users:(("sshd",pid=37674,fd=3)) timer:(keepalive,104min,0) skmem:(r0,rb934516,t0,tb1000960,f8192,w0,o0,bl0,d0) sack cubic wscale:8,7 rto:227 rtt:26.317/18.779 ato:40 mss:1460 rcvmss:1460 advmss:1460 cwnd:10 ssthresh:16 bytes_acked:1257181613 bytes_received:5834836 segs_out:973509 segs_in:218250 send 4.4Mbps lastsnd:1 lastrcv:29 pacing_rate 8.9Mbps retrans:0/124 rcv_rtt:360 rcv_space:104368 ESTAB00[::1]:x11-ssh-offset[::1]:56476users:(("sshd",pid=37674,fd=12)) skmem:(r0,rb1061184,t0,tb2626560,f0,w0,o0,bl0,d2) ts sack cubic wscale:7,7 rto:205 rtt:4.411/8.689 ato:40 mss:65464 rcvmss:536 advmss:65464 cwnd:10 bytes_acked:2248 bytes_received:484 segs_out:15 segs_in:19 send 1187.3Mbps lastsnd:15309980 lastrcv:15309980 lastack:15309980 pacing_rate 2374.5Mbps rcv_space:43690 ESTAB00[::1]:x11-ssh-offset[::1]:56472users:(("sshd",pid=37674,fd=11)) skmem:(r0,rb6291456,t0,tb2626560,f0,w0,o0,bl0,d11) ts sack cubic wscale:7,7 rto:222 rtt:21.07/21.032 ato:40 mss:65464 rcvmss:25784 advmss:65464 cwnd:3 ssthresh:2 bytes_acked:2618904 bytes_received:1247927456 segs_out:68092 segs_in:110429 send 74.6Mbps lastsnd:2470 lastrcv:2476 lastack:2430 pacing_rate 149.1Mbps retrans:0/19 rcv_rtt:1229.38 rcv_space:1463216

使用 Memcheck 分析内存使用量
Memcheck 是默认的 valgrind 工具。它检测并报告大量难以检测和诊断到的内存错误,例如:
1) 不应发生的内存访问
2) 使用未定义或未初始化的值
3) 不正确的释放堆内存
4) 指示字重叠
5) 内存泄露
> > 使用memcheck分析内存使用
[root@inf-c7-n1 media]# valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all echo hello ==7637== Memcheck, a memory error detector ==7637== Copyright (C) 2002-2017, and GNU GPL\'d, by Julian Seward et al. ==7637== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==7637== Command: echo hello ==7637== hello ==7637== ==7637== HEAP SUMMARY: ==7637==in use at exit: 0 bytes in 0 blocks ==7637==total heap usage: 30 allocs, 30 frees, 3,681 bytes allocated ==7637== ==7637== All heap blocks were freed -- no leaks are possible ==7637== ==7637== For lists of detected and suppressed errors, rerun with: -s ==7637== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

> > 使用cachegrind分析缓存
[root@inf-c7-n1 ~]# valgrind --tool=cachegrind echo hoo ==25512== Cachegrind, a cache and branch-prediction profiler ==25512== Copyright (C) 2002-2017, and GNU GPL\'d, by Nicholas Nethercote et al. ==25512== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==25512== Command: echo hoo ==25512== hoo ==25512== ==25512== Irefs:202,301 ==25512== I1misses:1,036 ==25512== LLi misses:1,029 ==25512== I1miss rate:0.51% ==25512== LLi miss rate:0.51% ==25512== ==25512== Drefs:70,674(51,869 rd+ 18,805 wr) ==25512== D1misses:3,312( 2,657 rd+655 wr) ==25512== LLd misses:2,677( 2,068 rd+609 wr) ==25512== D1miss rate:4.7% (5.1%+3.5%) ==25512== LLd miss rate:3.8% (4.0%+3.2%) ==25512== ==25512== LL refs:4,348( 3,693 rd+655 wr) ==25512== LL misses:3,706( 3,097 rd+609 wr) ==25512== LL miss rate:1.4% (1.2%+3.2%)

> > 使用cg_annotate查看分析结果
[root@inf-c7-n1 ~]# cg_annotate cachegrind.out.25512 -------------------------------------------------------------------------------- I1 cache:32768 B, 64 B, 8-way associative D1 cache:32768 B, 64 B, 8-way associative LL cache:2097152 B, 64 B, 8-way associative Command:echo hoo Data file:cachegrind.out.25512 Events recorded:Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Events shown:Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Thresholds:0.1 100 100 100 100 100 100 100 100 Include dirs: User annotated: Auto-annotation:off-------------------------------------------------------------------------------- IrI1mrILmrDrD1mrDLmrDwD1mw DLmw -------------------------------------------------------------------------------- 202,301 1,036 1,029 51,869 2,657 2,068 18,805655609PROGRAM TOTALS-------------------------------------------------------------------------------- IrI1mr ILmr DrD1mrDLmr DwD1mw DLmwfile:function -------------------------------------------------------------------------------- 56,5251212 13,788 1,0348591630???:_dl_addr 27,86214149,106215138 4,363129???:do_lookup_x 21,80011114,41611597 2,623105???:_dl_lookup_symbol_x 19,50147475,298696643 2,296254243???:_dl_relocate_object 14,102224,2434525000???:strcmp 6,350442,15413027900???:getenv 5,700552,362542068064???:check_match.9525 5,655661,08465624904242???:_nl_intern_locale_data 4,3432020560326752221???:_int_malloc 2,81117174581310000???:__GI_strcmp 2,130431300 2,0683333???:memset 1,967225095029265???:_dl_name_match_p 1,733464638019191832525???:_dl_map_object_from_fd 1,3544417775000???:__GI_strlen 1,3481414447651821414???:_dl_check_map_versions 1,26744366309200???:malloc 1,16966438441110400???:_dl_fixup 1,14538382481112055???:_dl_map_object_deps 1,137212127711525762???:_nl_load_locale_from_archive 1,080881566125200???:_nl_find_locale 1,049747421527201351616???:dl_main 1,037141425813137644???:bcmp 904221640011811???:bsearch

> > 使用massif查看程序使用堆栈
[root@inf-c7-n1 ~]# valgrind --tool=massif echo hello ==25380== Massif, a heap profiler ==25380== Copyright (C) 2003-2017, and GNU GPL\'d, by Nicholas Nethercote ==25380== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==25380== Command: echo hello ==25380== hello ==25380== [root@inf-c7-n1 ~]# ls anaconda-ks.cfgmassif.out.25380MemoryLeakMemoryLeak.cpptest

> > 使用ms_print查看分析结果
[root@inf-c7-n1 ~]# ms_print massif.out.25380 -------------------------------------------------------------------------------- Command:echo hello Massif arguments:(none) ms_print arguments: massif.out.25380 --------------------------------------------------------------------------------KB 3.961^@@@@@@@# |:::@# |::@::::@# |::@::::@# |::@::::@# |::@::::@# |@:@::::@# |:@:@::::@# |:@:@::::@# |:@:@::::@# |::@:@::::@# |::@:@::::@# |::@:@::::@# |::@:@::::@# |::@:@::::@# |::@:@::::@# |:::@:@::::@# |:::@:@::::@# |:::@:@::::@# |:::@:@::::@# 0 +-----------------------------------------------------------------------> ki 0153.1Number of snapshots: 63 Detailed snapshots: [2, 12, 22, 32, 33 (peak), 43, 53]-------------------------------------------------------------------------------- ntime(i)total(B)useful-heap(B) extra-heap(B)stacks(B) -------------------------------------------------------------------------------- 000000 1118,412245190 2118,680245190 20.83% (5B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. -> 20.83% (5B) 0x4E60E04: _nl_normalize_codeset (in /usr/lib64/libc-2.17.so) -> 20.83% (5B) 0x4E5B15E: _nl_load_locale_from_archive (in /usr/lib64/libc-2.17.so) -> 20.83% (5B) 0x4E5A35D: _nl_find_locale (in /usr/lib64/libc-2.17.so) -> 20.83% (5B) 0x4E59CC2: setlocale (in /usr/lib64/libc-2.17.so) -> 20.83% (5B) 0x401428: ??? (in /usr/bin/echo) -> 20.83% (5B) 0x4E4F554: (below main) (in /usr/lib64/libc-2.17.so)-------------------------------------------------------------------------------- ntime(i)total(B)useful-heap(B) extra-heap(B)stacks(B) -------------------------------------------------------------------------------- 3118,6800000 4119,175136120160 5119,234160132280 6119,348952908440 7120,8121,0721,020520 8121,0162,0401,972680 9122,8702,2722,188840 10123,2692,7122,620920 11124,0852,8322,7241080 12124,2732,9362,8121240 95.78% (2,812B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. -> 91.28% (2,680B) 0x4E5A9BF: _nl_intern_locale_data (in /usr/lib64/libc-2.17.so) | -> 91.28% (2,680B) 0x4E5B0A5: _nl_load_locale_from_archive (in /usr/lib64/libc-2.17.so) |-> 91.28% (2,680B) 0x4E5A35D: _nl_find_locale (in /usr/lib64/libc-2.17.so) |-> 91.28% (2,680B) 0x4E59CC2: setlocale (in /usr/lib64/libc-2.17.so) |-> 91.28% (2,680B) 0x401428: ??? (in /usr/bin/echo) |-> 91.28% (2,680B) 0x4E4F554: (below main) (in /usr/lib64/libc-2.17.so) | -> 04.09% (120B) 0x4E5B025: _nl_load_locale_from_archive (in /usr/lib64/libc-2.17.so) | -> 04.09% (120B) 0x4E5A35D: _nl_find_locale (in /usr/lib64/libc-2.17.so) |-> 04.09% (120B) 0x4E59CC2: setlocale (in /usr/lib64/libc-2.17.so) |-> 04.09% (120B) 0x401428: ??? (in /usr/bin/echo) |-> 04.09% (120B) 0x4E4F554: (below main) (in /usr/lib64/libc-2.17.so) | ......

内存优化配置 配置HugeTLB Huge Page
> > 查看当前hugepage大小,默认2MB,配置大页数量
[root@inf-c7-n1 ~]# cat /proc/sys/vm/nr_hugepages 0 [root@inf-c7-n1 ~]# cat /proc/meminfo |grep -i hugepage AnonHugePages:8192 kB HugePages_Total:0 HugePages_Free:0 HugePages_Rsvd:0 HugePages_Surp:0 Hugepagesize:2048 kB [root@inf-c7-n1 sysctl.d]# sysctl -p 100-memctl.conf vm.nr_hugepages = 10 [root@inf-c7-n1 sysctl.d]# cat /proc/meminfo |grep -i hugepage AnonHugePages:8192 kB HugePages_Total:10 HugePages_Free:10 HugePages_Rsvd:0 HugePages_Surp:0 Hugepagesize:2048 kB

> > 在内核启动参数中配置Hugepagesize
[root@inf-c7-n1 vm]# vim /etc/default/grub [root@inf-c7-n1 vm]# cat /etc/default/grub GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR="$(sed \'s, release .*$,,g\' /etc/system-release)" GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=true GRUB_TERMINAL_OUTPUT="console" GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=c01/root rd.lvm.lv=c01/swap rhgb quiet default_hugepagesz=1G hugepagesz=1G" GRUB_DISABLE_RECOVERY="true" [root@inf-c7-n1 vm]# grub2-mkconfig -o /boot/grub2/grub.cfg Generating grub configuration file ... Found linux image: /boot/vmlinuz-3.10.0-862.el7.x86_64 Found initrd image: /boot/initramfs-3.10.0-862.el7.x86_64.img Found linux image: /boot/vmlinuz-0-rescue-6fde1470ec6d473c8db4edb9e122c965 Found initrd image: /boot/initramfs-0-rescue-6fde1470ec6d473c8db4edb9e122c965.img done [root@inf-c7-n1 vm]# [root@inf-c7-n1 vm]# [root@inf-c7-n1 vm]# reboot [root@inf-c7-n1 ~]# cat /proc/meminfo |grep -i hugepage AnonHugePages:8192 kB HugePages_Total:10 HugePages_Free:10 HugePages_Rsvd:0 HugePages_Surp:0 Hugepagesize:1048576 kB[root@inf-c7-n1 ~]# numastat -cm |egrep \'Node|Huge\' Node 0 Total AnonHugePages88 HugePages_Total10240 10240 HugePages_Free10240 10240 HugePages_Surp00

无numa结构按以上的配置即可,如下有numa结构的还需要配置脚本,开机服务来判断设定;
[root@localhost ~]# numastat -cm |egrep \'Node|Huge\' Node 0 Node 1 Node 2 Node 3Total AnonHugePages16380875257261261243470 HugePages_Total00000 HugePages_Free00000 HugePages_Surp00000

配置Transparent Hug Page
> > 查看透明大页默认状态
[root@inf-c7-n1 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled [always] madvise never

always:全局开启
madvise:局部程序开启
never:禁用透明大页
> > 查看透明大页内存整理
[root@inf-c7-n1 ~]# cat /sys/kernel/mm/transparent_hugepage/defrag [always] madvise never

内存参数调优
路径:/proc/sys/vm
dirty_ratio:
触发pdflush将内存数据写入磁盘的阀值,默认20%;

dirty_bytes:
触发一个写入进程开始回写的脏存储器量,默认值为0;

?dirty_background_ratio:
当脏页达到系统内存的10%时,强制回收写入磁盘,默认值10%;

dirty_background_bytes:
触发pdflush后台回写的脏存储器量,默认值为0;

dirty_expire_centisecs:
使用pdflush的脏存储器最小时间,默认值为3000;

dirty_writeback_centisecs:
pdflush活跃时间间隔(0为停用),默认值为500;

?overcommit_memory
是否接受或拒绝大内存请求,默认值0;0超分;1不超分,2超分但不超过?overcommit_ratio阀值;

?overcommit_ratio
内存超分阀值,默认50%;

?max_map_count
一个进程可使用的最大内存映射,默认值65530;

min_free_kbytes
预留内存空间大小,注意,这个参数不要随便设置,如果值太小,会影响系统的内存回收,可能导致系统hang住,或者触发oom-kill进程,如果太大(达到系统内存的5%-10%),容易导致内存溢出,或系统花费太长时间来回收内存。

?oom_adj
当系统中panic_on_oom参数为0时,系统内存资源使用紧张时,oom_killer触发kill进程开始按照oom_score值的大小杀死进程(值越小越不容易被杀死)。Oom_adj的设置值会影响进程的oom_score,当值为-17禁用oom_killer杀死此进程,其他设置值范围为-16~15。

Swappiness
值的范围0~100,rhel7默认值30,控制系统使用匿名内存和页面内存的倾向,
值大:提高文件系统性能,同时将不太活跃的进程从内存中置换出来;
值小:避免进程从内存中置换出去,以牺牲I/O性能为代价来降低延迟;

Linux的进程使用的内存分为2种:
1) file-backed pages(有文件背景的页面,比如代码段、比如read/write方法读写的文件、比如mmap读写的文件,它们有对应的硬盘文件,因此如果要交换,可以直接和硬盘对应的文件进行交换;比如读取一个文件,没有关闭,也没有修改,交换时,就可以将这个文件直接放回硬盘,代码处理其实就是删除这部分内容,只保留一个索引,让系统知道这个文件还处于打开状态,只是它的内容不在内存,还在硬盘上),此部分页面叫做page cache;
2) anonymous pages(匿名页,如stack,heap,CoW后的数据段等;他们没有对应的硬盘文件,因此如果要交换,只能交换到swap分区),此部分页面,如果系统内存不充分,可以被swap到swapfile或者硬盘的swap分区。
因此,Linux在进行内存回收(memory reclaim)的时候,实际上可以从1类和2类这两种页面里面进行回收,而swappiness值就决定了回收这2类页面的优先级。swappiness越大,越倾向于回收匿名页;swappiness越小,越倾向于回收file-backed的页面。当然,它们的回收方法都是一样的LRU算法。(缓存淘汰算法--LRU算法LRULeast recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是"如果数据最近被访问过,那么将来被访问的几率也更高"新数据插入到链表头部;每当缓存命中(即缓存数据被访问),则将数据移到链表头部;当链表满的时候,将链表尾部的数据丢弃。)

vm.swappiness = 0
仅在内存不足的情况下--当剩余空闲内存低于vm.min_free_kbytes limit时,使用交换空间。

vm.swappiness = 1
内核版本3.5及以上、Red Hat内核版本2.6.32-303及以上,进行最少量的交换,而不禁用交换。

vm.swappiness = 10
当系统存在足够内存时,推荐设置为该值以提高性能。

如果swappiness=0,除非系统的内存过小(nr_free + nr_filebacked < high watermark)这种恶劣情况发生,都只是考虑交换file-backed的pages,就不会考虑交换匿名页了。
于是,现在的swappiness如果等于0的话,意味着哪怕匿名页占据的内存很大,哪怕swap分区还有很多的剩余空间,除非恶劣情况发生,都不会交换匿名页,因此这可能造成更大的OOM(Out Of Memory)压力。

红帽官方说明:
Warning
Setting swappiness==0 will very aggressively avoids swapping out, which increase the risk of OOM killing under strong memory and I/O pressure.

文件系统参数
路径:/proc/sys/fs
?aio-max-nr
定义在异步输入/输出环境中允许的最大事件数量,默认值65536.

?file-max
定义整个系统中最大的文件句柄,rhel7中默认最大值8192【或(mempages * (PAGE_SIZE / 1024)) / 10】.增加参数值可以解决由于缺少可用的文件句柄而引起的错误。

内核参数
路径:/proc/sys/kernel
?msgmax
定义一个消息队列中单个消息最大值(KB),默认值65535,值不能超过队列大小(msgmnb)。

?msgmnb
定义单个消息队列最大值(KB),默认65535.

?msgmni
定义信息队列标识符的最大数量(以及队列的最大数量)。在 64 位架构的系统中,默认值为 1985。

?shmall
定义系统中可使用的共享的页面数,在64位系统中,单个页面为4096bytes。
[root@rhel7 vm]# getconf PAGESIZE
4096

?shmmax
定义页面上内核允许的单个共享内存片段的最大值(bytes)。

?shmmni
定义系统范围内最大的共享内存片段数量。在所有系统中的默认值为4096。

?threads-max
定义系统范围内内核能同时使用的最大线程量。默认值与内核参数max_threads 相同,【或mempages / (8 * THREAD_SIZE / PAGE SIZE )】,最小值为20.
【Linux系统故障定位与优化】



    推荐阅读