落叶 发表于 2024-7-29 14:28:09

【MyBatis】一次生产事故发现的一级缓存导致伪内存泄露问题

    “内存泄漏”指的是某些内存空间因为某些原因导致无法被正常回收,导致这部分空间始终无法再被利用。
    本次事故突发于上周末,具体表现为:CPU占用颇高,通过jstat命令查看进程发现FGC时间一直在增长。
    首先我根据掌握的线索初步定为原因是内存泄漏,但是具体原因未知,趁着客户还没爆炸赶紧将堆内存数据dump一份下来然后在本地分析:




    最终根据分析结果,定位问题出在Mybatis。
    此时,我想到一个问题:myBatis是存在一级缓存和二级缓存的,这些是本地缓存,也就是直接常驻程序内存的。
    因为线上服务器的堆内存分配策略是有一半多的分给了年轻代(程序会频繁大量产生短生命周期的对象),老年代的内存很少,也刚好就在4~6G之间,这么一看问题就很明了了,因为老年代内存不足的时候,就会触发GC,而且会直接导致FGC的产生。FGC会使得程序STW(Stop the world),CPU使用率飙升。
    根据相关资料查询所得:MyBatis的二级缓存默认关闭,一级缓存是无法完全关闭的,只能通过其他方案实现关闭的效果:
mybatis:
    configuration:
      cache-enabled: false#禁用二级缓存
            local-cache-scope: statement#一级缓存指定为statement级别</font>    将上述代码添加到application.properties或者nacos中,即可实现将一级缓存更改为statement级别,当statement关闭的时候相对应的缓存会被立即释放。
    上述方案可以避免因为一级缓存导致的内存泄露问题,但是也同样带来了额外的开销。
    所以,个人认为ORM框架就做好ORM框架的事情,将缓存这种工作交给缓存中间件来做。
Felix2024年7月29日 14:25
页: [1]
查看完整版本: 【MyBatis】一次生产事故发现的一级缓存导致伪内存泄露问题