了解更多银河麒麟操作系统全新产品,请点击访问
麒麟软件产品专区:https://product.kylinos.cn
开发者专区:https://developer.kylinos.cn
文档中心:https://documentkylinos.cn
现象描述
系统中出现大量的TCP: out of memory -- consider tuning tcp_mem的报错,同时有多次call trace 产生。
根据提示 查询内核参数,net.ipv4.tcp_mem = 25401 33869 50802 值的很小,出现此问题时,cpu负载很高,tcp连接断续,请求处理不及时。
现象分析
tcp_mem报错分析
查看前线收集的sosreport日志,对于频繁出现TCP: out of memory -- consider tuning tcp_mem的错误,通常表明系统TCP缓冲区已满,无法继续申请对应的缓存。
net.ipv4_tcp_mem和业务需求不符,对这种情况我们通常会调整其数值。但对当前问题我们发现了一个异常的地方,net.ipv4_tcp_mem的数值在不手动设定的情况下系统初始化是和机器总内存大小相关的,查看本机内存大小为128G,对比上述的tcp_mem的数值明显不符。
继续查看系统内核版本,发现为SP2-4.19.90-24.4内核,该版本内核存在内存managed统计错位这一已知问题,该问题会造成系统内存碎片化、容易触发OOM、tcp_mem初始化异常等故障,下面我们详细进行说明。
内存managed统计错位bug说明
银河麒麟服务器系统内核基于openeuler内核开发,而openeuler内核在优化内存时引入了一个bug(commit eb761d6521c32c006a4987260394a61c6684fb35: mm: parallelize deferred struct page initialization within each node),该bug会导致zone的managed_pages统计出现错位。
具体查看系统的/proc/zoneinfo我们可以发现Node 0 Normal区域的managed出现统计异常,其managed远小于spanned、present;而Node 0 Movable区域这个本不该管理内存的区域managed异常的大,对应的内存回收水位也极高。其余几个Node的情况也是如此,这就是上述BUG导致的managed_pages统计出现错位的问题了。
而zone的managed_pages统计出现错位会进一步造成其他影响,一是影响各个zone的内存回收水位的计算,因为内存回收水位是按照各个zone managed_pages的比例来分配的,zone Normal原本管理的内存被统计到zone Movable后,可以看到其内存回收水位min/low/high变成了27/59/91这个极小的值,这又影响了后续系统的内存回收。linux系统的内存回收是当对应zone的剩余内存低于low水位被触发,直至回收到high水位停止,这么小的内存回收水位将导致即使触发内存回收也回收不了多少内存就停止了,高压力下zone Normal将始终保持在一个几乎没有空闲内存可以使用的情况。
二是net.ipv4.tcp_mem的初始化也是只考虑DMA/DMA32/Normal三个区域的managed内存和high水位情况,net.ipv4.tcp_mem等于这三个区域的(managed-high)/16/4*3。和上面的情况类似,zone Normal原本管理的内存被统计到zone Movable后,系统的net.ipv4.tcp_mem初始化数值也将变得异常的低。这也就使得后续有大量tcp链接时,tcp_mem不足、无法分配内存,使得tcp链接的稳定性受到影响。
对于这个bug目前麒麟软件及openeuler都已在官网发布了内核修复公告,银河麒麟操作系统内核在SP1 23.30、SP2 25.22版本得到修复,SP3内核不存在这个BUG。
call trace报错分析
问题发生时,系统日志中除了除了有大量的TCP: out of memory -- consider tuning tcp_mem的报错,同时有多次call trace 产生。
通过整理这些call trace日志我们发现日志集中出现,所有call trace日志打印都是hung_task_timeout_secs 120s超时触发的。
查看这些call trace日志的内容如下所示:
根据上述信息,我们可以发现这些call trace都是nfs模块相关处理中触发的,从堆栈信息来看此时服务器CPU正在处理nfs相关任务,如nfs_updatepage(nfs数据更新)、nfs_file_write(nfs文件写操作)、nfs_flush_incompatible(nfs缓存处理)、nfs_check_verifier(nfs数据完整性验证)等,但上述任务由于长时间处于bit_wait_io、io_schedule这些I/O等待状态中未完成,直到触发hung_task 120S超时便打印的相关日志。
综合当前系统的业务情况,其kubelet pod使用了大量nfs存储,问题时间点系统tcp_mem耗尽,这导致pod与nfs存储的tcp通信出现问题,大量nfs相关任务超时从而在日志中打印了call trace日志。
sa日志分析
继续查看sa日志,首先关注CPU使用情况,我们发现系统%iowait开始上升,结合之前的message日志分析,这应该是由于大规模的NFS文件系统操作延时导致。
再看NFS客户端请求数据,NFS客户端RPC请求数突然开始大幅度上升,这应该就是导致系统tcp_mem耗尽的原因,大量tcp缓存被用于维持nfs链接。
直到系统tcp_mem耗尽,系统无法处理新的tcp链接,已有的tcp链接也会因为内存压力不得不频繁地回收和重新分配内存。NFS客户端RPC请求数开始迅速下降,直到40分钟后才恢复正常。
总结
综上所述,本次tcp_mem异常报错问题产生的原因为当前使用的低版本内核存在的managed_pages统计出现错位的bug。该bug导致Zone Normal原本管理的内存被统计到Zone Movable,而net.ipv4.tcp_mem的初始化只考虑DMA/DMA32/Normal三个区域的managed内存和high水位情况,net.ipv4.tcp_mem等于这三个区域的(managed-high)/16/4*3,因此最终系统net.ipv4.tcp_mem的初始化值会偏小。
net.ipv4.tcp_mem数值较小,在网络压力较大时会出现tcp缓存耗尽的情况。这将导致系统无法处理新的tcp链接,已有的tcp链接也会因为内存压力不得不频繁地回收和重新分配内存,这将影响系统的业务性能和稳定性。对此我们建议升级内核修复相关内核bug,若当前情况不方便升级内核建议手动调整对应内核参数。