uncategorized

Sharding In MongoDB

MongoDB

当数据量变得巨大,服务器无法容纳更多数据,或者大量的数据库操作让机器不堪重负时,有两种解决思路:垂直扩展和水平扩展。

  1. 垂直扩展:增强服务器的能力,例如使用更强的CPU,添加更多内存,增加硬盘。由于技术和钱的限制,这些硬件不能无限制增加,或者不划算。
  2. 水平扩展:通过增加服务器的数量来增强整体的服务能力:把数据存储压力和数据操作压力分散到各个服务器上,通过增加服务器数量就能轻易扩展服务能力。代价就是大大增加了复杂性,给开发、维护带来了不便。

MongoDB中的分片(Sharding)就是这种水平扩展的方式的实现。

Shard

每一个Shard存储了被分片数据集合的一个子集,每个Shard可以部署为副本集。

Primary Shard

PrimaryShard上面存储数据库中未分片的数据集合。创建数据库时,mongos选择拥有最少数据的shard为该数据库的PrimaryShard。

Mongos

Mongos扮演路由角色:把应用的请求分配到对应shard上面,并整合各shard返回的数据。

Sorting

如果查询不需要排序,mongos轮流从各shard取数据。

Limit

如果查询使用了limit方法限制数据返回条数,mongos对各shard应用同样的limit参数,整合数据后再次应用limit方法。

Skips

如果查询使用了skip方法,mongos无法对shard使用skip方法,只能整合数据后再使用skip方法。
如果skip方法和limit联合使用,对各shard应用的limit方法的参数会加上skip方法的参数。

Broadcast vs. Targeted

如果mongos不能决定查询应该应用到某个/某些shard上面,它就会给所有shard发送查询请求,反之mongos只发送查询给目标shard,效率比广播高。

Config Servers

ConfigServers保存集群的配置信息和元数据。由于元数据反映了集群所有组件的组织结构和状态,数据丢失后果严重,所以它必须被配置为副本集以保证其高可用性。

  • mongos从ConfigServers中读取数据缓存,并根据此数据路由查询请求。
  • ConfigServers保存认证配置信息,如RBAC。
  • ConfigServers被用来管理分布式锁。
  • 每个集群有自己的ConfigServers,不能与其他集群共享。

ReplicaSet ConfigServers

ConfigServers的副本集需要满足以下条件:

  • 没有Arbiter(仲裁者)
  • 没有DelayedMember(延迟成员)
  • 必须建立索引(buildIndexes:true)

Read Write on ConfigServers

ConfigServers包含admin database, 和config database。

  • admin database保存认证与授权相关数据,和system.*等内部使用的collections。
  • config database保存了各shard的元素据。

ShardKey

ShardKey决定文档在集群中的分布,是存在于每一个文档上的索引或组合索引。
ShardKey在分片后不可以更改,不能修改ShardKey字段的值。

Shard Key Specification

sh.shardCollection(<database>.<collection>, { <field>: 'hashed' })

Shard Key Indexes

  • 所有分片集合必须包含支持ShardKey的索引
  • 如果集合为空,sh.shardCollection()会为shard key创建索引。
  • 如果过集合不为空,必须手动为shard key创建索引。

Unique Indexes

  • 不能给hashed index添加唯一性约束。
  • Ranged sharded collections中只有shard key上的索引或以shard key为前缀的组合索引可以有唯一性约束。
  • 如果collection其它键上有唯一性约束,则这个collection不能被分片。
  • 对已经分片的collection,不能在其它键上建立唯一性索引。
  • 开启集群内的唯一性约束:在sh.shardCollection()中传入{unique: true}参数。

Choosing a Shard Key

ShardKey的选择影响数据块的创建和分布,影响集群的效率和性能。理想的ShardKey应该能使数据块均匀的分布在Shards上面。
在选择ShardKey时,至少应该考虑三个方面:cardinality, frequency, and monotonically。

Shard Key Cardinality

