分片是横跨多台主机存储数据记录的过程,它是MongoDB针对日益增长的数据需求而采用的解决方案。随着数据的快速增长,单台服务器已经无法满足读写高吞吐量的需求。分片通过水平扩展的方式解决了这个问题。通过分片,你能添加更多的机器到集群中来应对快速增长的数据存储并且满足高吞吐量读写操作。
一、分片介绍
MongoDB使用分片技术来支持大数据集和高吞吐量操作。
1、分片目的
对于单台数据库服务器,庞大的数据量及高吞吐量的应用程序对它而言无疑是个巨大的挑战。频繁的CRUD操作能够耗尽服务器的CPU资源,快速的数据增长也会让硬盘存储无能为力,最终内存无法满足数据需要导致大量的I/O,主机负载严重。为了解决这种问题,对于数据库系统一般有两种方法:垂直扩展和分片(水平扩展)。
【垂直扩展】:添加更多的CPU和存储资源来增加系统性能。这种方式缺点是:拥有大量CPU和RAM资源的高端机器比普通PC机器昂贵得太多,而且单点故障会影响整个系统的服务。
【分片】:相反地,分片将大的数据集分配到多台主机上,每个分片是一个独立的数据库,这些分片整体上构成一个完整的逻辑数据库。分片减少了每台服务器上的数据操作量,随着集群的增长,每台分片处理越来越少的数据,结果,增加了系统整体服务能力。另外,分片还减少了每台服务器需要存储的数据量。
2、MongoDB中的分片
MongoDB通过配置分片集群来支持分片,一个分片集群包括以下几个组件:分片,查询路由,配置服务器
- 分片:用来存储数据,为了提供系统可用性和数据一致性,一个生产环境的分片集群,通常每个分片是一个副本集。
- 查询路由:指客户端应用访问每个分片的路径。
- 配置服务器:存储集群的元数据,这些数据包含了集群数据集到各分片的映射关系。查询路由就是通过这些元数据到特定的分片上执行指定的数据操作。(从v3.2开始,配置服务器也可以作为副本集,但是必须使用存储引擎,反对使用3个镜像实例作为配置服务器)
3、数据划分
MongoDB的数据划分,是以集合级别为标准。分片通过shard key来划分集合数据。
- shard key:
为了对集合分片,你需要指定一个shard key。shard key既可以是集合的每个文档的索引字段也可以是集合中每个文档都有的组合索引字段。MongoDB将shard keys值按照块(chunks)划分,并且均匀的将这些chunks分配到各个分片上。MongoDB使用基于范围划分或基于散列划分来划分chunks的。
- 基于范围划分:
MongoDB通过shard key值将数据集划分到不同的范围就称为基于范围划分。对于数值型的shard key:你可以虚构一条从负无穷到正无穷的直线(理解为x轴),每个shard key 值都落在这条直线的某个点上,然后MongoDB把这条线划分为许多更小的没有重复的范围成为块(chunks),一个chunk就是就某些最小值到最大值的范围。
- 基于散列划分:
MongoDB计算每个字段的hash值,然后用这些hash值建立chunks。
- 基于范围和基于散列划分的性能比较:
基于范围划分对于范围查询比较高效。假设在shard key上进行范围查询,查询路由很容易能够知道哪些块与这个范围重叠,然后把相关查询按照这个路线发送到仅仅包含这些chunks的分片。但是基于范围划分很容易导致数据不均匀分布,这样会削弱分片集群的功能。例如当shard key是个成直线上升的字段,如时间。那么,所有在给定时间范围内的请求都会映射到相同的chunk,也就是相同的分片上。这种情况下,小部分的分片将会承受大多数的请求,那么系统整体扩展并不理想。
相反的,基于散列划分是以牺牲高效范围查询为代价,它能够均匀的分布数据,散列值能够保证数据随机分布到各个分片上。
- 使用标签来自定义数据分布
MongoDB允许DBA们通过标签标记分片的方式直接平衡数据分布策略,DBA可以创建标签并且将它们与shard key值的范围进行关联,然后分配这些标签到各个分片上,最终平衡器转移带有标签标记的数据到对应的分片上,确保集群总是按标签描述的那样进行数据分布。标签是控制平衡器行为及集群中块分布的主要方法
4、维持数据分布平衡
新加入的数据及服务器都会导致集群数据分布不平衡,MongoDB采用两种方式确保数据分布的平衡:
- 拆分
拆分是一个后台进程,防止块变得太大。当一个块增长到指定块大小的时候,拆分进程就会块一分为二,整个拆分过程是高效的。不会涉及到数据的迁移等操作。
- 平衡
平衡器是一个后台进程,管理块的迁移。平衡器能够运行在集群任何的mongd实例上。当集群中数据分布不均匀时,平衡器就会将某个分片中比较多的块迁移到拥有块较少的分片中,直到数据分片平衡为止。举个例子:如果集合users有100个块在分片1里,50个块在分片2中,那么平衡器就会将分片1中的块迁移到分片2中,直到维持平衡。
分片采用后台操作的方式管理着源分片和目标分片之间块的迁移。在迁移的过程中,源分片中的块会将所有文档发送到目标分片中,然后目标分片会获取并应用这些变化。最后,更新配置服务器上关于块位置元数据。
- 从集群中增加和删除分片
添加新分片到集群中会产生数据不平衡,因为新分片中没有块,当MongoDB开始迁移数据到新分片中时,等到数据分片平衡恐怕需要点时间。
当删除一个分片时,平衡器将会把分片中所有块迁移到另一个分片中,在完成这些迁移并更新元数据后,你就可以安全的删除分片了。
5、更多的资源
- [http://www.mongodb.com/presentations/webinar-sharding-methods-mongodb?jmp=docs]
- [http://www.mongodb.com/presentations/webinar-everything-you-need-know-about-sharding?jmp=docs]
- [http://www.mongodb.com/presentations/mongodb-time-series-data-part-3-sharding?jmp=docs]
- [http://www.mongodb.com/lp/white-paper/ops-best-practices?jmp=docs]
- [http://www.mongodb.com/lp/contact/planning-for-scale?jmp=docs]
- [https://www.mongodb.com/products/consulting?jmp=docs]
- [https://www.mongodb.com/lp/misc/quick-reference-cards?jmp=docs]
二、分片概念
1、分片集群组件
1) 分片
一个分片既可是一个副本集也可以是一台单独的mongod实例。大多数建议分片是个副本集,这样能够保证数据的冗余性和可用性。
- 主分片:每个数据库都有个主分片,所谓主分片就是数据库中拥有未被分片的集合,对于数据库,为了改变主分片,可以用movePrimary命令,这个过程需要很多时间,在期间不要访问任何的集合。
- 分片状态:你可以在shell中用sh.status()方法查看分片状态,结果中包括哪个分片是主分片及块的分布情况。
2)配置服务器
配置服务器上存储了分片集群的元数据。如果配置服务器不可用那么整个集群也不可用。
- 对配置服务器采用副本集:从V3.2版本起,默认配置服务器都是采用副本集,但是有几点限制:不能有仲裁者,不能有延迟成员,必须有索引,每个分片集群必须有自己的配置服务器,不要用相同的配置服务器在不同的分片集群上。
- 在配置服务器上读和写操作:配置服务器上存储集群元数据在config数据库中,mongo实例缓存这些数据并通过它们选择到各个shard的访问路径。配置服务器只有在元数据改变时才进行写操作,如块迁移、块分裂等,写安全级别使用majority级别。在下面情形下会进行读操作,如元数据改变了或者新实例第一次启动或某个实例重启。读安全级别使用majority。
- 配置服务器可用性:如果配置服务器副本集主库不可用并且无法选出新主,分片集群元数据变成只读。你仍然能够对分片进行读和写,但是无法进行块迁移、分离等操作直到新主产生。如果所有的config数据库都不可用,那么整个分片集群将不可用。mongos实例缓存了配置服务器的元数据,这样,如果所有配置服务器不可用,如果你没有重启mongos实例,那么这时集群仍然可以服务,如果重启了实例,将失去元数据,集群也不可用了。
所以,配置服务器上的元数据很重要,必须有备份策略。
2、分片集群架构
1)分片集群需求
MongoDB的分片集群是一个十分强大的特性,因此它的部署和维护也很复杂,只有当应用程序或者业务有需求时,才会考虑部署分片集群,否则除了增添复杂性外别无好处。
如果你的系统有下面问题,你可以考虑分片集群:
- 数据集达到或超过单台实例存储能力
- 热点数据大小超过系统最大RAM大小
- 单个mongod实例无法满足现在的写操作并且其他方法都没有效果
部署分片集群需要时间和资源,如果你的系统达到或超过它的性能,如果不影响应用程序下会很难部署分片集群的。所以,如果你需要将来分片你的数据集,不要等到你的系统超过性能那一刻。
2)生产环境集群架构
生产环境中,你必须确保数据是冗余的,系统是高可用的,为了达到这样的目标,生产环境集群必须有以下组件:
- 配置服务器
- 两个或更多的副本集作为分片
- 一个或更多的查询路由(mongos):mongos实例是查询路由,一般而言,每个应用服务器配一个mongo实例