高并发场景下的BigCache本地缓存OOM问题

一.背景

线上频繁出现报警,提示内存被打爆问题,几个服务出现短暂不可用的现象,现就分析过程和解决过程记录如下

二.问题描述:

报警群里开始报警:活动中心集群中某个节点内存超过90%,有接口出现短暂不可用。

立即重启机器,但是重启依然挂掉。然后进行扩容,但是刚起来就内存打爆。

通过可以看到以下接口收到大量请求,同时有三台天津的机器 内存使用率超过90%

初步怀疑是请求量大,导致内存被打爆, 可能是本地内存淘汰的速率远远小于缓存速率导致的,内部容量不够时会扩容。

使用go heap tool分析如下

内存空间图如下:

可以明显的看到bigCache在init初始化时用了大量内存,而且当前业务场景key的值并不是太多,所以排除了缓存速度远远大于淘汰速度的原因。

然后深入到代码,以及查看bigCache发现是参数设置有问题。这里的MaxEntrySize并不是bigcache的内存大小,

只是每个entry(key)的最大大小

这里1000*10*60*500Byte = 300M和上图的基本吻合,但是发现还有个2.83G

原来另一个接口中设置了更大的本地缓存:

1000*10*60*5000Byte 约等于3G。设置内存大小需要使用:WithHardMaxCacheSize,否则会导致OOM.

但是有一个疑问,为啥平时没有报出这个错误那?

回到业务场景,这个服务是为了首页不断拉取横幅和小工具,属于读多写少的情况,为了前端速度,采用本地缓存,这就造成如果用户更新,不能影响全局的数据,所以设置了比较短的过期时间。在高并发情况下这就可能出现大量set cache的情况

,代码发现代码设置缓存开了goroutine 异步执行,本身高并发导致goroutine set cache时,锁等待,大量goroutine hang 住了。短过期时间下,高并发set 导致gorountiue 过多,进而导致gotournie内存泄漏。那个时间段的监控确实goroutine 过多,
高并发导致goroutine set cache时,锁等待,大量goroutine hang 住了. 因为是本地缓存,如果用户更新db,为了拉到最新数据,让cache快速过期。

带锁,而且bigCache本身也是有lock机制,当并发上来时直接产生竞争,导致内存不能及时回收,撑爆内存。

这快采用单例模式进行set,每次只保证一个gorountine去设置缓存。

三.总结

1.本地缓存BigCache设置有问题.

2.Set bigcache key是加锁操作,高并发场景下,当多个goroutine 同时进行set时,导致其他goroutine hang住,短时间内大量gotinue没有被释放撑爆内存。

四.解决方案

1. 初始化较小本地缓存,设置缓存最大值,出发LRU淘汰。

2.使用SingleFlight-- 合并相同请求,是为了加固代码,采用double check机制,set 之前get一次,减少无谓的cpu计算和内存资源浪费

五 效果如何:

经过修改,同时压测了1000qps的数据,测试环境如下:

经过上线后对比数据如下,可以清楚的看到变更后内存使用率显著下降。

分析go内存heap 可以看到init New bigCache显著下降

版权声明:
作者:后厂村鹅厂
链接:https://jkboy.com/archives/12979.html
来源:随风的博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
高并发场景下的BigCache本地缓存OOM问题
线上频繁出现报警,提示内存被打爆问题,几个服务出现短暂不可用的现象,现就分析过程和解决过程记录如下
<<上一篇
下一篇>>