【MongoDB】shard切分 原理

来源:互联网 发布:java时间戳转换成秒 编辑:程序博客网 时间:2024/05/16 06:35

1.角色:

在一个MongoDB的shard集群中,会有三种角色:shard,config和routing

shard:每一个shard节点都会包含数据集的一部分,是存储真正数据的节点;

config:主要存储元数据或者配置信息,比如每一个切片的片键的范围,mongos(即routing)会根据这个服务器的配置信息来决定到哪一个分片服务器上存取数据

routing:也就是mongos客户端,用来操作shard集群的接口。

这里有一个问题,为什么不把集群信息存储在mongos里面,即由mongos客户端进程来管理维护呢?主要是因为这些配置信息是会动态改变的,因此直接交给另一个进程更好。


通常,每一个shard都会是一个复制集,主要为了健壮性,因为切片集群一个挂一个切片,那么整个切片的数据都会丢失。每一个config更应该是一个复制集,因为一旦config挂了,那么整个集群就用不了了,所以在MongoDB的最新版本中,强制配置config节点为至少3个节点的复制集,这是很有必要的。


2.片键:

指的就是文档中的一组属性,mongos会根据这个属性来查看该条数据应该属于哪一个shard分片。片键的路由有两种实现方式,一种是范围,一种是哈希,其实本质上都是范围。

范围法:把片键的取值划分为很多区间,每一个区间对应一个分片(其实是chunk,后面再说);



哈希法:先根据片键值计算哈希值,然后把哈希值按范围划分,只是比范围法多了一步哈希。使用哈希法可以使得键值分布更加均匀。



3.chunk,块,理解这个概念很重要。块是比分片更小的单位,每一个shard分片都是由若干个chunk构成的,chunk有以下一些属性:

min和max,该chunk里最小和最大的片键,也就是这个chunk的数据范围,这其实是对应了我们之前说的片键区间。片键的每一个区间段都会对应一个chunk。每一个shard的配置信息就会包括其中所有的chunk块的范围,最终mongos就可以根据这些值来判定应该走哪一个切片的哪一个chunk。

maxSize,chunk大小的上限,这个和后面的内容有关,是一个阈值,会触发chunk的分割。


4.chunk分裂:

MongoDB不希望chunk块的size太大,所以一旦超过了maxSize,就会执行一次split操作,把chunk分割为几个更小的chunk。当发生insert或者update操作时,可能会除触发split操作。


5.balancer:

balancer是MongoDB里的一个后台进程,会检测每一个分片的chunk数目,一旦发现某一些分片的chunk数目太多,就会触发一次chunkMove,会把多出来的chunk移到chunk较少的分片上。每当chunk太大被分裂时,就很有可能导致某一个分片上的chunk数目变多,触发move。当我们增加或者删除shard机器时,也会导致上述move过程。

过程如下:balancer会给要迁移的shard发出一个move命令,该shard就会发送自己的数据给目标shard,目标shard就会同步数据,一旦同步完,源shard就会删除数据,最后config里面的配置信息也会被更新。

所以,MongoDB的shard集群为用户提供了一种水平扩展数据的功能,还提供了健壮性和可用性,健壮性是我们可以使用复制集技术来增加容错性,可用性是我们可以随意修改shard集群的节点,shard集群内部会做相应的balance,让每一个shard的空间都均摊所有的数据,其实这个还是很重要的,因为虽然我们可以部署很多机器,但是一旦最后的数据分布-不均匀,全部到了一台机器上,导致这个机器负载太高,装不下数据,应用肯定会挂,但是其余的机器却是空的,所以这里的balance功能非常重要。

实现思路大致是,首先保证每一个shard的chunk数目相当,但是光有这一点还不行,因为可能某一些chunk很大,所以还必须保证每一个chunk的大小均匀,这是通过split来实现,基于这两点,就可以保证每一个shard的大小相当。为什么shard的数据要以一个一个的chunk来组织?如果不以chunk来组织,那么如果要平衡数据,只能以shard为视角,把shard的一部分数据移到另一个shard,表面上好像也没什么,甚至更简单,但是实际上,比较难做到,因为当我们想把一个shard的一部分切下来时,该如何修改shard的片键范围呢?这是比较复杂的问题,切分的大小和片键的范围没有一一对应的关系,所以MongoDB就想出了让shard以chunk来做平衡的单位,每一个chunk会对应一个子区间,chunk本身有自己的大小管理,比如分裂,所以每一个shard里面的chunk基本可以认为大小一样,这样shard做平衡的依据就是chunk块的大小,如果数目差异较大,直接移动chunk即可,最后shard维护自己的片键范围也简单了很多。所以引入chunk的概念是一个很好的缓冲。

其次MongoDB的路由信息是基于范围的,这样在做balancing以后修改路由信息很简单,只需要修改shard的范围即可,如果采用除模等运算,还需要涉及一致性哈希等问题。基于范围和基于哈希函数或者除模运算的不同在于,范围的路由信息与插入的数据有关,不同的数据集可能会得到不同的范围集,是随着数据的插入而动态生成的。哈希函数这种有点静态的味道,只要给一个片值,不管有没有数据,不管其他数据如何,结果都是固定的。所以,基于范围可能在插入数据时需要维护路由信息,但是在修改时很容易,使用哈希法,虽然插入数据时不需要做事情,但是在动态修改拓扑结构以后,路由信息就会出问题。具体使用哪一个看场景看需求了,MongoDB要做balancing,所以肯定选择范围法更好。

原创粉丝点击