竹笋

首页 » 问答 » 常识 » MongoDB疑难解析为什么升级之后负载
TUhjnbcbe - 2024/8/18 0:16:00

本文是“我和MongoDB的故事”征文比赛的二等奖得主李鹏冲的文章。下面我们一起来欣赏下。

问题

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

监控与日志

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

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

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

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

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

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

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

撸代码:splitChunk、balancer与moveChunk

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

3.2版本和4.0版本,此部分逻辑最大的区别就是,3.2版本balancer在mongos,4.0版本在config(3.4版本开始),moveChunk过程和删除数据的逻辑基本没有差异。

splitChunk

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

启动时,mongos默认每个chunk的原始大小为0-1/5maxChunkSize范围取个随机值;之后chunk内数据,每次update/insert操作时,chunkSize=chunkSize+docSize;当chunkSizemaxChunkSize/5时,触发一次可能splitchunk的操作;到分片mongod执行splitVector命令,splitVector命令返回chunk的分割点,如果返回为空那么不需要split,否则继续splitChunk。也就是说,splitChunk操作有滞后性,即使数据分布均衡,也有可能splitChunk执行时间的差异导致chunks分布存在中间的不均匀状态,导致大量的moveChunk。

balancer

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

config.shards读取分片信息;config.collections读取所有集合信息,并且随机排序保存到一个数组中;对每个集合从config.chunks读取chunks的信息;含有最多chunks数量(maxChunksNum)的分片为源分片,含有最少chunks数量(minChunksNum)的分片为目的分片;如果maxChunksNum–minChunksNum大于迁移的阈值(threshold),那么就是不均衡状态,需要迁移,源分片的chunks第一个chunk为待迁移的chunk,构造一个迁移任务(源分片,目的分片,chunk)。

每次balancer会检测所有集合的情况,每个集合最多一个迁移任务;而且构造迁移任务时,如果某个集合含有最多数量的分片或者最少数量chunks的分片,已经属于某一个迁移任务,那么此集合本轮balancer不会发生迁移。最后,本次检测出的迁移任务完成以后才开始下次balancer过程。

balancer过程中,会对集合做一次随机排序,当有多个集合的数据需要均衡时,迁移时也是随机的,并不是迁移完一个集合开始下一个集合。

重点

1
查看完整版本: MongoDB疑难解析为什么升级之后负载