记一次无vmcore内存死机问题分析过程

问题现象

客户发现在物理机上跑读写业务时,出现了一次死机现象,kdump服务未抓到vmcore文件。/var/log/messages里没有发现内核panic报错信息,只有call trace的警告信息。抓取到的call trace信息总共有三种类型:内存分配失败、rmmod、任务超时。

问题不稳定复现,客户分析是在新读写业务开始调试长加电运行后,大概两周多左右出现了死机问题。业务设备由于诸多原因无法邮寄,也无法提供远程环境。但问题紧急程度很高,要求快速解决。

因没有生成vmcore不好准确分析,于是第一时间提供客户监测系统多种性能的脚本放到后台运行,运行一周左右取出这段时间监测到的数据信息以及系统messages。此时系统虽未死机,但已成功复现了上述三类call trace,下文将对抓取到的日志进行分析

日志分析

内存分配失败日志分析

系统message分析

page allocation failure的call trace输出,以下内核输出的时间戳在15:39:46左右:

kernel: [67442.657502] mount: page allocation failure: order:0, mode:0x440000(GFP_NOWAIT|__GFP_THISNODE), nodemask=(null)
kernel: [67442.658760] mount cpuset=/ mems_allowed=0,2,4,6,8,10,12,14
kernel: [67442.659451] CPU: 31 PID: 872267 Comm: mount Kdump: loaded Tainted: G        W  OE K   4.19.90-25.2.aarch64 #1
kernel: [67442.660681] Hardware name: ... ...
kernel: [67442.661595] Call trace:
kernel: [67442.661910]  dump_backtrace+0x0/0x170
kernel: [67442.662392]  show_stack+0x24/0x30
kernel: [67442.662809]  dump_stack+0xa4/0xe8
kernel: [67442.663256]  warn_alloc+0xc4/0x128
kernel: [67442.663664]  __alloc_pages_nodemask+0xcd4/0xd70
... ...
kernel: [67442.673551]  __arm64_sys_mount+0x28/0x38
kernel: [67442.674033]  el0_svc_common+0x78/0x130
kernel: [67442.674505]  el0_svc_handler+0x38/0x78
kernel: [67442.674966]  el0_svc+0x8/0x1b0

本次失败是申请2^0个page时失败,即连续1个页的内存(pagesize为64kB),一般order 0分配失败代表着系统已经没有内存了。

因GFP_NOWAIT代表不可睡眠等待,__GFP_THISNODE代表从指定内存节点中分配并且无回退机制,没有指定zone则默认是ZONE_NORMAL。怀疑可能是当时指定的node节点里zone normal的order 0链表内没有找到空闲且匹配成功的页,故而没有重试直接返回了申请失败。根据日志中call trace前,业务软件的输出表示将任务绑定到了node 0上,猜测可能是node 0上没有空闲页。

由日志信息可见,死机时pid为872267的进程调用__alloc_pages_nodemask直接申请物理内存。由底层堆栈知,这段过程应该是由用户态的应用程序调用mount系统调用,触发el0中断,从而陷入内核。

内核中调用warn_alloc的函数有:__alloc_pages_slowpath、__vmalloc_area_node、__vmalloc_node_range、vmemmap_alloc_block。根据堆栈函数调用流程知,进入的内存分配函数是__alloc_pages_nodemask,在此函数内会通过get_page_from_freelist快速内存分配。快速分配失败以后,会去调用__alloc_pages_slowpath进行慢速内存分配。在__alloc_pages_slowpath里,先会尝试唤醒kswapd进程回收内存,因本次未设置__GFP_KSWAPD_RECLAIM属性,故未走这个流程。之后,重新尝试分配了一次内存,但是仍旧失败了。失败后的流程需要判断当前是否可以进行内存回收操作,若回收后依旧分配失败,则会进入OOM检查流程。因本次未设置__GFP_DIRECT_RECLAIM属性,故直接判断为内存申请失败就调warn_alloc报错返回,没有走内核direct reclaim回收内存的流程,进而也没有触发OOM。

为了详细了解当时的内存状态,进一步分析meminfo输出。

第一段meminfo输出:

