一、分布式集群搭建方案
运用MongoDB的复制集(Replica Sets)+分片(Sharding)就能实现MongoDB分布式高可用的集群。分片(sharding)能够增加更多的机器来应对不断增加的负载和数据,也不影响应用。复制集(Replica Sets)能确保每个分片节点都具有自动备份、自动故障恢复能力。
二、MongoDB的高可用集群配置
高可用集群,即High Availability Cluster,简称HA Cluster。集群(cluster)就是一组计算机,它们作为一个整体向用户提供一组网络资源。这些单个的计算机系统就是集群的节点(node)。搭建高可用集群需要合理的配置多台计算机之间的角色,数据恢复,一致性等,主要有以下几种方式:
(1)、主从方式
(2)、双机双工方式
(3)、集群工作方式(多服务器互备方式)
MongoDB集群配置的实践也遵循了这几个方案,主要有主从结构,副本集方式和Sharding分片方式。
三、Master-Slave主从结构
主从架构一般用于备份或者读写分离,一般有一主一从和一主多从设计。
由两种角色构成:
(1)、Master
可读可写,当数据有修改的时候,会将oplog同步到所有Slave上。
(2)、Slave
只读不可写,自动从Master同步数据。
特别的,对于Mongodb来说,并不推荐使用Master-Slave架构,因为Master-Slave其中Master宕机后不能自动恢复,除非Replica的节点数超过50,才需要使用Master-Slave架构,正常情况是不可能用那么多节点的。
还有一点,Master-Slave不支持链式结构,Slave只能直接连接Master。Redis的Master-Slave支持链式结构,Slave可以连接Slave,成为Slave的Slave。
四、Relica Set副本集方式
Mongodb的Replica Set即副本集方式主要有两个目的,一个是数据冗余做故障恢复使用,当发生硬件故障或者其它原因造成的宕机时,可以使用副本进行恢复。
另一个是做读写分离,读的请求分流到副本上,减轻主(Primary)的读压力。
1.Primary和Secondary搭建的Replica Set
Replica Set是mongod的实例集合,它们有着同样的数据内容。包含三类角色:(1)主节点(Primary)
接收所有的写请求,然后把修改同步到所有Secondary。一个Replica Set只能有一个Primary节点,当Primary挂掉后,其他Secondary或者Arbiter节点会重新选举出来一个主节点。默认读请求也是发到Primary节点处理的,需要转发到Secondary需要客户端修改一下连接配置。
(2)副本节点(Secondary)
与主节点保持同样的数据集。当主节点挂掉的时候,参与选主。
(3)仲裁者(Arbiter)
不保有数据,不参与选主,只进行选主投票。使用Arbiter可以减轻数据存储的硬件需求,Arbiter跑起来几乎没什么大的硬件资源需求,但重要的一点是,在生产环境下它和其他数据节点不要部署在同一台机器上。
(4)选主过程其中Secondary宕机,不受影响,若Primary宕机,则进行重新选主:
2.使用Arbiter搭建Replica Set
偶数个数据节点,加一个Arbiter构成的Replica Set方式:
>>Sharding分片技术
当数据量比较大的时候,我们需要把数据分片运行在不同的机器中,以降低CPU、内存和IO的压力,Sharding就是数据库分片技术。
MongoDB分片技术类似MySQL的水平切分和垂直切分,数据库主要由两种方式做Sharding:垂直扩展和横向切分。
垂直扩展的方式就是进行集群扩展,添加更多的CPU,内存,磁盘空间等。
横向切分则是通过数据分片的方式,通过集群统一提供服务:
(1)MongoDB的Sharding架构
(2)MongoDB分片架构中的角色
A.数据分片(Shards)
用来保存数据,保证数据的高可用性和一致性。可以是一个单独的mongod实例,也可以是一个副本集。
在生产环境下Shard一般是一个Replica Set,以防止该数据片的单点故障。所有Shard中有一个PrimaryShard,里面包含未进行划分的数据集合:
B.查询路由(Query Routers)
路由就是mongos的实例,客户端直接连接mongos,由mongos把读写请求路由到指定的Shard上去。
一个Sharding集群,可以有一个mongos,也可以有多mongos以减轻客户端请求的压力。
C.配置服务器(Config servers)
保存集群的元数据(metadata),包含各个Shard的路由规则。
>>Replica sets+Sharding分布式高可用集群运用MongoDB的复制集(Replica Sets)+分片(Sharding)就能实现MongoDB分布式高可用的集群。
构建一个MongoDB Sharding Cluster,需要三种角色:Shard Server
Shard Server是实际存储数据的分片,每个Shard可以是一个mongod实例,也可以是一组mongod实例构成的Replica Set。为了实现每个Shard内部的auto-failover,MongoDB 官方建议每个Shard为一组Replica Set。
Config Server
为了将一个特定的collection存储在多个shard中,需要为该collection指定一个shard key,例如{age: 1} ,shard key可以决定该条记录属于哪个chunk。Config Servers就是用来存储:所有shard节点的配置信息、每个chunk的shard key范围、chunk在各shard的分布情况、该集群中所有DB和collection的sharding配置信息。
Route Process(mongos)
这是一个前端路由,客户端由此接入,然后询问Config Servers需要到哪个Shard上查询或保存记录,再连接相应的Shard进行操作,最后将结果返回给客户端。客户端只需要将原本发给mongod的查询或更新请求原封不动地发给Routing Process,而不必关心所操作的记录存储在哪个Shard上。
Sharded cluster架构
Mongos是Sharded cluster的访问入口,强烈建议所有的管理操作、读写操作都通过mongos来完成,以保证cluster多个组件处于一致的状态。
Mongos本身并不持久化数据,Sharded cluster所有的元数据都会存储到Config Server,而用户的数据则会分散存储到各个shard。Mongos启动后,会从config server加载元数据,开始提供服务,将用户的请求正确路由到对应的Shard。
数据分布策略
Sharded cluster支持将单个集合的数据分散存储在多个shard上,用户可以指定根据集合内文档的某个字段即shard key来分布数据,目前主要支持2种数据分布的策略,范围分片(Range based sharding)或hash分片(Hash based sharding)。
范围分片
如上图所示,集合根据x字段来分片,x的取值范围为[minKey, maxKey](x为整型,这里的minKey、maxKey为整型的最小值和最大值),将整个取值范围划分为多个chunk,每个chunk(通常配置为MB)包含其中一小段的数据。
Chunk1包含x的取值在[minKey, -75)的所有文档,而Chunk2包含x取值在[-75, 25)之间的所有文档... 每个chunk的数据都存储在同一个Shard上,每个Shard可以存储很多个chunk,chunk存储在哪个shard的信息会存储在Config server种,mongos也会根据各个shard上的chunk的数量来自动做负载均衡。
范围分片能很好的满足『范围查询』的需求,比如想查询x的值在[-30, 10]之间的所有文档,这时mongos直接能将请求路由到Chunk2,就能查询出所有符合条件的文档。
范围分片的缺点在于,如果shardkey有明显递增(或者递减)趋势,则新插入的文档多会分布到同一个chunk,无法扩展写的能力,比如使用_id作为shard key,而MongoDB自动生成的id高位是时间戳,是持续递增的。
Hash分片
Hash分片是根据用户的shard key计算hash值(bit整型),根据hash值按照『范围分片』的策略将文档分布到不同的chunk。
Hash分片与范围分片互补,能将文档随机的分散到各个chunk,充分的扩展写能力,弥补了范围分片的不足,但不能高效的服务范围查询,所有的范围查询要分发到后端所有的Shard才能找出满足条件的文档。
合理的选择shard key
选择shard key时,要根据业务的需求及『范围分片』和『Hash分片』2种方式的优缺点合理选择,同时还要注意shard key的取值一定要足够多,否则会出现单个jumbo chunk,即单个chunk非常大并且无法(split);比如某集合存储用户的信息,按照age字段分片,而age的取值非常有限,必定会导致单个chunk非常大。
Mongos
Mongos作为Sharded cluster的访问入口,所有的请求都由mongos来路由、分发、合并,这些动作对客户端driver透明,用户连接mongos就像连接mongod一样使用。
Mongos会根据请求类型及shard key将请求路由到对应的Shard
查询请求
查询请求不包含shard key,则必须将查询分发到所有的shard,然后合并查询结果返回给客户端
查询请求包含shard key,则直接根据shard key计算出需要查询的chunk,向对应的shard发送查询请求
写请求
写操作必须包含shard key,mongos根据shard key算出文档应该存储到哪个chunk,然后将写请求发送到chunk所在的shard。
更新/删除请求
更新、删除请求的查询条件必须包含shard key或者_id,如果是包含shard key,则直接路由到指定的chunk,如果只包含_id,则需将请求发送至所有的shard。
其他命令请求
除增删改查外的其他命令请求处理方式都不尽相同,有各自的处理逻辑,比如listDatabases命令,会向每个Shard及Config Server转发listDatabases请求,然后将结果进行合并。
Config Server
config database
Config server存储Sharded cluster的所有元数据,所有的元数据都存储在config数据库,3.2版本后,Config Server可部署为一个的复制集,极大的方便了Sharded cluster的运维管理。
config.shards
config.shards集合存储各个Shard的信息,可通过addShard、removeShard命令来动态的从Sharded cluster里增加或移除shard。如下所示,cluster目前拥有2个shard,均为复制集。
config.databases
onfig.databases集合存储所有数据库的信息,包括DB是否开启分片,primary shard信息,对于数据库内没有开启分片的集合,所有的数据都会存储在数据库的primary shard上。
如下所示,shtest数据库是开启分片的(通过enableSharding命令),primary shard为mongo-9003;而test数据库没有开启分片,primary shard为mongo-9003。
Sharded cluster在数据库创建时,为用户选择当前存储数据量最小的shard作为数据库的primary shard,用户也可调用movePrimary命令来改变primary shard以实现负载均衡,一旦primary shard发生改变,mongos会自动将数据迁移到的新的primary shard上。
config.colletions
数据分片是针对集合维度的,某个数据库开启分片功能后,如果需要让其中的集合分片存储,则需调用shardCollection命令来针对集合开启分片。
如下命令,针对shtest数据里的hello集合开启分片,使用x字段作为shard key来进行范围分片。
config.chunks
集合分片开启后,默认会创建一个新的chunk,shard key取值[minKey, maxKey]内的文档(即所有的文档)都会存储到这个chunk。当使用Hash分片策略时,也可以预先创建多个chunk,以减少chunk的迁移。
当chunk里写入的数据量增加到一定阈值时,会触发chunk,将一个chunk的范围为多个chunk,当各个shard上chunk数量不均衡时,会触发chunk在shard间的迁移。如下所示,shtest.coll的一个chunk,在写入数据后成3个chunk。
config.settings
config.settings集合里主要存储sharded cluster的配置信息,比如chunk size,是否开启balancer等
其他集合
config.tags主要存储sharding cluster标签(tag)相关的信息,以实现根据tag来分布chunk 的功能
config.changelog主要存储sharding cluster里的所有变更操作,比如balancer迁移chunk的动作就会记录到changelog里。
config.mongos存储当前集群所有mongos的信息
config.locks存储锁相关的信息,对某个集合进行操作时,比如moveChunk,需要先获取锁,避免多个mongos同时迁移同一个集合的chunk。
MongoDB 概念解析
通过下图实例,我们也可以更直观的了解Mongo中的一些概念:
IOPS,即I/O per second,即每秒读写(I/O)操作的次数,多用于OLTP/数据库、小文件存储等场合,衡量随机访问的性能。