MongoDB升级后CPU负载升高的原因和解决方法

  

近期线上一个三分片集群从3.2版本升级到4.0版本以后,集群节点的CPU的负载升高了很多(比10%;40%),除了版本的升级,项目逻辑和操作量均无变化。关闭均衡器以CPU后负载回归正常,稳定在10%以下。为此,只能经常关闭当前正在写入表的平衡器,每周二打开均衡器开启均衡,在此期间节点的CPU负载持续稳定在40%。集群有3个分片,除了MongoDB版本的变化,项目本身的逻辑无任何变化。那么升级以CPU后负载较大变化的背后是什么原因呢?

监控与日志

首先可以明确,升级以CPU后负载升高和均衡器迁移数据有关。观察升级以后4.0版本,周二打开均衡器期间的负载情况和mongostat结果:

可以发现,CPU负载升高和删除数据的情况很吻合。而迁移数据数据之后源节点需要删除迁移走的数据,所以肯定有大量的删除。迁移数据之后的删除也会有如下的日志:

<李>

<代码> 53094:2019-10-08T10:09:24.035199 +喂饲我分片(收集范围删除人)没有文档仍在dt2log删除。tbl_log_item_20191001范围[{_id: -3074457345618258602}, {_ id: -3033667061349287050})

<李>

53095:2019-10-08T10:09:24.035222 +喂饲我分片(收集范围删除器)等新疆复制dt2log当地的删除。tbl_log_item_20191001范围[{_id: -3074 457345618258602}, {_id: -3033667061349287050})

53096:2019-10-08T10:09:24.035274 +喂饲我分片(收集范围删除人)完成删除ting dt2log文档。tbl_log_item_20191001范围[{_id: -3074457345618258602}, {_id

<代码> -3033667061349287050})

所以从监控和日志判断,CPU负载较高主要是因为迁移数据之后的删除导致。而且集群的表都是{_id:散列}分片类型的表,数据量较大,但是每条数据较小,平均每个块10 w +的文档数,删除数据速度约200 - 300/s,所以移动一个块导致的删除就会持续10分钟左右。

统计最近2个周期,开启均衡器以后moveChunk的情况:

从上表可知此场景下,{_id:散列}分片类型集合数据基本已经均匀了,不必重启开启均衡器。因为每个块文档数较多,删除会比较耗资源。

关闭表的均衡器可以解决升级之后负载升高的问题,但是竟然是为何升级到4.0之后CPU负载较高,而3.2版本稳定在低位呢?这只有可能是一个原因:4.0版本更频繁的发生moveChunk,持续的删除数据导致CPU负载一直较高,3.2版本较少的发生moveChunk,不用删除数据所以负载很低。

所以本次问题的根本是:4.0版本和3.2版本的均衡器与moveChunk的逻辑是否有差别?同样的操作,为什么4.0版本的集群会有较多的moveChunk ?

撸代码:splitChunk,均衡器与moveChunk

当通过蒙戈发生插入和更新删除操作时,蒙戈会估算对应的块的数据量的大小,满足条件会触发splitChunk的操作,splitChunk之后可能会导致集群的一部分分布不均匀.balancer检测数据的分布情况,当数据分配不均匀时,发起moveChunk任务,将数据从较块多的分片迁移到块较少的分片,迁移之后源节点会异步删除迁移走的块数据。

3.2版本和4.0版本,此部分逻辑最大的区别就是,3.2版本均衡器在蒙戈,4.0版本在配置(3.4版本开始),moveChunk过程和删除数据的逻辑基本没有差异。

splitChunk

分割一块般是在插入,更新,删除数据时,由蒙戈发出到分片的splitVector命令,此时分片才会判断是否需要分裂。但是蒙戈并不知道每个块真正的数据量,是利用一个简单的估算算法判断的。

<李>

启动时,蒙戈默认每个块的原始大小为0-1/5 maxChunkSize范围取个随机值;

<李>

之后块内数据,每次更新/插入操作时,chunkSize=chunkSize + docSize;

<李>

当chunkSize祝辞maxChunkSize/5时,触发一次可能分割块的操作,到分片mongod执行splitVector命令,splitVector命令返回块的分割点,如果返回为空那么不需要分裂,否则继续splitChunk。

也就是说,splitChunk操作有滞后性,即使数据分布均衡,也有可能splitChunk执行时间的差异导致块分布存在中间的不均匀状态,导致大量的moveChunk。

均衡器

无论还3.2是4.0的均衡器,默认的检测周期为10年代,如果发生了moveChunk,检测周期为1 s .balancer基本过程也大致相同:

<李>

配置。碎片读取分片信息;

<李>

配置。集合读取所有集合信息,并且随机排序保存到一个数组中,

<李>

对每个集合从配置。块读取块的信息;

<李>

含有最多块数量(maxChunksNum)的分片为源分片,含有最少块数量(minChunksNum)的分片为目的分片;如果maxChunksNum——minChunksNum大于迁移的阈值(阈值),那么就是不均衡状态,需要迁移,源分片的块第一个块为待迁移的块,构造一个迁移任务(源分片,目的分片,块)。

MongoDB升级后CPU负载升高的原因和解决方法