如果一个collection中,shard key的值的集合的基数很小,那么数据块不能较为均匀的分布,当shard数量大于shardkey的基数时,集群失去了水平扩展性。
如果需要使用基数很低的字段作为shardkey,应该考虑结合基数较高的字段组成组合索引。

Shard Key Frequency

如果一个collection中,shard key的值高度集中,某些值对应许多文档,而其他值对应少量文档,那么高频值所在的shard将成为集群的性能瓶颈,它会削弱甚至消除集群的水平可扩展性。
如果需要使用高频字段作为shardkey,应该考虑结合低频的字段组合成组合索引。

Monotonically Changing Shard Keys

如果shardkey对应的字段值总是单调地变化,那么新增的元素总是会被添加到同一个shard上面,不能均匀地分布数据。不单调的shardkey也不能保证均匀的分配数据。
如果需要单调变化的字段作为shardkey,应该考虑使用哈希索引(Hashed Index)。

Hashed Sharding

哈希分片使用哈希索引来划分数据。哈希索引计算单个字段的哈希值,并以此值作为shardkey。
哈希分片提供了更加均匀的数据分布,代价是大多数查询都需要广播,降低了查询效率。
字段值很接近的数据很可能并不在同一个shard上面,因此查询更加倾向于广播;相等匹配可以计算出特定shard,范围匹配则不行。
哈希索引会将浮点数截取为64bit整数再计算哈希值,为了避免冲突,不应该把值为浮点数的字段作为哈希索引

Ranged Sharding

RangedSharding把数据按shardkey的值分为连续的范围。shardkey相近的文档基本在同一个shard上面,这对查询连续范围内的文档很有帮助,然而如果shardkey选择的不好,效率也会下降。
满足以下条件的字段适合作为shardkey:

  • 高基数High Cardinality
  • 低频Low Frequency
  • 非单调变化Non-Monotonically

Zones

区域(Zones)是一种定义在Collection上的分割数据的方法:定义一个区域A,并指定A中shardKey的范围。

  • 如果数据的shardKey在A指定范围,那么数据就属于A区域。
  • Zone可以定义多个shardKey区间,区间之间不能重叠。
  • 定义在同一个collection上的Zone的区间不能重叠。
  • Shard和zone是多对多的关系。
  • 属于某个Zone的数据会存储/迁移到包含这个Zone的Shard上。

Zone的常见应用场景:

  • 根据shard所在的地理位置划分数据,使得数据离它的所属用户更近,从而提高查询性能。
  • 根据shard的硬件性能划分数据,使得常用数据在高性能shard上面,从而从整体上提高查询效率。
  • 根据不同用户、不同应用划分数据,以便根据用户、应用来优化调整服务器资源。
  • 总之,通过各种维度的数据划分来提高查询性能,提供更强大的服务。

Chunk

MongoDB通过shardKey把数据标注为连续的数据块(Chunk),每个Chuck是整个数据集的一个子集。MongoDB通过合理的分布这些数据块,使得数据尽可能均匀的分布到各Shard上面。

Balancer

Balancer在后台监视各个shards的数据块的数量,当某个shard的数据块的数量超过另一个shard,并且这个差值大于一定阈值时,Balancer会尝试迁移数据块,使各个shard重新达到平衡状态。
Balancer运行在ConfigServers的Primary节点上面,它对应用层来说是透明的。

Chunk Migration Procedure

  1. Balancer发送moveChunk命令给源分片。
  2. 源分片通过内部命令moveChunk开始迁移目标数据块到目标分片。在此过程中,对目标数据块内数据的操作在源分片上处理。
  3. 目标分片开始建立源分片有的而目标分片没有的索引。
  4. 目标分片从源分片复制目标数据块。
  5. 数据块的最后一个文档复制完成时,目标分片开始一个同步过程,保证迁移过程中对目标数据块的改变也要应用到目标分片上的数据块。
  6. 当同步完全完成时,源分片链接ConfigServers,更新集群的元数据,即更新目标数据块在集群中的位置。
  7. 当元数据更新完成,且当该数据块上不存在未关闭的游标时,源分片删除该数据块。
Share