• Debezium Mysql BinLog同步引擎的内存爆满,频繁GC导致CPU爆高


    现象,第一步

    同步任务的http接口查询任务列表接口突然变卡,很久才相应,进入服务器后执行top命令发现CPU已经爆满。

    top (查看进程占用资源)

    机器是4核,所以占用了400%

    wecom-temp-138912e7f885f37ae16b86cb7872acc1.png

    top -H -p 276965 (查看进程ID下的子进程占用资源)

    4个子线程,每个各占了100%

    wecom-temp-06673636548e93c8a3584ee412ca405c.png

    printf “%x\n” 276970

    jstack 276965 | grep 439ea -A 100

    通过查看当前线程执行的详情,发现输出的是gc线程

    jmap -heap 276965

    jmap的使用方式:blog.csdn.net/heihaozi/ar…

    查看jvm当前的堆内存情况,老年代、新生代皆已满

    wecom-temp-9498631e96940ca4b078158f017e544a.png

    上面的命令具体怎么用参考这篇blog:blog.csdn.net/cainiao1412…

    第二步

    既然是堆内存满了,此刻就要拿到整个堆内存的快照,执行

    jmap -dump:live,format=b,file=heap.dump 276965

    下载到本地使用 VisualVM 打开,有很亮眼的TableMapEventData,但是此时还是不清楚何处引起的泄露。

    VisualVM的使用方式:blog.csdn.net/weixin_4546…t.zoukankan.com/wangzun-p-1…

    image.png

    此时使用工具MAT继续打开dump,这里看就比较明显,是一个名为MySql…EventSource类中的tableMap…ByTableId的一个HashMap巨大,

    MAT的使用方式:zhuanlan.zhihu.com/p/482860374 , blog.csdn.net/w2009211777…

    image.png

    第三步

    根据MAT的提示,找到该处代码,可以看见在收到TABLE_MAP这个Event事件时,会将数据放到HashMap中

    image.png

    数据既然存,就也需要清理,在源码中只找到了一处清理该Map的地方,当收到ROTATE事件时,清理Map,那么由此可见如果不收到ROTATE事件,Map将会无限增长

    image.png

    什么是ROTATE事件?

    参考:www.freesion.com/article/125…

    也就是说我们的Map会等到binlog文件大小达到 max_binlog_size 的值时,才会进行清空,或者手动执行flush logs,但是生产环境中一般不会去手动执行,max_binlog_size 的值我们的库默认为 256MB。

    image.png

    什么是 Table Map Event?

    意思就是 Table Map Event 会存储表的元数据,例如数据库名、表名、字段等,后续的Row Event会通过table id 和其关联,取到对应的元数据,因此这个存储是有必要的,

    但是table id会随着缓存淘汰、刷新等机制出现变化,也就是说同一个库的同一个表的table id会不停的变化,因此table id并不是唯一的,所以我们的Map会随着程序的运行可能存储很多明明是同库同表,但是因为table id不同导致存map中很多重复的数据,导致占用内存越来越大。

    image.png

    image.png

    解决方式

    Debezium对mysql binlog同步默认使用的是 github.com/osheroff/my… , 这个库很久没有更新了,

    但是Flink CDC使用的也是 Debezium,也就是说也依赖了这个库,所以可能也会存在这种问题,

    两种解决方式,一是增大内存,均匀任务,让内存足够存储这么多的冗余数据,二是修改源码,在特定时机,例如新的table id过来时,将老的table id对应的数据清除?

    针对binlog的同步,还有一个工具叫做maxwell,在生产环境中使用并没有出现这种问题,追踪了一下源码,也是类似的原理,但是maxwell使用我们使用了docker做资源隔离,每个进程给了2g,而Debezium任务则跑在同一个jvm中,因此更多倾向于均匀分配一些资源。

    最终解决方式

    我们的系统采用的版本是1.9.0.Final,在查看其源码时,在 MySqlStreamingChangeEventSource 类中,针对 ROTATE 事件发生时,并没有对map进行clear处理,所以导致了内存泄露,为了避免升级版本影响过大,我们采用了修改源码的方式,针对ROTATE发生时,对map进行清除。

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    关于Java Integer和Long使用equals直接比较
    Flutter系列文章-Flutter 插件开发
    java基础07
    生物素偶联二硒化钨WSe2 (Biotin-WSe2)|羟基修饰PEG化二硒化钨WSe2纳米颗粒 (OH-WSe2)齐岳
    Swagger2使用------------整合SpringBoot
    C#实现观察者模式
    Clickhouse中的预聚合引擎
    DTW 2023:戴尔发力多云战略与边缘运营
    一次服务器被入侵的处理过程分享
    Spark SQL数据源 - Hive表
  • 原文地址:https://blog.csdn.net/cainiao1412/article/details/126640797