kernel: [67442.726710] Node 0 DMA32 free:119232kB min:1664kB low:2560kB high:3456kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:595072kB writepending:0kB present:2031616kB managed:907904kB mlocked:595072kB kernel_stack:0kB pagetables:128kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:1472kB
kernel: [67442.729920] lowmem_reserve[]: 0 1913 1913
kernel: [67442.730433] Node 0 Normal free:124032kB min:58752kB low:90048kB high:121344kB active_anon:1985152kB inactive_anon:13248kB active_file:803840kB inactive_file:7035136kB unevictable:18799680kB writepending:320kB present:31391744kB managed:31353600kB mlocked:18799680kB kernel_stack:17328kB pagetables:14528kB bounce:0kB free_pcp:34112kB local_pcp:128kB free_cma:0kB
kernel: [67442.733879] lowmem_reserve[]: 0 0 0
kernel: [67442.734339] Node 2 Normal free:12869376kB min:62784kB low:96256kB high:129728kB active_anon:1365696kB inactive_anon:29376kB active_file:2222784kB inactive_file:2928960kB unevictable:12462720kB writepending:2240kB present:33554432kB managed:33516416kB mlocked:12462720kB kernel_stack:18512kB pagetables:19008kB bounce:0kB free_pcp:66944kB local_pcp:64kB free_cma:0kB
kernel: [67442.737912] lowmem_reserve[]: 0 0 0
kernel: [67442.738457] Node 4 Normal free:1002240kB min:62784kB low:96256kB high:129728kB active_anon:1204288kB inactive_anon:9600kB active_file:283264kB inactive_file:4446656kB unevictable:25140416kB writepending:2240kB present:33554432kB managed:33516480kB mlocked:25140416kB kernel_stack:5776kB pagetables:15616kB bounce:0kB free_pcp:65856kB local_pcp:1024kB free_cma:0kB
kernel: [67442.741901] lowmem_reserve[]: 0 0 0
kernel: [67442.742368] Node 6 Normal free:15073536kB min:62784kB low:96256kB high:129728kB active_anon:475520kB inactive_anon:20096kB active_file:153216kB inactive_file:1919424kB unevictable:15502400kB writepending:1024kB present:33554432kB managed:33516480kB mlocked:15502464kB kernel_stack:10272kB pagetables:8448kB bounce:0kB free_pcp:64896kB local_pcp:1024kB free_cma:0kB
kernel: [67442.745760] lowmem_reserve[]: 0 0 0
kernel: [67442.746199] Node 8 Normal free:3885312kB min:62656kB low:96064kB high:129472kB active_anon:1126464kB inactive_anon:1024kB active_file:528768kB inactive_file:2995776kB unevictable:23091456kB writepending:768kB present:33488896kB managed:33450816kB mlocked:23091456kB kernel_stack:11856kB pagetables:11840kB bounce:0kB free_pcp:51456kB local_pcp:832kB free_cma:0kB
kernel: [67442.749695] lowmem_reserve[]: 0 0 0
kernel: [67442.750213] Node 10 Normal free:13484864kB min:62784kB low:96256kB high:129728kB active_anon:2751808kB inactive_anon:448kB active_file:714112kB inactive_file:3798400kB unevictable:12332672kB writepending:1088kB present:33554432kB managed:33516416kB mlocked:12332672kB kernel_stack:7648kB pagetables:4864kB bounce:0kB free_pcp:49216kB local_pcp:832kB free_cma:0kB
kernel: [67442.753654] lowmem_reserve[]: 0 0 0
kernel: [67442.754118] Node 12 Normal free:19964416kB min:62720kB low:96192kB high:129664kB active_anon:333568kB inactive_anon:2048kB active_file:7296kB inactive_file:558144kB unevictable:12332480kB writepending:64kB present:33554432kB managed:33492928kB mlocked:12332480kB kernel_stack:2592kB pagetables:768kB bounce:0kB free_pcp:33728kB local_pcp:896kB free_cma:0kB
kernel: [67442.757542] lowmem_reserve[]: 0 0 0
kernel: [67442.758019] Node 14 Normal free:20600384kB min:62720kB low:96192kB high:129664kB active_anon:356416kB inactive_anon:640kB active_file:12416kB inactive_file:7232kB unevictable:12332480kB writepending:0kB present:33554432kB managed:33474368kB mlocked:12332480kB kernel_stack:2256kB pagetables:1472kB bounce:0kB free_pcp:27136kB local_pcp:896kB free_cma:0kB
kernel: [67442.761357] lowmem_reserve[]: 0 0 0

除了Node 0 DMA32,其他节点均未留有CMA预留区域。所有Node Normal区域的free值均高于low、min水位线,说明当前系统仍有空闲内存。但一般情况下min以下的内存是不会被分配的,故各节点Normal区域可分配内存大小为,Node 0:65280 kB,Node 2:12806592 kB,Node 4:939456 kB,Node 6:15010752 kB,Node 8:3822656 kB,Node 10:13422080 kB,Node 12:19901696 kB,Node 14:20537664 kB,各节点内存充足。分配失败有可能是order 0链表上没有空闲页导致的。

第二段meminfo输出:

kernel: [67442.761808] Node 0 DMA32: 27*64kB (UMC) 4*128kB (UMC) 3*256kB (MC) 1*512kB (M) 1*1024kB (M) 0*2048kB 0*4096kB 0*8192kB 1*16384kB (M) 1*32768kB (M) 1*65536kB (M) 0*131072kB 0*262144kB 0*524288kB = 119232kB
kernel: [67442.763860] Node 0 Normal: 867*64kB (UME) 221*128kB (ME) 61*256kB (UME) 18*512kB (ME) 8*1024kB (UME) 2*2048kB (M) 0*4096kB 0*8192kB 0*16384kB 0*32768kB 0*65536kB 0*131072kB 0*262144kB 0*524288kB = 120896kB
kernel: [67442.765863] Node 2 Normal: 732*64kB (UME) 1020*128kB (UME) 532*256kB (UME) 99*512kB (UME) 101*1024kB (ME) 91*2048kB (UME) 59*4096kB (UM) 43*8192kB (UM) 21*16384kB (UM) 10*32768kB (UME) 5*65536kB (UME) 3*131072kB (UME) 1*262144kB (U) 19*524288kB (UM) = 12864256kB
kernel: [67442.768538] Node 4 Normal: 328*64kB (UME) 562*128kB (UME) 482*256kB (UM) 174*512kB (UM) 60*1024kB (UM) 56*2048kB (UM) 35*4096kB (UM) 24*8192kB (UM) 8*16384kB (UM) 2*32768kB (UM) 0*65536kB 0*131072kB 0*262144kB 0*524288kB = 1018112kB
kernel: [67442.770803] Node 6 Normal: 1168*64kB (UME) 903*128kB (UME) 323*256kB (UME) 186*512kB (UME) 93*1024kB (UM) 72*2048kB (UME) 40*4096kB (UM) 29*8192kB (UME) 18*16384kB (ME) 14*32768kB (ME) 9*65536kB (UME) 3*131072kB (UM) 1*262144kB (E) 23*524288kB (M) = 15069824kB
kernel: [67442.773294] Node 8 Normal: 566*64kB (UME) 276*128kB (UME) 140*256kB (UME) 142*512kB (UM) 137*1024kB (UME) 40*2048kB (UM) 34*4096kB (UME) 24*8192kB (UME) 14*16384kB (UM) 12*32768kB (UME) 9*65536kB (UME) 1*131072kB (M) 5*262144kB (UME) 1*524288kB (M) = 3916672kB
kernel: [67442.775762] Node 10 Normal: 37*64kB (UME) 77*128kB (ME) 14*256kB (ME) 45*512kB (UME) 114*1024kB (M) 58*2048kB (UME) 61*4096kB (UME) 46*8192kB (UME) 26*16384kB (UM) 10*32768kB (ME) 4*65536kB (UME) 2*131072kB (UM) 1*262144kB (E) 21*524288kB (M) = 13451200kB
kernel: [67442.778295] Node 12 Normal: 297*64kB (UME) 190*128kB (UME) 97*256kB (UME) 52*512kB (UM) 57*1024kB (UM) 53*2048kB (UME) 35*4096kB (M) 16*8192kB (ME) 14*16384kB (UM) 8*32768kB (UM) 9*65536kB (UME) 4*131072kB (UME) 2*262144kB (ME) 33*524288kB (M) = 19967552kB
kernel: [67442.780749] Node 14 Normal: 165*64kB (UME) 134*128kB (UME) 53*256kB (UME) 37*512kB (UME) 48*1024kB (UM) 33*2048kB (UME) 29*4096kB (UM) 15*8192kB (UME) 8*16384kB (M) 6*32768kB (ME) 5*65536kB (UME) 3*131072kB (ME) 3*262144kB (UME) 35*524288kB (M) = 20603712kB

上图输出了每个Node的区域内order链表情况,可知所有normal区域的order 0链表均有空余内存,迁移类型为unmovable、movable、reclaimable,但是仍然分配失败。怀疑是内存碎片导致的order 0链表里没有连续的64kB的页。

Call trace发生前后半小时内,系统各类监测值分析

  1. free
    call trace发生前,可分配的物理内存数量持续减少,buff/cache占总内存的峰值大约为11%。Call trace发生后,可分配的物理内存数量增多,buff/cache占用极少的比例。整个过程里,free占比未低于30%。说明物理内存充足。
    在这里插入图片描述
  2. Vmstat
    未使用swap空间,虚拟内存容量充足。Call trace发生前,根据cache、buff、bi、bo值的变化,可知有大量读写任务,系统将数据放入缓冲区的速度大于将数据取出交给设备IO的速度,导致buff持续增多,可能导致系统内存不足。

在这里插入图片描述

