Cache占用过多内存导致Linux系统内存不足问题排查

本文介绍了一次Linux服务器因Cache占用过多内存导致系统内存不足的问题排查过程。通过free命令和top命令定位问题,并通过调整/proc/sys/vm/drop_caches和/proc/sys/vm/vfs_cache_pressure来释放内存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux服务器内存使用量超过阈值,触发报警。经排查发现,是由于Cache占用过多内存导致Linux系统内存不足。本文将这个问题排查的方法分享给各位,希望对您有所帮助。

问题描述

Linux服务器内存使用量超过阈值,触发报警。

问题排查

首先,通过free命令观察系统的内存使用情况,显示如下:

 
  1. total       used       free     shared    buffers     cached 
  2. Mem:      24675796   24587144      88652          0     357012    1612488 
  3. -/+ buffers/cache:   22617644    2058152 
  4. Swap:      2096472     108224    1988248 

其中,可以看出内存总量为24675796KB,已使用22617644KB,只剩余2058152KB。

然后,接着通过top命令,shift + M按内存排序后,观察系统中使用内存最大的进程情况,发现只占用了18GB内存,其他进程均很小,可忽略。

因此,还有将近4GB内存(22617644KB-18GB,约4GB)用到什么地方了呢?

进一步,通过cat /proc/meminfo发现,其中有将近4GB(3688732 KB)的Slab内存:

 
  1. ...... 
  2. Mapped:          25212 kB 
  3. Slab:          3688732 kB 
  4. PageTables:      43524 kB 
  5. ...... 

Slab是用于存放内核数据结构缓存,再通过slabtop命令查看这部分内存的使用情况:

 
  1. OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME 
  2. 13926348 13926348 100%    0.21K 773686       18   3494744K dentry_cache 
  3. 334040 262056  78%    0.09K   8351       40     33404K buffer_head 
  4. 151040 150537  99%    0.74K  30208        5    120832K ext3_inode_cache 

发现其中大部分(大约3.5GB)都是用于了dentry_cache。

问题解决

1. 修改/proc/sys/vm/drop_caches,释放Slab占用的cache内存空间(参考drop_caches的官方文档):

 
  1. Writing to this will cause the kernel to drop clean caches, dentries and inodes from memory, causing that memory to become free. 
  2. To free pagecache: 
  3. * echo 1 > /proc/sys/vm/drop_caches 
  4. To free dentries and inodes: 
  5. * echo 2 > /proc/sys/vm/drop_caches 
  6. To free pagecache, dentries and inodes: 
  7. * echo 3 > /proc/sys/vm/drop_caches 
  8. As this is a non-destructive operation, and dirty objects are notfreeable, the user should run "sync" first in order to make sure allcached objects are freed. 
  9. This tunable was added in 2.6.16. 

2. 方法1需要用户具有root权限,如果不是root,但有sudo权限,可以通过sysctl命令进行设置:

 
  1. $sync 
  2. $sudo sysctl -w vm.drop_caches=3 
  3. $sudo sysctl -w vm.drop_caches=0 #recovery drop_caches 

操作后可以通过sudo sysctl -a | grep drop_caches查看是否生效。

3. 修改/proc/sys/vm/vfs_cache_pressure,调整清理inode/dentry caches的优先级(默认为100),LinuxInsight中有相关的解释:

 
  1. At the default value of vfs_cache_pressure = 100 the kernel will attempt to reclaim dentries and inodes at a “fair” rate with respect to pagecache and swapcache reclaim. Decreasing vfs_cache_pressure causes the kernel to prefer to retain dentry and inode caches. Increasing vfs_cache_pressure beyond 100 causes the kernel to prefer to reclaim dentries and inodes.  

具体的设置方法,可以参考方法1或者方法2均可。

参考资料

  • https://www.kernel.org/doc/Documentation/sysctl/vm.txt
  • http://major.io/2008/12/03/reducing-inode-and-dentry-caches-to-keep-oom-killer-at-bay/
  • http://linux-mm.org/Drop_Caches

以下记录的是进一步排查的进展情况。

更深层次的原因

上文排查到Linux系统中有大量的dentry_cache占用内存,为什么会有如此多的dentry_cache呢?

1. 首先,弄清楚dentry_cache的概念及作用:目录项高速缓存,是Linux为了提高目录项对象的处理效率而设计的;它记录了目录项到inode的映射关系。因此,当应用程序发起stat系统调用时,就会创建对应的dentry_cache项(更进一步,如果每次stat的文件都是不存在的文件,那么总是会有大量新的dentry_cache项被创建)。

