概述
介绍
分片(sharding)是MongoDB用来将大型集合分割到不同的服务器(或者说一个集群)上所采用的方法,尽管分片起源于关系型数据库分区,但MongoDB分片完全又是另一回事。
和MySQL分区方案相比,MongoDB的最大区别在于它几乎能自动完成所有事情,只要告诉MongoDB要分配数据,它就能自动维护数据在不同服务器之间的均衡。
分片的目的
高数据量和吞吐量的数据库会对单机的性能造成较大压力,大的查询量会将单机的CPU耗尽,大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘IO上。
为了解决这些问题,有两个基本的方法:垂直扩展和水平扩展。
垂直扩展:增加更多的CPU和存储资源来扩展容量。
水平扩展:将数据集分布在多个服务器上,水平扩展即分片。
分片设计思想
分片为应对高吞吐量与大数据提供了方法,使用分片减少了每个分片需要处理的请求数,因此,通过水平扩展,集群可以提高自己的存储容量和吞吐量,举例来说,当插入一条数据时,应用只需要访问存储这条数据的分片。
使用分片减少了每个分片存储的数据。
例如,如果数据库1TB的数据集,并有4个分片,然后每个分片可能仅持有256GB的数据。如果有40个分片,那么每个分片可能只有25GB的数据。
分片机制的三种优势
- 对集群进行抽象,让集群“不可见”。
MongoDB自带了一个叫作mongos的专有路由进程。mongos就是掌握统一路口的路由器,其会将客户端发来的请求准确无误的路由到集群中的一个或者一组服务器上,同时会把接收到的响应拼装起来发回到客户端。 - 保证集群总是可读写
MongoDB通过多种途径来确保集群的可用性和可靠性,将MongoDB的分片和复制功能结合使用,在确保数据分片到多台服务器的同时,也确保了每份数据都有响应的备份,这样就可以确保有服务器坏掉时,其他的从库可以立即接替坏掉的部分继续工作。 - 使集群易于扩展
当系统需要跟多的空间和资源的时候,MongoDB使我们可以按需方便的扩充系统容量。
分片集群架构节点
组件 | 说明 |
---|---|
Config Server | 存储集群所有节点、分片数据路由信息。默认需要配置3个Config Server节点。 |
Mongos | 提供对外应用访问,所有操作均通过mongos执行,一般有多个mongos节点。 |
Mongod | 存储应用数据记录,一般有多个Mongod节点,达到数据分片目的。 |
集群架构图
- mongos
数据路由,与客户端打交道的模块,mongos本身没有任何数据,它也不知道该怎么处理这数据,去找config server。 - config server
所以shard节点的信息、存储数据的方式,分片功能的一些配置信息,可以理解为真实数据的元数据。 - shard
真正的数据存储位置,以chunk为单位存储数据。
chunk(数据块)是什么
在一个shard server内部,MongoDB还是会把数据分为chunks,每个chunks代表这个shard server内部一部分数据。chunk的产生,会有以下两个用途:
- Splitting:当一个chunk的大小超过配置中的chunk size是,MongoDB的后台进程会把这个chunk切分成更小的chunk,从而避免chunk过大的情况。
- Balancing:在MongoDB中,balancer(平衡器)是一个后台进程,负责chunk的迁移,从而均衡各个shard server的负载,系统初始1个chunk,chunk size默认值64M,生产库上选择适合业务的chunk size是最好的。mongoDB会自动拆分和迁移chunks。
分片集群节点的数据分布
- 使用chunk来存储数据。
- 集群搭建完成后,默认开启一个chunk,大小是64M。
- 存储需求超过64M,chunk会进行分裂,如果单位时间存储需求很大,设置更大的chunk。
- chunk会被自动均衡迁移。
如何选择chunksize
小的chunksize:数据均衡是迁移速度快,数据分布更均匀,数据分裂频繁,路由节点消耗更多资源。
大的chunksize:数据分裂少。数据块移动会集中消耗IO资源,chunk通常设置在100-200M。
适合业务的chunksize是最好的,一般默认就好;
chunk的分裂和迁移非常消耗IO资源;
chunk分裂的时机:在插入和更新时,读数据不会分裂。
chunk分裂及迁移
随着数据的增大,其中的数据大小超过了分配中的chunk size,默认是64M,则这个chunk就会分裂成两个。
这时候,各个shard上的chunk数量就会不平衡。这时候,mongos中的一个组件balancer就会执行自动平衡,把chunk从chunk数量最多的shard节点挪到到数量最小的节点。
chunkSize对分裂及迁移的影响
- MongoDB默认的chunkSize为64MB,如无特殊需求,建议保持默认值;chunkSize会直接影响到chunk分裂、迁移的行为。
- chunkSize越小,chunk分裂及迁移越多,数据分布越均衡;反之,chunkSize越大,chunk分裂及迁移会更少,但可能导致数据分布不均匀。
- chunk自动分裂只会在数据写入时触发,所以如果将chunkSize改小,系统需要一定的时间来将chunk分裂到指定的大小。
- chunk只会分裂,不会合并,所以即使将chunkSize改大,现有的chunk数量不会减少,但chunk大小会随着写入不断增长,直到达到目标大小。
shard key分片键
MongoDB中数据的分片是,以集合为基本单位的,集合中的数据通过片键(shard key)被分成多部分。其实片键就是在集合中选一个键,用该键的值作为数据拆分的依据。
所以一个好的片键对分片至关重要,片键必须是一个索引。
对集合进行分片时,你需要选择一个片键,片键是每条记录都必须包含的,且建立了索引的单个字段或复合字段,MongoDB按照片键将数据划分到不同的数据块中,并将数据块均衡地分布到所有分片中。
分片键策略
- 一个自增的片键对写入和数据均匀分布就不是很好。因为自增的片键总会在一个分片上写入,后续达到某个阈值可能写到别的分片,但是按照片键查询会非常高效。
- 随机片键对数据的均匀分布效果很好。注意尽量避免在多个分片上进行查询,在所有分片上查询,mongos会对结果进行归并排序。
- MongoDB使用基于范围的分片方式或者基于hash的分片方式。
- 注意事项:
- 分片键是不可变的。
- 分片键必须有索引。
- 分片键大小限制512bytes。
- 分片键用于路由查询。
- 键的文档(分片键字段不支持空值插入)。
基于范围的分片方式
Sharded Cluster支持将单个集合的数据分散存储到多shard上,用户可以指定根据集合内文档的某个字段即shard key来进行范围分片(range sharding)。
对于基于范围的分片,MongoDB按照片键的范围把数据分成不同部分。
假设有一个数字的片键:想象一个从负无穷到正无穷的直线,每一个片键的值都在直线上画一个点。MongoDB把这条直线划分为更短的步重叠的片段,并称之为数据块,每个数据块包含了片键在一定范围内的数据。在使用片键做范围划分的系统中,拥有“相近”片键的文档很可能存储在同一个数据块中,因此也会存储在同一个分片中。
基于哈希的分片方式
分片过程中利用哈希索引作为分片的单个键,且哈希分片的片键只能使用一个字段,而基于哈希片键最大的好处就是保证数据在各个节点分片基本均匀。
对于基于哈希的分片,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块。在使用基于哈希分片的系统中,“相近”片键的文档很可能不会存储在同一个数据块中,因此数据的分离性更好一些。
Hash分片与范围分片互补,能将文档随机的分散到各个chunk中,充分的扩展写能力,弥补了范围分片的不足,但不能高效的服务范围查询,所有的范围查询,要分发到后端所有的shard,才能找出满足条件的文档。
分片集群部署的常见错误
- 配置可复制集作为分片节点与配置单独使用的可复制集基本一样。但启动参数需要指定–shardsvr参数。否则,在启动数据库分片时报错:{“code”:193,“ok”:0,“errormsg”:“Cannot accept sharding commands if not started with --shardsvr”}。
- 分片不会默认生成,需要现在数据库中启动分片(sh.enableSharding{“DBName”}),然后再设置集合分片(sh.shardCollection(“Collection”{片键}))。