根据procs r知在运行队列中等待的进程数持续增长,但同时cpu id显示cpu长期空闲,结合设备读写数值,猜测大多数等待的进程是在等待IO资源,cpu算力充足。Call trace发生半小时后,buff/cache内存占有率大幅度下降,应该是内存不足触发系统将这部分内存回收了,而缓冲区大小的减少导致此时bi、bo、r数值飘高。

  1. Top
    call trace发生后半小时,进程oStor对cpu的占有率仍然非常高,load average数值大幅度增长,cpu idle比例也降了10%。平台cpu为两颗S2500/64,load average占cpu核数的17%左右,说明cpu资源充足。

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/88de7a6fb52c44fcac66929712975af5.png]

  1. Iostat
    cpu一直较为空闲,整个过程里进行了大量的磁盘IO操作,没有丢块。
    在这里插入图片描述

总结

根据上述分析可知,call trace因可分配空闲内存不足而触发:

  • call trace发生前后半小时左右,系统持续执行大量的读写任务,由于磁盘读写速度慢于缓冲区缓存的速度,导致缓冲区占用的内存持续增长,系统可分配的空闲内存比例减少。
  • 系统显示有大量空闲内存,但不可分配给进程,猜测是内存碎片导致空闲内存均不连续,进而无法分配。
  • 内存回收机制可缓解内存碎片、释放缓冲区,从而增加可分配空闲内存。当水位线低于low时,系统会唤醒kswapd进程回收内存,若水位线低于min时,系统会通过内核触发direct reclaim直接回收内存。通过上述数据,知call trace发生后,系统成功地将buff/cache的大部分内存回收了,系统回收机制工作正常。

优化思路

避免此类call trace发生有两个方向:增大内存容量,缓解内存碎片。

解决内存碎片可以尝试及时回收内存,可以通过将/proc/sys/vm/zone_reclaim_mode设置为1,当前环境下zone_reclaim_mode值为0。zone_reclaim_mode对应的是内核代码里node_reclaim_mode的值。在分配函数get_page_from_freelist内,会遍历zone链表,若当前zone内存不够,会判断node_reclaim_mode值是否为0,若为0则继续遍历其他zone,若为1则直接对当前zone进行内存回收,提高了内存回收的概率。

rmmod引发的call trace

系统message分析

rmmod的call trace输出:

kernel: [63375.659792] ------------[ cut here ]------------
kernel: [63375.660345] WARNING: CPU: 44 PID: 41590 at kernel/jump_label.c:638 jump_label_del_module+0xdc/0x1d0
kernel: [63375.661339] Modules linked in: disksense(OEK-) ... ...
kernel: [63375.669409] CPU: 44 PID: 41590 Comm: rmmod Kdump: loaded Tainted: G           OE K   4.19.90-25.2.aarch64 #1
kernel: [63375.670712] Hardware name: ... ...
kernel: [63375.671697] pstate: 40000005 (nZcv daif -PAN -UAO)
kernel: [63375.672272] pc : jump_label_del_module+0xdc/0x1d0
kernel: [63375.672846] lr : jump_label_del_module+0xdc/0x1d0
kernel: [63375.673410] sp : ffff81785dc83cd0
kernel: [63375.673830] x29: ffff81785dc83cd0 x28: ffff81785d097400
kernel: [63375.674467] x27: 0000000000000000 x26: 0000000000000000
kernel: [63375.675094] x25: 0000000056000000 x24: ffff24e3a5c19a10
kernel: [63375.675828] x23: ffff24e3a54c6930 x22: ffff24e378e700f0
kernel: [63375.676452] x21: ffff24e378e70000 x20: ffff24e3a5da08f0
kernel: [63375.677040] x19: ffff24e378e72540 x18: 0000000000000001
kernel: [63375.677635] x17: 0000000000000001 x16: 0000000000000007
kernel: [63375.678257] x15: ffffffffffffffff x14: ffff24e425e2bf2f
kernel: [63375.678874] x13: ffff24e3a5e2bf42 x12: ffff24e3a5bfddc0
kernel: [63375.679494] x11: 0000000005f5e0ff x10: ffff24e3a5bd5968
kernel: [63375.680116] x9 : ffff24e3a57c0018 x8 : ffff24e3a4b65998
kernel: [63375.680756] x7 : 7563205b2d2d2d2d x6 : 00000000000012b4
kernel: [63375.681390] x5 : 0000000000000001 x4 : ffff83dc3ef813a0
kernel: [63375.682039] x3 : ffff83dc3ef813a0 x2 : 0000000000000007
kernel: [63375.682672] x1 : 0000000000000006 x0 : 0000000000000024
kernel: [63375.683277] Call trace:
kernel: [63375.683583]  jump_label_del_module+0xdc/0x1d0
kernel: [63375.684106]  jump_label_module_notify+0x78/0x358
kernel: [63375.684643]  notifier_call_chain+0x5c/0xa0
kernel: [63375.685084]  blocking_notifier_call_chain+0x68/0xc0
kernel: [63375.685722]  __arm64_sys_delete_module+0x224/0x2c0
kernel: [63375.686249]  el0_svc_common+0x78/0x130
kernel: [63375.686676]  el0_svc_handler+0x38/0x78
kernel: [63375.687090]  el0_svc+0x8/0x1b0
kernel: [63375.687448] ---[ end trace d2eb9998b4fe61d8 ]---