2. 当前服务器是storm集群的节点,首先想到了storm相关的工作进程,strace一下storm的worker进程发现其中有非常频繁的stat系统调用发生,而且stat的文件总是新的文件名:

sudo strace -fp <pid> -e trace=stat

3. 进一步观察到storm的worker进程会在本地目录下频繁的创建、打开、关闭、删除心跳文件,每秒钟一个新的文件名:

sudo strace -fp <pid> -e trace=open,stat,close,unlink

以上就是系统中为何有如此多的dentry_cache的原因所在。

一个奇怪的现象

通过观察/proc/meminfo发现,slab内存分为两部分:

SReclaimable // 可回收的slab
SUnreclaim // 不可回收的slab

当时服务器的现状是:slab部分占用的内存,大部分显示的都是SReclaimable,也就是说可以被回收的。

但是通过slabtop观察到slab内存中最主要的部分(dentry_cache)的OBJS几乎都是ACTIVE的,显示100%处于被使用状态。

OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME                   
13926348 13926348 100%    0.21K 773686       18   3494744K dentry_cache
334040 262056  78%    0.09K   8351       40     33404K buffer_head
151040 150537  99%    0.74K  30208        5    120832K ext3_inode_cache

为什么显示可回收的,但是又处于ACTIVE状态呢?求Linux内核达人看到后热心解释下:(

会不会由于是ACTIVE状态,导致dcache没有被自动回收释放掉呢?

让系统自动回收dcache

上一小节,我们已经提到,服务器上大部分的slab内存是SReclaimable可回收状态的,那么,我们能不能交给操作系统让他在某个时机自动触发回收操作呢?答案是肯定的。

查了一些关于Linux dcache的相关资料,发现操作系统会在到了内存临界阈值后,触发kswapd内核进程工作才进行释放,这个阈值的计算方法如下:

1. 首先,grep low /proc/zoneinfo,得到如下结果:

        low      1
        low      380
        low      12067

2. 将以上3列加起来,乘以4KB,就是这个阈值,通过这个方法计算后发现当前服务器的回收阈值只有48MB,因此很难看到这一现象,实际中可能等不到回收,操作系统就会hang住没响应了。

3. 可以通过以下方法调大这个阈值:将vm.extra_free_kbytes设置为vm.min_free_kbytes和一样大,则/proc/zoneinfo中对应的low阈值就会增大一倍,同时high阈值也会随之增长,以此类推。

$ sudo sysctl -a | grep free_kbytes       
vm.min_free_kbytes = 39847
vm.extra_free_kbytes = 0
$ sudo sysctl -w vm.extra_free_kbytes=836787  ######1GB

4. 举个例子,当low阈值被设置为1GB的时候,当系统free的内存小于1GB时,观察到kswapd进程开始工作(进程状态从Sleeping变为Running),同时dcache开始被系统回收,直到系统free的内存介于low阈值和high阈值之间,停止回收。

原文链接:http://www.cnblogs.com/panfeng412/p/drop-caches-under-linux-system.html

http://www.cnblogs.com/panfeng412/p/drop-caches-under-linux-system-2.html


<think>嗯,用户现在想解决Elasticsearch进程内存占用高的问题。之前用户提到了几个引用,都是关于Elasticsearch常见问题的解决方案,比如目录权限、fielddata内存、堆内存和磁盘占用等。需要结合这些引用信息以及用户当前的需求来提供排查和优化的方法。首先,用户引用的内容里,引用[2]和[3]尤其相关,因为它们涉及到fielddata内存和堆内存的监控命令。比如引用[2]提到用_cat/indices查看fielddata.memory_size排序,而引用[3]中的_cat/nodes命令可以查看各个节点的内存组成部分,如堆内存、fielddata、查询缓存等。这些是排查的关键步骤。接下来,用户的直接需求是解决内存占用高的问题。需要分步骤来考虑。首先,确认是否堆内存不足,引用[3]中的heapCurrent接近heapMax可能导致频繁GC。这时候可能需要调整堆大小,但要注意不超过32GB和50%物理内存的原则。同时,检查是否有内存泄漏或未释放的资源,比如未关闭的scroll或大量聚合查询。引用[4]中调整副本数的操作虽然主要用于磁盘空间,但也可能间接影响内存,因为副本也会占用内存资源。然后,fielddata内存可能是一个大问题,特别是当text字段被用于聚合或排序时。引用[2]中的命令可以帮助定位具体索引,从而决定是否需要优化字段类型或者清理缓存。另外,查询缓存和请求缓存的使用情况也需要通过引用[3]中的指标来确认,如果占用过高,可能需要评估是否有必要调整缓存策略。文件系统缓存(OSCache)的优化也很重要。虽然堆内存的设置是关键,但剩余内存应由Linux用于缓存索引文件,提升性能。因此,需要确保堆内存设置合理,避免挤压OSCache的空间。用户的引用中提到了replica调整(引用[4]),虽然主要应对磁盘问题,但在内存场景下也可能有用,因为减少副本数可以降低内存开销,不过需权衡数据可靠性。同时,冷热数据的分离策略(引用[4]间接相关)也能帮助分散负载,使用不同层级的存储资源,减轻节点压力。关于是否调整分片数量,可能用户引用中没有直接提到,但根据经验,过多分片会增加内存负担,特别是当节点分片数超限(如ES7默认1000),所以需要检查并可能调整分片策略。综合所有引用和用户需求,需要给出系统的步骤:监控具体内存组件→调整堆内存→优化缓存策略→控制fielddata使用→分离冷热数据→分片优化。同时,提醒用户具体配置需根据硬件和集群状况调整,避免一刀切。最后,相关问题的延伸可以覆盖堆内存优化后的问题排查、fielddata控制方法及冷热数据分离的具体操作,这些都是用户可能进一步关心的方向。</think> 以下是排查和优化 Elasticsearch 高内存占用系统性解决方案,结合关键引用信息整理: --- ### **排查步骤** #### 1. **分析内存组成** ```bash GET _cat/nodes?v&h=id,heapCurrent,heapMax,fielddataMemory,queryCacheMemory,requestCacheMemory,segmentsMemory ``` - **关键指标**(引用[3]): - `heapCurrent`:当前堆内存占用 - `fielddataMemory`:排序/聚合字段缓存大小 - `segmentsMemory`:Lucene 段内存占用 - 若 `heapCurrent` 持续接近 `heapMax`,说明堆内存不足,需优化配置或查询 #### 2. **定位 fielddata 溢出** ```bash GET _cat/indices?v&h=index,fielddata.memory_size&s=fielddata.memory_size:desc ``` - 检查是否有索引的 `fielddata.memory_size` 异常(引用[2]),常见于对 `text` 字段进行聚合/排序 #### 3. **检查查询缓存** ```bash GET _nodes/stats/indices?filter_path=**.request_cache,query_cache ``` - 高频聚合查询易导致 `query_cache` 膨胀(引用[3]) #### 4. **监控磁盘缓存** - 剩余内存应尽可能留给 OS Cache(未被 JVM 堆占用部分),用于缓存 Lucene 文件 --- ### **优化方案** #### 1. **堆内存调整** - **配置原则**(引用[3]): - 不超过物理内存的 **50%**(预留空间给 OS Cache) - 不超过 **30GB**(避免 JVM 指针压缩失效) - 修改 `jvm.options`: ```conf -Xms30g -Xmx30g # 根据物理内存按比例调整 ``` #### 2. **控制 fielddata 内存** - **方案 1:限制字段类型** 避免对 `text` 字段聚合/排序,改用 `keyword` 类型(占用固定内存) - **方案 2:强制清理缓存** ```bash POST _cache/clear?fielddata=true # 临时释放 fielddata(引用[2]) ``` - **方案 3:设置内存熔断** ```yaml indices.breaker.fielddata.limit: 30% # 堆内存占比上限 ``` #### 3. **优化查询缓存** - 关闭非必要缓存(引用[3]): ```yaml indices.requests.cache.enable: false # 关闭请求缓存 index.queries.cache.enabled: false # 关闭查询缓存 ``` #### 4. **减少分片资源开销** - **降低副本数**(引用[4]): ```bash PUT /my_index/_settings { "number_of_replicas": 0 } # 生产环境需权衡可靠性 ``` - **合并小分片**: ```bash POST /my_index/_forcemerge?max_num_segments=1 ``` #### 5. **冷热数据分离** - 将历史数据迁移至低频节点: ```yaml # 配置分层存储(需安装 Data Tier 插件) node.roles: ["data_hot"] # 热节点 node.roles: ["data_cold"] # 冷节点 ``` --- ### **长效预防** ```bash # 定期监控(引用[1][3]) watch -n 30 'curl -sXGET "http://localhost:9200/_cat/nodes?h=ramCurrent,heap*"' ``` - **关键指标阈值**: - `heap_used_percent` > 75% → 触发 GC 压力警告 - `fielddataMemory` > 20% 堆内存 → 需优化映射 --- ### 总结建议 > **堆内存优化是核心**(物理内存50% + ≤30GB),配合**禁用非必要字段聚合**(如 `text` 字段)和**缓存控制**。优先排查 `fielddata` 溢出(引用[2]),其次检查分片数量(单节点分片勿超 600)和查询模式,最后考虑扩展集群。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值