代码改变世界

MongoDB如何处理Jumbo块

2022-04-18 22:45  abce  阅读(248)  评论(0编辑  收藏  举报

你是一名MongoDB DBA,当天的第一项任务是从集群中删除一个分片。听起来很吓人,但你知道这很容易。 你可以用一个简单的命令来做到这一点:

db.runCommand( { removeShard: "server1_set6" } )

mongodb会找到对应的块和数据库,并在所有的其它节点上重新平衡。你可以放心地睡了。

第二天醒来,你检查某个分片的状态,你会发现进程被夯住了:

"msg" : "draining ongoing",
"state" : "ongoing",
"remaining" : {
"chunks" : NumberLong(3),
"dbs" : NumberLong(0)

由于某种原因,有三个块没有被迁移。所以,removeShard命令夯了。接下来你会怎么做呢?

找出哪些块不能被移动

连接到mongos并检查:

mongos> use config
switched to db config
mongos> db.chunks.find({shard:"server1_set6"})

结果会显示有三个块,以及最小和最大的_id键,属于的命名空间。

最后一部分才是你需要检查的:

{
[...]
"min" : {
"_id" : "17zx3j9i60180"
},
"max" : {
"_id" : "30td24p9sx9j0"
},
"shard" : "server1_set6",
"jumbo" : true
}

块被标记为jumbo,我们必须找出为什么平衡进程为什么没有成功。

如何处理Jumbo块

所谓“jumbo chunk”,就是一个chunk的大小超过了设置的chunk的最大值。默认是64MB。当超出这个值的时候,balancer进程就不会起作用。

这只是概念上的解释,实现上就是当splitCommand发现无法将一定范围内的documents分裂到比设定值小的segment中,就会将该块标记为Jumbo。

如何清除Jumbo标记

从mongodb 4.0.15开始,可以使用clearJumboFlags命令。

在老的版本中,需要手动移除

db.getSiblingDB("config").chunks.update(
{"ns": <your_sharded_user_db.coll>, "jumbo": true},
{$unset: { "jumbo": "" }}
);

使用Indivisible处理

从mongodb4.4开始,可以使用refineCollectionShardKey命令给分片键增加一列,作为前缀。比如将 {“surname”: 1,“given_name”: 1} 修改成{“surname”: 1, “given_name”: 1, “date_of_birth”: 1}

如果版本低于或等于4.2,块大小超出设置后不能被移动。

在上面段落中描述的 can't-drain 问题场景中,你必须执行以下操作之一才能完成分片的清理,以便你可以运行最终的removeShard

1.在增加块大小设置后移动jumbo块

·遍历所有jumbo块,使用 dataSize 命令找出最大的大小。·将块大小设置更改为大于该值。·清除巨型标志(参见上面的小节)·再次开始清理,等待它移动大块。 如果想它们尽快发生,请使用 sh.moveChunk() 命令。·之后不要忘记更改块大小。

2.间或删除数据。然后重新插入数据

·仍然需要清理jumbo标记

 

jumbo 标志一旦被附加,即使文档被删除或以其他方式缩小,也不会自动删除,因此块在(默认)64MB 大小内。你可以手动清除巨型标志(请参阅上面的小节)并重试。

理论上,不需要手动进行任何拆分,但如果想快点确认可以将块拆分成足够小的大小,请参阅如何使用 sh.splitAt() 命令文档。