这个call trace是由rmmod指令引发的,本次没有像page allocation failure的call trace一样打出meminfo,可用的信息不多。查看log里这次call trace发生前的上文内容,会发现内核模块disksense在工作。从上文disksense的输出看,所有操作均成功完成了,没有失败报错。因"disksense: remove disk[sda]"操作之后才发生call trace,猜测可能是模块disksense执行了rmmod操作,从而触发了本次call trace。

代码分析

代码分析:
根据输出中的“kernel/jump_label.c:638 jump_label_del_module”,去查看相应代码。内核中调用jump_label_del_module的只有以下两处:

static int
jump_label_module_notify(struct notifier_block *self, unsigned long val,void *data)
{... ...switch (val) {case MODULE_STATE_COMING:ret = jump_label_add_module(mod);if (ret) {WARN(1, "Failed to allocate memory: jump_label may not work properly.\n");jump_label_del_module(mod);//第一处}break;case MODULE_STATE_GOING:jump_label_del_module(mod);//第二处break;... ...}
... ...
}

因call trace之前没有“Failed to allocate memory”输出,知本次call trace走的是MODULE_STATE_GOING分支。根据内核中的定义,得知MODULE_STATE_GOING代表模块当前正在被卸载,符合前面对call trace上文的分析。

查看内核代码kernel/jump_label.c里638行的jump_label_del_module,发现是由于内存不足导致的warn_on调用。

jump_label_del_module代码:

637			/* No memory during module load */
638			if (WARN_ON(!jlm))
639				continue;

总结

经上分析,本类call trace同样是可分配内存不足导致的。当系统内存回收速度低于申请内存的速度,就有可能触发此类call trace。

优化思路

因与page allocation failure的call trace触发原因相同,解决方法也同上,调整/proc/sys/vm/zone_reclaim_mode的值为1。

任务超时引发的call trace

系统message分析

超时call trace:

kernel: [64395.445978] INFO: task sync:63328 blocked for more than 120 seconds.
kernel: [64395.446778]       Tainted: G        W  OE K   4.19.90-25.2.aarch64 #1
kernel: [64395.447711] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kernel: [64395.448565] sync            D    0 63328  63278 0x00000200
kernel: [64395.449189] Call trace:
kernel: [64395.449519]  __switch_to+0xe8/0x150
kernel: [64395.449937]  __schedule+0x298/0x958
kernel: [64395.450352]  schedule+0x2c/0x88
kernel: [64395.450735]  wb_wait_for_completion+0x5c/0x90
kernel: [64395.451235]  sync_inodes_sb+0xb0/0x2b8
kernel: [64395.451687]  sync_inodes_one_sb+0x28/0x38
kernel: [64395.452183]  iterate_supers+0xb0/0x178
kernel: [64395.452651]  ksys_sync+0x3c/0xa0
kernel: [64395.453084]  __arm64_sys_sync+0x14/0x20
kernel: [64395.453591]  el0_svc_common+0x78/0x130
kernel: [64395.454056]  el0_svc_handler+0x38/0x78
kernel: [64395.454529]  el0_svc+0x8/0x1b0
systemd[1]: session-244.scope: Succeeded.
kernel: [64402.830405] kauditd_printk_skb: 18 callbacks suppressed

“INFO:task … blocked for more than 120 seconds”是内核hung task机制的警告,内核进程khungtaskd会监控状态为TASK_UNINTERRUPTIBLE的进程是否在120秒内转变状态,如果超时则会输出此警告信息。查看堆栈发现sync_inodes_sb是对块的脏节点同步回写的操作函数,说明call trace发生时系统正处于脏页回写的状态。因等待磁盘IO,sync进程的状态会切换为TASK_UNINTERRUPTIBLE,猜测可能是IO子系统将缓存数据写入磁盘的速度不够快,未能在120秒内完成,从而触发了本次告警信息。

代码分析

hung_task_timeout_secs对应到内核的代码中是sysctl_hung_task_timeout_secs,值默认是120。在内核代码watchdog函数里(watchdog是khungtaskd进程的主函数),每隔sysctl_hung_task_timeout_secs秒就调用check_hung_uninterruptible_tasks检查所有进程。check_hung_uninterruptible_tasks会遍历所有进程,若当前进程状态为TASK_UNINTERRUPTIBLE,则调函数check_hung_task判断是否该进程已经sysctl_hung_task_timeout_secs秒未被唤醒过,若已超时则输出“INFO:task … blocked for more than 120 seconds”的告警信息。

现象分析

当系统脏页同步回写操作耗时较长,导致因IO操作被阻塞的进程超时的情况下,会触发本类call trace。耗时长可能与磁盘IO速度有关,还可能和当时系统内待同步的数据量有关,缓冲区越大,意味着同步所需的时间越长。由于系统上持续运行着应用程序跑读写业务,怀疑当时系统缓存脏页较多,加上磁盘IO积压的任务较多,导致回写操作超过了120秒。

当缓存脏页所占内存的比例低于阈值dirty_background_ratio时,linux系统会唤醒flush等进程在后台执行异步的缓存回写操作,将一定数量的脏页写入磁盘里,此时应用程序仍可以执行磁盘读写操作。当缓存脏页所占内存的比例低于阈值dirty_ratio时,linux系统会触发flush进程进行同步的回写操作,此时应用程序的磁盘读写操作会被阻塞。

怀疑本次call trace是因应用程序发起大量的IO申请,导致脏页所占内存比例降到第一个阈值dirty_background_ratio,而后台异步脏页回写速度没有应用程序占用缓存的速度快,导致脏页所占内存比例持续降到了第二个阈值dirty_ratio。如果此种情况得不到缓解,大量进程将被阻塞,可能导致系统卡顿;如果是核心内核进程被阻塞,可能会导致系统卡死。

优化思路

缓解此类call trace,可以通过调整dirty_background_ratio和dirty_ratio的值来实现。默认情况下,dirty_background_ratio = 10,dirty_ratio = 40,这代表着linux系统最多分配40%的内存空间用于缓存,当缓存占10%内存时会开启脏页回写流程回收一部分脏页。因系统内存较大,大约256GB,linux分配的缓冲区大小也很大,导致将缓冲区数据向磁盘回写所需的时间较长,从而触发超时call trace的概率更高。此情况下,根据调优经验,较合适的数值为:dirty_background_ratio = 5,dirty_ratio = 10。降低两个比例的阈值,能使系统及时回写脏页,在磁盘IO速度没有优势的情况下,降低每次待回写的缓存量,从而减少回写操作的耗时,达到减少阻塞进程超时的目的。

解决方案及验证效果

经过上述分析,可知前两类call trace是系统可分配空闲内存不足导致的两种现象,而第三类call trace是系统分配的缓冲区大小过大导致脏页回写超时现象。综合评估,提出以下两个解决措施。

措施1:解决内存碎片,设置 /proc/sys/vm/zone_reclaim_mode为1。

措施2:调整系统脏页回写,设置 /proc/sys/vm/dirty_ratio为10,设置/proc/sys/vm/dirty_background_ratio为5。

设置方法:
在/etc/sysctl.conf文件末尾加上下图三行参数,然后执行sysctl -p更新到内核。

在这里插入图片描述
设置如上三个参数后,客户现场在测试机上持续跑业务程序,连测了一个月一直未出现死机,证明措施有效。

zone_reclaim_mode的官方解释

下方出自linux内核Documentation,是关于zone_reclaim_mode的官方解释:
在这里插入图片描述
zone_reclaim_mode可以控制内存回收算法的激进程度,在设置为1后仍不能有效解决可分配内存不够的情况下,还可以改为2、4测试,但是可能会影响系统性能。

PS:内存问题排查技巧

问题发生在两年前,排查记录最近才有空整理出来。当时太菜了。。。。只想到看日志输出

内存不足问题往往没法正常生成vmcore,而日志如果有alloc failed报错的话大概率是内存不足。

如果有调试环境,实际上内存问题最先应排查的是/proc/下的buddyinfo和pagetypeinfo的状态,能很清晰的看出具体是哪个node内存可能有问题 …

如果call trace或者panic的堆栈不完整,比如出现非内核地址例如0x2000…之类的(不是0xfff…开头的)、或者只打印出来两三层(最底层还不是系统调用),那么可以怀疑内存被篡改,开始往非法访问内存方向排查(不排除内存跳bit可能性)。

内存相关问题排查可查询的内核数据:

  • /proc/meminfo:全局内存汇总的统计值
root@sujing-GW-001N1B-FTF:/proc# cat meminfo
MemTotal:        8077916 kB
MemFree:          443352 kB
MemAvailable:    2263828 kB
PageSize:   	      16 kB
Buffers:           60800 kB
Cached:          2198512 kB
SwapCached:           88 kB
Active:          5409368 kB
... ...
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
root@sujing-GW-001N1B-FTF:/proc#
  • /proc/zoneinfo:单独打印每个zone的内存信息
root@sujing-GW-001N1B-FTF:/proc# cat zoneinfo 
Node 0, zone    DMA32per-node statsnr_inactive_anon 244316nr_active_anon 1079548nr_inactive_file 167680nr_active_file 270832... ...nr_written   467399nr_kernel_misc_reclaimable 0pages free     28688min      2648low      3310high     3972spanned  524288... ...pagesetscpu: 0count: 13high:  378batch: 63vm stats threshold: 30cpu: 1count: 2high:  378batch: 63... ...vm stats threshold: 30node_unreclaimable:  0start_pfn:           524288
Node 0, zone   Normalpages free     84432min      8615low      10768high     12921spanned  34078720present  1572864managed  1536799protection: (0, 0, 0)nr_free_pages 84432nr_zone_inactive_anon 174227... ...
  • /proc/buddyinfo:能把每个order链表上的页数都打印出来
root@sujing-GW-001N1B-FTF:/proc# cat buddyinfo 
Node 0, zone    DMA32   2483   3619   1374    711    280     48    101      7      9      8      0 
Node 0, zone   Normal   5959   4727   1319   2405   1361    621    177     58      3      0      0
  • /proc/pagetypeinfo:按不同页块类型,打印相应的数量
root@sujing-GW-001N1B-FTF:/proc# cat pagetypeinfo 
Page block order: 9
Pages per block:  512Free pages count per migrate type at order       0      1      2      3      4      5      6      7      8      9     10 
Node    0, zone    DMA32, type    Unmovable     19     23     25     27     29     18     14      5      4      7      0 
Node    0, zone    DMA32, type      Movable   2675   3702   1544    717    261     29     87      2      4      3      0 
Node    0, zone    DMA32, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type          CMA      1      1      0      1      0      1      0      0      1      0      0 
Node    0, zone    DMA32, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type    Unmovable    413    463    315    150     93     57     26     21      3      2      0 
Node    0, zone   Normal, type      Movable     92    593    572     99    116     16      6      1      0      0      0 
Node    0, zone   Normal, type  Reclaimable    512    566    574   2164   1174    546    148     36      0      0      0 
Node    0, zone   Normal, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type          CMA      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 Number of blocks type     Unmovable      Movable  Reclaimable   HighAtomic          CMA      Isolate 
Node 0, zone    DMA32           18          952            0            0           16            0 
Node 0, zone   Normal          187         2646          239            0            0            0 
root@sujing-GW-001N1B-FTF:/proc#

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/738899.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

7.无重复字符的最长字串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为…

Unity性能优化篇(十一) 动画优化

1.恰当地设置Animator组件的Culling Mode。Always Animate表示如果该动画不可见,也会播放它。Cull Update Transformations表示如果该动画不可见,则不会渲染该动画,但是依然会根据该动画的播放来改变游戏对象的位置、旋转、缩放,这…

2024计算机软考基本介绍、考试时间、考试科目等2024年软考新变化政策 证书的作用

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级…

【考研数学】张宇学习包

张宇的授课侧重于启发学生的综合思维能力。对于基础较好的学生而言,在听完他的课后,解题通常不会构成太大问题,而且可以学到许多解题技巧,其中包括张宇老师创造的易记的“点火公式”。 然而,对于基础较薄弱的学生来说…

无人机手持地面站软件功能详解,无人机手持地面站软件开发人员组成及成本分析

无人机手持地面站软件是专为无人机操控和任务管理设计的移动应用,它通常集成在智能手机、平板电脑或其他便携式设备上,使得用户可以在远离无人机的地方对飞行器进行实时监控与远程控制。 主要功能详解: 1. 飞行控制与姿态显示: …

基于springboot+vue实现乌鲁木齐南山冰雪旅游服务网管理系统项目【项目源码+论文说明】计算机毕业设计

基于springbootvue实现南山冰雪旅游服务网演示 摘要 随着2022年北京冬奥会的成功举办,在冬天进行冰雪运动已经逐渐流行起来,人们慢慢享受到了冰雪活动给大家带来的欢乐,除此之外人们的身体素质也可以得到提升。虽然已经有一部分人可以接受并…

关于yolov8文档的记录,补充一些整理的知识点

2023年由Ultralytics 提供了YOLOv8开源项目。YOLOv8 支持全方位的视觉 AI 任务,包括检测、分割、姿态估计、跟踪和分类。这种多功能性使用户能够在各种应用和领域中利用YOLOv8 的功能。安装yolov8开源项目 pip install githttps://github.com/ultralytics/ultralyti…

微信小程序开发系列(二十四)·wxml语法·列表渲染·wx:for-item 和 wx:for-index

目录 1. 如果需要对默认的变量名和下标进行修改,可以使用wx:for-item 和 wx:for-index 2. 将 wx:for 用在 标签上,以渲染一个包含多个节点的结构块 方法一 方法二 3. 总结 3.1 wx:for-item 和 wx:for-index总结 3.2 总结 1. 如果需要对默…

新品发布:广州大彩科技COF系列2.1寸480*480 IPS 串口屏发布!

一、产品介绍 该产品是一款2.1寸分辨率为 480480的医用级工业组态串口屏,拥有2.1寸IPS液晶屏,分辨率有480480(实际显示为R240内切圆区域),支持电容触摸。采用COF超薄结构工艺设计,用户安装便捷灵活&#x…

力扣hot100:240.搜索二维矩阵II(脑子)

吉大21级算法分析与设计的一道大题,由于每一行都是排好序的直接逐行二分 可以达到:O(mlogn)。但是这里追求更广的思路可以使用其他方法。 矩阵四分: 在矩阵中用中心点比较,如果target大于中心点的值,则由于升序排列&am…

【C++】string类(介绍、常用接口)

🌈个人主页:秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343🔥 系列专栏:http://t.csdnimg.cn/eCa5z 目录 string类的常用接口说明 string类对象的常见构造 ​编辑 string字符串的遍历(迭代器&#xf…

Python网站的搭建和html基础

1.Python网站代码及讲解 一般我们搭建小型的网站就用flask库就行了。 (1)安装flask库 安装完python后,按住windows徽标键和r,弹出“运行”,在里面输入cmd。 回车打开,输入“pip install flask”。 (2&am…

地平线旭日x3派部署yolov5--全流程

地平线旭日x3派部署yolov5--全流程 前言一、深度学习环境安装二、安装docker三、部署3.1、安装工具链镜像3.2、配置天工开物OpenExplorer工具包3.3、创建深度学习虚拟空间,安装依赖:3.4、下载yolov5项目源码并运行3.5、pytorch的pt模型文件转onnx3.6、最…

要先学会 “面向对象编程” 就得学会类和对象(Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. 🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人…

申请选择商家转账到零钱流程怎样的

商家转账到零钱是什么? 【商家转账到零钱】可以说是【企业付款到零钱】的升级版,商家转账到零钱可以为商户提供同时向多个用户微信零钱转账的能力,支持分销返佣、佣金报酬、企业报销、企业补贴、服务款项、采购货款等自动向用户转账的场景。…

如何关闭微软的Edge浏览器右击提示的:“使用copilot重写“的提示?

最近在使用微软的edge浏览器写文档的时候,总是不小心右击鼠标,提示 有时候挺烦人的,那怎么关闭呢? 打开edge浏览器的设置 在设置中搜索AI,并关闭AI书写的选项就好了 这样就可以获得一个干净的界面了,不…

什么是APP封装?APP封装有什么途径?APP封装如何实现?

APP封装是形成APP成本最低的一种方式。你只需要拥有一个手机端的网址就可以通过一些技术处理封装成一个跨iOS和Android的APP,这个过程往往只需要几分钟。既节省时间又能节省开发的成本资金,所以接下来就介绍一下大家都比较关心的怎么给手机网站封装打包成…

基于pytest的证券清算系统功能测试工具开发

需求 1.造测试数据:根据测试需要,自动化构造各业务场景的中登清算数据与清算所需起来数据 2.测试清算系统功能: 自动化测试方案 工具设计 工具框架图 工具流程图 实现技术 python, pytest, allure, 多进程,mysql, 前端 效果 测…

探索 PostgreSQL 的高级数据类型 - 第 二 部分

范围类型 范围类型提供了一种简洁的方式来表示单个数据库字段中的值范围。它们在从时间数据到数字间隔的各种领域中都有应用。在本篇博客文章中,我们将通过 DML/SQL 语句和 Navicat for PostgreSQL 16 来深入了解它们的使用(以及好处!&#…

STM32存储左右互搏 SPI总线读写SD/MicroSD/TF卡

STM32存储左右互搏 SPI总线读写SD/MicroSD/TF卡 SD/MicroSD/TF卡是基于FLASH的一种常见非易失存储单元,由接口协议电路和FLASH构成。市面上由不同尺寸和不同容量的卡,手机领域用的TF卡实际就是MicroSD卡,尺寸比SD卡小,而电路和协…