ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

服务占用page cache过高问题分析

2022-05-08 19:02:05  阅读:382  来源: 互联网

标签:文件 滚动 FADV 占用 cache POSIX 日志 page


问题描述

三个星期前,测试反馈重构服务部署后cache是5.6G,跑了5个小时,cache涨到53G,增涨了47.4G。

分析处理

1.对于 free 的 cache 异常,以前没有涉猎,查询资料,cache 作为page cache的内存数量,一般作为文件系统的cache,如果cache较大,说明用到cache的文件较多。我的服务主要负责网络通信,内核计算会用到文件资源,因此怀疑是内核打开过多文件导致cache上涨,但测试反馈老服务使用同一资源没有该问题,由此分析,应该跟内核没有关系,可能是我服务错误使用了内核导致的。

2.还是使用排除法定位问题,比较重构和老服务的区别,先注释jemalloc,发现没有解决问题。

3.开始review代码,希望发现重构服务和老服务的区别,没有发现问题。

4.同事反馈使用 iotop 命令发现重构服务存在大量写操作,怀疑可能是服务写日志导致 page cache 增加,于是关闭日志输出,page cache几乎停止增加,问题确认,由于重构日志写的太大,导致page cache增加

5.开始解决日志过大问题,同事建议日志滚动可以解决问题,但是我打算分两步操作,第一步,精简日志,将一些不需要info日志修改成debug,第二步实现滚动日志功能。

6.精简日志后,有一定效果,但是精简日志不是最终的办法,毕竟有些日志还是很重要的,日志滚动功能必须实现。

7.滚动日志,我的想法是按大小进行滚动,当打印日志超过一定大小,直接创建一个新的日志文件.

8.实现功能之后,经过测试,效果几乎没有,内存上涨还是很厉害,通过 cahce 检测工具[nocache]发现滚动的那些日志还在 cache 中,同事建议使用 posix_fadvise() 来将文件从page cache 中清除。

9.实现代码如下,但是编译程序出现错误

#include <stdio.h>
#include <fcntl.h>

FILE* fp = fopen(path, "a");
if (fp) 
{
    posix_fadvise(fileno(fp), 0, 0, POSIX_FADV_DONTNEED);
    fclose(fp);
    fp = NULL;
}

10.因为日志原来是第三方库的功能,我只是增加日志滚动功能,结果一直无法编译通过,但是写一个demo程序直接调用 posix_fadvise 函数确没有该问题,经过比较编译命令,最终发现是 "-std=c99"带来的影响,注释该属性,编译正常。

11.再次测试,发现 cache 仍然存在,通过 cahce 检测工具发现滚动的那些日志还在 cache 中,再使用lsof命令发现本应该被卸载出 cache 日志文件居然还是某些进程引用着,因为重构服务是多进程架构,按大小滚动日志,那么多个进程会重复打开每一个日志文件,但是可能写一行数据就换一个文件,这种场景下,可能会出现某些进程没有正常关闭日志文件。而且按大小滚动还存在一个问题,查找日志特别不方便,因为我也无法确认日志在哪个文件中。

12.重新设计日志滚动方案,按小时滚动日志,这样多进程就不会打开自己不需要打开日志文件,并且查询日志更加方便快。

13.修改完经过测试完美解决 cache 上涨问题。

 

总结

page cache过高可能是读取了大量文件或者大量写文件导致。

附件

#include <fcntl.h>
int posix_fadvise(int fd, off_t offset, off_t len, int advice);

说明:

程序可以使用posix_fadvise()宣布将来打算以特定模式访问文件数据,从而允许内核执行适当的优化。

该建议适用于从fd引用的文件中的偏移量开始并延伸len个字节(或者如果len为0则直到文件末尾)的(不一定存在的)区域。该建议不具有约束力。它仅代表该应用程序的期望。

允许的建议值包括:

POSIX_FADV_NORMAL
指示该应用程序不建议给出其对指定数据的访问模式。如果没有建议打开文件,这是默认假设。
POSIX_FADV_SEQUENTIAL
该应用程序期望顺序访问指定的数据(先读取较低的偏移量,然后读取较高的偏移量)。
POSIX_FADV_RANDOM
指定的数据将以随机顺序访问。
POSIX_FADV_NOREUSE
指定的数据将仅被访问一次。
在2.6.18之前的内核中,POSIX_FADV_NOREUSE具有与POSIX_FADV_WILLNEED相同的语义。这可能是一个错误;从2.6.18内核开始,此标志为空。
POSIX_FADV_WILLNEED
指定的数据将在不久的将来访问。
POSIX_FADV_WILLNEED启动对页面缓存中指定区域的非阻塞读取。内核可以根据虚拟内存负载减少读取的数据量。 (通常将完全满足几兆字节的需求,而很少有用。)
POSIX_FADV_DONTNEED
指定的数据将在不久的将来不被访问。
POSIX_FADV_DONTNEED尝试释放与指定区域关联的缓存页面。例如,在流大文件时,这很有用。程序可能会定期请求内核释放已使用的缓存数据,以使更有用的缓存页面不会被丢弃。
丢弃部分页面的请求将被忽略。与丢弃不需要的数据相比,保留所需的数据更好。如果应用程序要求考虑将数据丢弃,则必须将offset和len页面对齐。
该实现可能会尝试写回指定区域中的脏页,但这不能保证。任何未写的脏页都不会被释放。如果应用程序希望确保将释放脏页,则应首先调用fsync(2)或fdatasync(2)。

返回值:
成功时,返回零。出错时,返回错误号。

备注:
在Linux下,POSIX_FADV_NORMAL将预读窗口设置为备用设备的默认大小; POSIX_FADV_SEQUENTIAL将该大小加倍,并且POSIX_FADV_RANDOM完全禁用文件预读。这些更改不仅会影响指定的区域,还会影响整个文件(但不会影响同一文件的其他打开文件句柄)。

可以通过proc(5)中描述的/ proc / sys / vm / drop_caches接口清除内核缓冲区高速缓存的内容。

通过打开文件,使用mmap(2)映射文件,然后将mincore(2)应用于映射,可以获取快照文件驻留在缓冲区高速缓存中的快照。

 

标签:文件,滚动,FADV,占用,cache,POSIX,日志,page
来源: https://www.cnblogs.com/zhanggaofeng/p/16246416.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有