Mongodb复制集和分片
1、复制集
MongoDB为了保证数据的完整性,提出了复制集的概念(replica set),它通过数据的冗余备份备份的方式,在多个服务器上存储数据副本,避免了单点故障的问题,提高了数据的可用性,保证了数据的安全性,同时还允许从硬件故障和服务中断中恢复数据。
1.1 复制集成员
MongoDB的复制集是由一组mongod实例所组成的,并提供了数据冗余与高可用性。复制集中的成员有以下几种:
Primary:主节点,负责接收所有的写操作,通知从节点的数据变动情况。
Secondaries:从节点,响应主节点的数据变动情况,保持其数据集与主节点的一致。
arbiter:仲裁节点,仲裁节点其本身并不包含数据集。但是,一旦当前的主节点不可用时,投票节点就会参与到新的主节点选举的投票中。
备注:当节点数目为奇数时,可以不需要仲裁节点。节点数目为偶数个时,需要部署一个仲裁节点,否则偶数个节点,当主节点挂了后,可能会出现两个从节点得票相同的情况,无法选举出主节点。
主节点是复制集成员中唯一能够接收写操作的节点,并记录操作日志(oplog)。然后从节点会根据操作日志来同步自己节点的数据保持与主节点一致。集群中所有的成员都会发送心跳(Heartbeat,其实就是ping)给对方,感知彼此之间是否一直在线。
1.2 操作日志
操作日志(oplog)oplog是capped collection,因为oplog的特点(不能太多把磁盘填满了,固定大小)需要,MongoDB才发明了capped collection(the oplog is actually the reason capped collections were invented),oplog位于local库中。复制集中的所有成员在local库中都能找到这local.oplog.rs这个集合。
在64位版本中,不管当前MongoDB的数据存储引擎是什么,oplog的默认大小都是192MB[l1] 。有时候为了应付更大的数据量,启动时可以使用oplogSizeMB参数来指定操作日志集合的大小。修改操作日志大小必须要重启复制集,并且要将复制集主节点变更为从节点后才能重启,这样做的目的是为了保持数据集中的数据一致。重启后,可以重新制定oplogSizeMB参数大小。切换到local数据库后,可以使用rs.printReplicationInfo()来查看当前操作日志的信息。
1.3数据同步
为了保证从节点的数据实时同步,MongoDB主从节点数据同步由两部构成:初始化同步和实时备份。当复制集添加新的成员时,初始化同步保证了从节点的数据能够从复制集的其他节点完整的复制过来;当复制集的数据量不停增长时,实时备份保证了急群众各个节点的数据一致性。
备注:经过实践发现,MongoDB下的local库下的集合并不会参与数据同步。
1.4复制集部署
1.4.1部署主节点
a)启动主节点mongod进程
mongod --replSet replication_db_set --dbpath ./replication_db_primary --bind_ip 10.171.60.150 --port 27017
b)使用mongo连接主节点,初始化复制集
mongo 10.171.60.150:27017
> rs.initiate()
初始化后,当前节点会成为主节点,如下所示:
> replication_db_set:PRIMARY>
1.4.2部署从节点
a)启动从节点mongod
mongod --replSet replication_db_set --dbpath ./replication_db_second --bind_ip 10.171.60.150 --port 27018
b)使用mongo连接主节点,添加从节点
replication_db_set:PRIMARY> rs.add("10.171.60.150:27018")
这时候使用mongo连接从节点,可以发现命令提示符变成了:replication_db_set:SECONDARY>
1.4.3添加仲裁节点
a)启动仲裁节点mongod
mongod --replSet replication_db_set --dbpath ./replication_db_second --bind_ip 10.171.60.150 --port 27019
b)使用mongo连接主节点,添加仲裁节点
replication_db_set:PRIMARY> rs.addArb("10.171.60.150:27019")
2、分片
随着MongoDB存储的数据量不断的增长,CPU、内存和磁盘IO的负载将会越来越高,从而导致性能下降。为了解决这个问题,MongoDB提出了分片(Sharding)的概念。分片的基本思想就是把集合切割成若干小的数据块块,这些数据块分布的洒在集群中各个主机上。分片对于应用而言其实是屏蔽的,应用不必关心数据时如何存储的,因为在分片模式下,MongoDB会使用路由进程(Mongos进程)来管理分片数据的分布,所以应用只需要范围路由进程就可以了。MongoDB只支持集合(collection)级别的分片,并需要从集合中选取一个键来作为数据拆分的依据,这个键即为片键。片键这个概念后续会详细介绍。
2.1分片集群成员
Shard:分片是存储了一个集合部分数据的MongoDB实例,每个分片是单独的mongod或者是复制集(replica set)。实际应用场景中,所有的分片都应该是复制集。
mongos:mongos是数据库集群请求的路由,所有的请求都通过mongos进行。它负责把对应的数据请求请求转发到对应的分片服务器上。实际应用场景中,分片集群可以考虑部署多个mongos作为请求的入口,防止其中一个挂掉所有的mongodb请求都没有办法操作。
Config Servers:配置服务器,存储所有数据库元信息:路由(mongos)、分片(shard)的配置。mongos本身没有物理存储分片服务器和数据路由信息,只能存储在配置服务器上。mongos第一次启动或者关掉重启就会从配置服务器加载配置信息,配置服务器信息变化会通知到所有的路由更新自己的状态。实际应用场景中,,通常会部署多个配置服务器,因为它存储了分片路由的元数据,就算其中一台意外宕机,只要还有配置服务器正常工作, mongodb分片集群就不会挂掉。
2.2片键和数据块
MongoDB会选择文档中的一个或多个Field来作为片键(Shard key),根据片键的值来分割集合中的文档,形成一个个的数据块(Chunk),然后再将这个数据块平均分配到集群中的各个分片上。一个数据块存放片键的一个区间范围的数据。选择一个好的分片字段非常重要,否则就会遭遇到不能被拆分的大Chunk。
2.2.1基于片键值范围的分片
基于范围的分片,MongoDB按照片键的范围把数据分成不同部分。就如同坐标轴中的X轴一样,MongoDB会根据片键来划分一定的数据范围,这个范围内的数据就是数据库(Chunk)。
2.2.2基于片键哈希的分片
基于哈希的分片,MongoDB计算一个片键的哈希值,并用这个哈希值来创建数据块。在使用基于哈希分片的系统中,拥有“相近”片键的文档很可能不会存储在同一个数据块中,因此数据的分散性更好一些。
2.2.3范围和哈希分片方式对比
基于范围的分片方式提供了更高效的范围查询,给定一个片键的范围,分发路由可以很简单地确定哪个数据块存储了请求需要的数据,并将请求转发到相应的分片中。不过基于范围的分片会导致数据在分布不均衡。如果片键所在的字段是线性增长的,一定时间内的所有请求都会落到某个固定的数据块中,最终导致分布在同一个分片中。在这种情况下,一小部分分片承载了集群大部分的数据形成了数据倾斜。
与此相比,基于哈希的分片方式以范围查询性能的损失为代价,保证了集群中数据的均衡。哈希值的随机性使数据随机分布在每个数据块中,因此也随机分布在不同分片中。但是也正由于随机性,一个范围查询很难确定应该请求哪些分片,通常为了返回需要的结果,需要请求所有分片。
2.3数据倾斜
新数据的加入或者新分片的加入可能会导致集群中数据的倾斜,即表现为有些分片保存的数据块数目显著地大于其他分片保存的数据块数。作为片键的Field值如果是单调递增或者递减的话,入库时MongoDB会将这些文档划分到同一个Chunk中,如此就会失去分布式的优势,集群所有的读写操作都会集中在这个分片上。
2.3.1数据块的切分
MongoDB数据块默认大小为64MB,可以通过连接到配置服务器,通过db.settings.save( { _id:"chunksize", value:
1数据块大小较小时可以使得分片间的数据更均衡,但是会造成频繁的迁移,会增加mongos路由的负载。
2数据块大小较大时会使得均衡较少,这从网络传输与mongos的角度来说更高效,但是,这种高效是通过数据不均衡的加重为代价的。大部分应用场景下,可以稍微牺牲一点均衡,来避免集群中数据块频繁地分裂和迁移。
2.3.2数据块分裂
分裂是MongoDB避免数据块过度增长的一种方式。当数据块的大小超过配置大小时,数据块就会根据片键分裂成多个数据块。但是分裂会导致整个集群中每个分片的数据块数不一致,新的数据插入或者更新时,会造成整个集群的数据负载不均衡。这个时候需要迁移数据块来保证集群的负载均衡。
2.3.3数据块迁移
随着数据的增长,集群中的数据块会分裂得越来越多。这时候,各个分片上的数据块数量就会不平衡。这时候,路由mongos中的一个组件balancer就会执行自动平衡。把数据块从数量最多的分片节点挪动到数量最少的节点。
2.3.4不可切分的数据块
不可切分的数据块一般是由于片键的选择不合理导致的,片键对应的值的变化范围太小,导致切分的数据块对应的范围很小或者就只有一个值,这样的话就会造成集群中一个分片只对应了一个数据块。应该选取值范围变化较大的Field作为片键,或者使用组合Field作为片键。
2.4分片集群部署
在部署集群分片时,所有的集群成员分片、mongos路由和配置服务器都要使用冗余备份,避免单点故障。其中分片节点和配置服务器节点以复制集(replica set)方式实现冗余备份;mongos路由可以使用多个实例方式实现冗余备份。如下示例展示了如何部署分片集群。
2.4.1部署配置服务器
mongod --dbpath /mongodb_workspace/sharding_db/sharding_config_db --bind_ip 10.171.60.150 --port 17020
备注:这里简单实例只启动了一个配置服务器实例,并且未使用复制集冗余备份,会存在单点故障的问题。
2.4.2部署mongos路由
mongos.exe --configdb 10.171.60.150:17020 --port 17021
备注:这里启动了一个路由,一般情况下推荐在不同的机器上部署多个mongos路由。依赖的配置服务器这里也只部署了一个,如果10.171.60.150:17020未采用复制集方式部署,会存在单点故障问题,可以同时启动多个配置服务器,在启动mongos路由时,指定多个配置服务器,中间以”,”分隔。
2.4.3部署Shard分片
a)部署分片
mongod --dbpath /mongodb_workspace/sharding_db/sharding_db_1 --bind_ip 10.171.60.150 --port 17022
mongod --dbpath /mongodb_workspace/sharding_db/sharding_db_2 --bind_ip 10.171.60.150 --port 17023
b)注册分片
使用mongo命令连接到mongos路由
mongo 10.171.60.150: 17021
在命令提示符中添加分片到mongos路由
mongos> sh.addShard("10.171.60.150:17022")
mongos> sh.addShard("10.171.60.150:17023")
备注:这里部署的分片没有使用复制集方式部署,在实际应用场景中,对应的每个分片应当使用复制集方式复制,避免故障问题。使用复制集方式部署时,向mongos路由注册信息时,应加上复制集名称并跟上复制集主节点的ip和端口。例如“replication_db_set/10.171.60.150:27017”, replication_db_set为复制集名称,10.171.60.150:27017为复制集主节点实例。
2.4.4开启分片功能
分片集群部署完成之后并不知道如何分片,也不知道对哪个数据库进行分片,更不知道对哪个集合进行分片。这个时候需要手动指定分片的数据库和集合。
a)为指定的数据块开启分片功能
连接到mongos路由
mongo 10.171.60.150: 17021
在命令提示符中执行如下命令,开启数据块分片功能,其中
mongos> sh.enableSharding("
b)为指定的集合开启分片功能
连接到mongos路由
mongo 10.171.60.150: 17021
mongos>sh.shardCollection("
备注:开启集合分片功能需要指定分片的片键。如果该集合已经存在,需要确认分片的片键是否已经构建过索引,如果没有,需要构建索引后才能进行分片。如果该集合不存在,则可以直接指定片键进行分片。如上
我自己新建了一个Replication Set,发现默认大小5622.878319740295MB,并未做任何修改。
- 点赞
- 收藏
- 关注作者
评论(0)