MongoDB集群简介
mongodb 集群搭建的方式有三种:
主从(Master-Slaver) ,或者叫主从复制模式。 因为官方已经不推荐使用,并且已经在MongoDB3.6以后慢慢废弃了
工作原理:主机工作,备机处于监控准备状况;当主机宕机时,备机接管主机的一切工作,待主机恢复正常后,按使用者的设定以自动或手动方式将服务切换到主机上运行,数据的一致性通过共享存储系统解决。
副本集(Replica Set) 简单来说就是集群当中包含了多份数据,保证主节点挂掉了,备节点能继续提供数据服务,提供的前提就是数据需要和主节点一致

默认设置下,主节点提供所有增删查改服务,备节点不提供任何服务。但是可以通过设置使备节点提供查询服务,这样就可以减少主节点的压力,当客户端进行数据查询时,请求自动转到备节点上。这个设置叫做Read Preference Modes。
副本集特点
什么是副本集
一组Mongodb复制集,就是一组mongod进程,这些进程维护同一个数据集合。复制集提供了数据冗余和高等级的可靠性,这是生产部署的基础。
MongoDB 副本集是将数据同步在多个服务器的过程,复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性,同时还允许从硬件故障和服务中断中恢复数据。
副本集的目的 保证数据在生产部署时的冗余和可靠性,通过在不同的机器上保存副本来保证数据不会因为单点损坏而丢失。能够随时应对数据丢失、机器损坏带来的风险。 换一句话来说,还能提高读取能力,用户的读取服务器和写入服务器在不同的地方,而且,由不同的服务器为不同的用户提供服务,提高整个系统的负载。 副本集工作原理
一组复制集就是一组mongod实例掌管同一个数据集,实例可以在不同的机器上面。实例中包含一个主导,接受客户端所有的写入操作,其他都是副本实例,从主服务器上获得数据并保持同步。 主服务器很重要,包含了所有的改变操作(写)的日志。但是副本服务器集群包含所有的主服务器数据,因此当主服务器挂掉了,就会在副本服务器上重新选取一个成为主服务器。 每个复制集还有一个仲裁者,仲裁者不存储数据,只是负责通过心跳包来确认集群中集合的数量,并在主服务器选举的时候作为仲裁决定结果。
副本集架构
基本的架构由3台服务器组成,一个三成员的复制集,由三个有数据,或者两个有数据,一个作为仲裁者。 没有仲裁节点 具有三个存储数据的成员的复制集有:
主库宕机时,这两个从库都可以被选为主库。

当主库宕机后,两个从库都会进行竞选,其中一个变为主库,当原主库恢复后,作为从库加入当前的复制集群即可。

当存在仲裁节点 在三个成员的复制集中,有两个正常的主从,及一台arbiter节点:

说明: 由于arbiter节点没有复制数据,因此这个架构中仅提供一个完整的数据副本。arbiter节点只需要更少的资源,代价是更有限的冗余和容错。 当主库宕机时,将会选择从库成为主,主库修复后,将其加入到现有的复制集群中即可。

Primary选举 复制集通过replSetInitiate命令(或mongo shell的rs.initiate())进行初始化,初始化后各个成员间开始发送心跳消息,并发起Priamry选举操作,获得『大多数』成员投票支持的节点,会成为Primary,其余节点成为Secondary。 『大多数』的定义 假设复制集内投票成员(后续介绍)数量为N,则大多数为 N/2 + 1,当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。
| 投票成员数 | 大多数 | 容忍失效数 |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
| 6 | 4 | 2 |
| 7 | 4 | 3 |
通常建议将复制集成员数量设置为奇数,从上表可以看出3个节点和4个节点的复制集都只能容忍1个节点失效,从『服务可用性』的角度看,其效果是一样的。(但无疑4个节点能提供更可靠的数据存储) 副本集成员 Secondary 正常情况下,复制集的Seconary会参与Primary选举(自身也可能会被选为Primary),并从Primary同步最新写入的数据,以保证与Primary存储相同的数据。 Secondary可以提供读服务,增加Secondary节点可以提供复制集的读服务能力,同时提升复制集的可用性。另外,Mongodb支持对复制集的Secondary节点进行灵活的配置,以适应多种场景的需求。 Arbiter Arbiter节点只参与投票,不能被选为Primary,并且不从Primary同步数据。 比如你部署了一个2个节点的复制集,1个Primary,1个Secondary,任意节点宕机,复制集将不能提供服务了(无法选出Primary),这时可以给复制集添加一个Arbiter节点,即使有节点宕机,仍能选出Primary。 Arbiter本身不存储数据,是非常轻量级的服务,当复制集成员为偶数时,最好加入一个Arbiter节点,以提升复制集可用性。

Sharding和Replica Set类似,都需要一个仲裁节点,但是Sharding还需要配置节点和路由节点。就三种集群搭建方式来说,这种是最复杂的。 为什么Sharding会需要配置Replica Set。其实想想也能明白,多个节点的数据肯定是相关联的,如果不配一个Replica Set,怎么标识是同一个集群的呢。配置方式和之前所说的一样,定一个cfg,然后初始化配置。
略
docker pull mongo创建挂载目录
建立网络
docker network create mongo-cluster
docker network ls生成key
创建配置文件
创建三个容器
参数说明
docker run 从镜像启动一个容器
-p 30001:27017 端口映射,容器内的端口 27017 映射到本机的端口 30001
–name mongo1 给这个容器起个名字 mongo1
–net mongo-cluster 把这个容器添加到网络 mongo-cluster mongo 要使用的镜像名 mongod
–replSet mongo-repliset 容器启动后要运行的命令,执行 mongod 命令,并通过参数指定这个实 例加入名为 mongo-repliset 的复制集登录容器
注意:因为开启了认证 所以需要登录容器才能进行副本集初始化
主节点添加数据 在主节点执行下面的命令
从节点查看
停掉主节点
扩容节点
新增一个docker节点
从主节点新增节点
到新增的副本节点查看数据
缩容节点
将我们刚才添加的模拟mongo4节点删除,在主节点执行以下命令
分片(sharding)是MongoDB用来将大型集合分割到不同服务器(或者说一个集群)上所采用的方法。尽管分片起源于关系型数据库分区,但MongoDB分片完全又是另一回事。 和MySQL分区方案相比,MongoDB的最大区别在于它几乎能自动完成所有事情,只要告诉 MongoDB要分配数据,它就能自动维护数据在不同服务器之间的均衡。分片的目的 高数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大的查询量会将单机的CPU耗尽,大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘IO上。 为了解决这些问题,有两个基本的方法: 垂直扩展和水平扩展。
垂直扩展:增加更多的CPU和存储资源来扩展容量。
水平扩展:将数据集分布在多个服务器上。水平扩展即分片。
分片设计思想
分片为应对高吞吐量与大数据量提供了方法。使用分片减少了每个分片需要处理的请求数,因此,通过水平扩展,集群可以提高自己的存储容量和吞吐量。举例来说,当插入一条数据时,应用只需要访问存储这条数据的分片.
使用分片减少了每个分片存储的数据。
例如,如果数据库1tb的数据集,并有4个分片,然后每个分片可能仅持有256 GB的数据。如果有40个分片,那么每个切分可能只有25GB的数据。

分片机制的优势 分片机制提供了如下三种优势 1.自动路由 对集群进行抽象,让集群“不可见” MongoDB自带了一个叫做mongos的专有路由进程。mongos就是掌握统一路口的路由器,其会将客户端发来的请求准确无误的路由到集群中的一个或者一组服务器上,同时会把接收到的响应拼装起来发回到客户端。 2.保证高可用 保证集群总是可读写 MongoDB通过多种途径来确保集群的可用性和可靠性。将MongoDB的分片和复制功能结合使用,在确保数据分片到多台服务器的同时,也确保了每份数据都有相应的备份,这样就可以确保有服务器挂掉时,其他的从库可以立即接替坏掉的部分继续工作。 3.易于扩展 使集群易于扩展 当系统需要更多的空间和资源的时候,MongoDB使我们可以按需方便的扩充系统容量。
分片架构


mongos的路由进程进行操作。 基础组件 其利用到了四个组件:mongos,config server,shard,replica set
基础组件 其利用到了四个组件:mongos,config server,shard,replica set mongos 数据库集群请求的入口,所有请求需要经过mongos进行协调,无需在应用层面利用程序来进行路由选择,mongos其自身是一个请求分发中心,负责将外部的请求分发到对应的shard服务器上,mongos作为统一的请求入口,为防止mongos单节点故障,一般需要对其做HA(高可用,HighlyAvailable缩写)。
config server 配置服务器,存储所有数据库元数据(分片,路由)的配置。mongos本身没有物理存储分片服务器和数据路由信息,只是缓存在内存中来读取数据,mongos在第一次启动或后期重启时候,就会从config server中加载配置信息,如果配置服务器信息发生更新会通知所有的mongos来更新自己的状态,从而保证准确的请求路由,生产环境中通常也需要多个config server,防止配置文件存在单节点丢失问题。
shard 在传统意义上来讲,如果存在海量数据,单台服务器存储1T压力非常大,考虑到数据库的硬盘,网络IO,还有CPU,内存的瓶颈,如果多台进行分摊1T的数据,到每台上就是可估量的较小数据,在mongodb集群只要设置好分片规则,通过mongos操作数据库,就可以自动把对应的操作请求转发到对应的后端分片服务器上。 replica set 在总体mongodb集群架构中,对应的分片节点,如果单台机器下线,对应整个集群的数据就会出现部分缺失,这是不能发生的,因此对于shard节点需要replica set来保证数据的可靠性,生产环境通常为2个副本+1个仲裁。
仲裁者 仲裁者(Arbiter),是复制集中的一个MongoDB实例,它并不保存数据。仲裁节点使用最小的资源并且不要求硬件设备,不能将Arbiter部署在同一个数据集节点中,可以部署在其他应用服务器或者监视服务器中,也可部署在单独的虚拟机中。为了确保复制集中有奇数的投票成员(包括primary),需要添加仲裁节点做为投票,否则primary不能运行时不会自动切换primary。
仲裁节点是一种特殊的节点,它本身并不存储数据,主要的作用是决定哪一个备节点在主节点挂掉之后提升为主节点,所以客户端不需要连接此节点。这里虽然只有一个备节点,但是仍然需要一个仲裁节点来提升备节点级别。如果没有仲裁节点的话,主节点挂了备节点还是备节点,所以咱们还是需要它的。
Chunk是什么

在一个shard server内部,MongoDB还是会把数据分为chunks,每个chunk代表这个shard server内部一部分数据,chunk的产生,会有以下两个用途:
Splitting:当一个chunk的大小超过配置中的chunk size时,MongoDB的后台进程会把这个chunk切分成更小的chunk,从而避免chunk过大的情况
Balancing:在MongoDB中,balancer是一个后台进程,负责chunk的迁移,从而均衡各个shardserver的负载,系统初始1个chunk,chunk size默认值64M,生产库上选择适合业务的chunk size是最好的。mongoDB会自动拆分和迁移chunks。
chunk的特点
chunksize的选择
chunk分裂及迁移
随着数据的增长,其中的数据大小超过了配置的chunk size,默认是64M,则这个chunk就会分裂成两个。数据的增长会让chunk分裂得越来越多。
这时候,各个shard 上的chunk数量就会不平衡。这时候,mongos中的一个组件balancer 就会执行自动平衡。把chunk从chunk数量最多的shard节点挪动到数量最少的节点
chunkSize对分裂及迁移的影响
MongoDB 默认的 chunkSize 为64MB,如无特殊需求,建议保持默认值;chunkSize 会直接影响到 chunk分裂、迁移的行为。
chunkSize 越小,chunk 分裂及迁移越多,数据分布越均衡;反之,chunkSize 越大,chunk分裂及迁移会更少,但可能导致数据分布不均。 chunkSize 太小,容易出现 jumbo chunk(即shardKey的某个取值出现频率很高,这些文档只能放到一个 chunk 里,无法再分裂)而无法迁移;chunkSize 越大,则可能出现 chunk内文档数太多(chunk 内文档数不能超过 250000 )而无法迁移。
chunk 自动分裂只会在数据写入时触发,所以如果将 chunkSize 改小,系统需要一定的时间来将chunk 分裂到指定的大小。
chunk 只会分裂,不会合并,所以即使将 chunkSize 改大,现有的 chunk 数量不会减少,但chunk大小会随着写入不断增长,直到达到目标大小。
数据分片
分片键shard key

MongoDB中数据的分片是、以集合为基本单位的,集合中的数据通过片键(Shard key)被分成多部分。其实片键就是在集合中选一个键,用该键的值作为数据拆分的依据。 所以一个好的片键对分片至关重要。分片键必须是一个索引,通过 sh.shardCollection 会自动创建索引(前提是此集合不存在的情况下)。一个自增的分片键对写入和数据均匀分布就不是很好,因为自增的片键总会在一个分片上写入,后续达到某个阀值可能会写到别的分片。但是按自增键查询会非常高效。 随机片键对数据的均匀分布效果很好。注意尽量避免在多个分片上进行查询。在所有分片上查询,mongos会对结果进行归并排序。 对集合进行分片时,你需要选择一个片键,片键是每条记录都必须包含的,且建立了索引的单个字段或复合字段,MongoDB按照片键将数据划分到不同的数据块中,并将数据块均衡地分布到所有分片中。 为了按照片键划分数据块,MongoDB使用基于范围的分片方式或者 基于哈希的分片方式。
注意事项 1.分片键一经设置,不可修改,不可删除。 2.执行了数据分片操作后,均衡器会对满足条件的数据进行拆分,这将占用实例的资源,请在业务低峰期操作 3.分片键必须有索引。 4.分片键大小限制512bytes。 5.分片键用于路由查询。 6.MongoDB不接受已进行collection级分片的collection上插入分片 7.分片键不支持空值插入 分片键分类
范围分片
MongoDB按照片键的值的范围将数据拆分为不同的块(chunk),每个块包含了一段范围内的数据。
Sharded Cluster支持将单个集合的数据分散存储在多个shard上,用户可以指定根据集合内文档的某个字段即shard key来进行范围分片(range sharding)。

对于基于范围的分片,MongoDB按照片键的范围把数据分成不同部分。
哈希分片 MongoDB计算单个字段的哈希值作为索引值,并以哈希值的范围将数据拆分为不同的块。 分片过程中利用哈希索引作为分片的单个键,且哈希分片的片键只能使用一个字段,而基于哈希片 键最大的好处就是保证数据在各个节点分布基本均匀。

对于基于哈希的分片,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块。在使用基于哈希分片的系统中,拥有”相近”片键的文档很可能不会存储在同一个数据块中,因此数据的分离性更好一些。 Hash分片与范围分片互补,能将文档随机的分散到各个chunk,充分的扩展写能力,弥补了范围分片的不足,但不能高效的服务范围查询,所有的范围查询要分发到后端所有的Shard才能找出满足条件的文档。
优点:可以将数据更加均衡地分布在各Shard节点中,具备写分散性。
缺点:不适合进行范围查询,进行范围查询时,需要将读请求分发到所有的Shard节点。
什么情况下使用分片
当您遇到如下两个问题时,您可以使用Sharded cluster来解决您的问题:
如何确定容量 当需要决定使用Sharded cluster时,到底应该部署多少个shard、多少个mongos?shard、mongos的数量归根结底是由应用需求决定:
存储型 如果您使用sharding只是解决海量数据存储问题,访问并不多。 假设单个shard能存储M(1G), 需要的存储总量是N(75G),那么您可以按照如下公式来计算实际需要的shard、mongos数量:
计算型 如果您使用sharding是解决高并发写入(或读取)数据的问题,总的数据量其实很小。 您要部署的shard、mongos要满足读写性能需求,容量上则不是考量的重点。假设单个shard最大QPS(Query Per Second)为M,单个mongos最大QPS为Ms,需要总的QPS为Q。那么您可以按照如 下公式来计算实际需要的shard、mongos数量:
numberOfShards = Q/M/0.75 (假设负载水位线为75%) numberOfMongos = Q/Ms/0.75
如何选择shard key 如果sharding要同时解决上述2个问题,则按需求更高的指标来预估。以上估算是基于sharded cluster里数据及请求都均匀分布的理想情况。但实际情况下,分布可能并不均衡,为了让系统的负载分布尽量均匀,就需要合理的选择shard key。
分片类型 MongoDB Sharded cluster支持2种分片方式:
问题 上述2种分片策略都无法解决以下3个问题:
shard key取值范围太小(low cardinality),比如将数据中心作为shard key,而数据中心通常不会很多,分片的效果肯定不好。
shard key某个值的文档特别多,这样导致单个chunk特别大(及 jumbo chunk),会影响chunk迁移及负载均衡。
根据非shardkey进行查询、更新操作都会变成scatter-gather查询,影响效率。
如何评估分片 好的shard key应该拥有如下特性:
整体架构涉及到15个节点,我们这里使用Docker容器进行部署
那么我们先来总结一下我们搭建一个高可用集群需要多少个Mongo
容器部署情况 整体架构预览

启动容器 启动config-server1
启动config-server2
启动config-server3
初始化config-server 登录容器
docker exec -it config-server1 bash
mongo -port 27017执行命令 执行以下命令进行MongoDB容器的初始化
创建用户
因为我们需要对用户进行权限管理,我们需要创建用户,这里为了演示,我们创建超级用户 权限是root
由于mongos是客户端,所以我们先搭建好config以及shard之后再搭建mongos。
创建挂载目录
在同一台服务器上初始化一组分片
创建密钥文件
因为集群只需要一个密钥文件,我们可以将config-server中的密钥文件复制过来
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/shard1-server/conf/配置配置文件
启动shard1-server1
启动shard1-server2
启动shard1-server3
初始化shard1分片组
并且制定第三个副本集为仲裁节点
创建用户
查看节点信息
创建密钥文件
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/shard2-server/conf/配置配置文件
启动shard2-server1
启动shard2-server2
启动shard2-server3
初始化shard2分片组
创建用户
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/shard3-server/conf/配置配置文件
启动shard3-server1
启动shard3-server2
启动shard3-server3
初始化shard3分片组
创建用户
mongos负责查询与数据写入的路由,是实例访问的统一入口,是一个无状态的节点,每一个节点都可以从
config-server节点获取到配置信息
创建密钥文件
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/mongos-server/conf/创建配置文件
启动mongos集群 启动mongos1
启动mongos2
启动mongos3
配置mongos-server1
因为mongos是无中心的配置,所有需要每一台都需要进行分片配置
配置mongos-server2
配置mongos-server3
查看状态
配置配置文件
启动shard4-server1
启动shard4-server2
启动shard4-server3
初始化shard4分片组
创建用户
添加到mongos 要将新增节点添加到mongos中 进入容器处理
Mongodb分片集群shard节点缩容相对是比较简单的,可以利用MongoDB自身的平衡器来将预下线中的分片中存储的数据进行转移,待预下线shard节点中无任何数据库,进行下线处理。所有的下线操作通过mongos进行管理实现。 查看分片状态 查看分片集群是否开启平衡器
mongos> sh.getBalancerState();
true
删除分片 发起删除分片节点命令,平衡器开始自动迁移数据
然后在执行删除命令
查看集群状态 检查分片缩容后的分片集群状态
初始化目录脚本
生成密钥文件
创建配置文件
启动服务
初始化文件 执行下面脚本进行容器初始化
初始化分片
开启数据库分片 开启数据库分片功能,命令很简单 enablesharding(),这里我就开启test数据库。
插入一条数据
对片键的字段建立索引 分片键必须要有索引才可以,并且一个集合只能有一个分片健;
db.blog.createIndex({title:1})
db.blog.createIndex({"by":"hashed","likes":1})
db.blog.getIndexes()因为我们要对 by 分片,索引需要对 likes 字段做升序索引
指定分片键 使用如下命令可以指定分片键
查看分片状态
查看数据分布 通过该命令可以查看数据的分布
插入10000条数据
for(var i=0;i<10000;i++){db.blog.insert({ "title": "MongoDB 教程", "description": "MongoDB 是一个 Nosql 数据库", "by": "我的博客"+i, "url": "http://www.baiyp.ren", "tags": [ "mongodb", "database", "NoSQL" ], "likes": 100 })}
mongos> db.blog.count()
10001cd /tmp/mongo/conf
openssl rand -base64 90 -out ./mongo.key
chmod 600 keyfile
chown 999:999 mongo.keyvi /tmp/mongo/conf/mongodb.conf
dbpath = /data/db
port = 27017
# 设置oplog的大小
oplogSize=4096
# 最大同时连接数 默认2000
maxConns=640000
# 设置每个数据库将被保存在一个单独的目录
directoryperdb=true
bind_ip=0.0.0.0
#auth=true
# #内存限制
wiredTigerCacheSizeGB = 6
replSet=mongo-repliset
# 启用key验证
keyFile=/etc/mongo/mongo.keydocker run --net mongo-cluster --restart always --name mongo1 \
-p 30001:27017 \
-v /tmp/mongo/mongo1/data:/data/db \
-v /tmp/mongo/conf:/etc/mongo \
-v /etc/localtime:/etc/localtime \
-d mongo -f /etc/mongo/mongodb.conf
docker run --net mongo-cluster --restart always --name mongo2 \
-p 30002:27017 \
-v /tmp/mongo/mongo2/data:/data/db \
-v /tmp/mongo/conf:/etc/mongo \
-v /etc/localtime:/etc/localtime \
-d mongo -f /etc/mongo/mongodb.conf
docker run --net mongo-cluster --restart always --name mongo3 \
-p 30003:27017 \
-v /tmp/mongo/mongo3/data:/data/db \
-v /tmp/mongo/conf:/etc/mongo \
-v /etc/localtime:/etc/localtime \
-d mongo -f /etc/mongo/mongodb.conf[root@localhost.localdomain /tmp/mongo/conf]#docker exec -it mongo1 bash
root@7be6253cd72c:/#
root@7be6253cd72c:/#
root@7be6253cd72c:/# mongo -port 27017
MongoDB shell version v5.0.5
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("82487f5d-57d6-4300-b73d-9fb1f119fa6f") }
MongoDB server version: 5.0.5
================
Warning: the "mongo" shell has been superseded by "mongosh",
which delivers improved usability and compatibility.The "mongo" shell has been deprecated and will be removed in
an upcoming release.
For installation instructions, see
https://docs.mongodb.com/mongodb-shell/install/
================
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
https://docs.mongodb.com/
Questions? Try the MongoDB Developer Community Forums
https://community.mongodb.com
>
>
> rs.initiate({
... "_id" : "mongo-repliset",
... "members" :
... [
... { "_id" : 0, "host" : "mongo1:27017" },
... { "_id" : 1, "host" : "mongo2:27017" },
... { "_id" : 2, "host" : "mongo3:27017" }
... ]
... })
{ "ok" : 1 }
mongo-repliset:PRIMARY> db.hello()
{
"topologyVersion" : {
"processId" : ObjectId("65dfea43e01055fe27d50b41"),
"counter" : NumberLong(6)
},
"hosts" : [
"mongo1:27017",
"mongo2:27017",
"mongo3:27017"
],
"setName" : "mongo-repliset",
"setVersion" : 1,
"isWritablePrimary" : true,
"secondary" : false,
"primary" : "mongo1:27017",
"me" : "mongo1:27017",
"electionId" : ObjectId("7fffffff0000000000000001"),
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1709177369, 1),
"t" : NumberLong(1)
},
"lastWriteDate" : ISODate("2024-02-29T03:29:29Z"),
"majorityOpTime" : {
"ts" : Timestamp(1709177369, 1),
"t" : NumberLong(1)
},
"majorityWriteDate" : ISODate("2024-02-29T03:29:29Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2024-02-29T03:29:29.220Z"),
"logicalSessionTimeoutMinutes" : 30,
"connectionId" : 32,
"minWireVersion" : 0,
"maxWireVersion" : 13,
"readOnly" : false,
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709177369, 1),
"signature" : {
"hash" : BinData(0,"0R4uy0VjkXptQ9uFxOsVRp1ekJ0="),
"keyId" : NumberLong("7340852824084840452")
}
},
"operationTime" : Timestamp(1709177369, 1)
}[root@localhost.localdomain /tmp/mongo/conf]#docker exec -it mongo1 bash
root@7be6253cd72c:/# mongo -uroot -proot
mongo-repliset:PRIMARY> db.blog.insert({ "title": "MongoDB 教程", "description": "MongoDB 是一个 Nosql 数据库", "by": "我的博客", "url": "http://www.baiyp.ren", "tags": [ "mongodb", "database", "NoSQL" ], "likes": 100 });
WriteResult({ "nInserted" : 1 })[root@localhost.localdomain /tmp/mongo/conf]#docker exec -it mongo2 bash
mongo-repliset:SECONDARY> db.setSecondaryOk()
mongo-repliset:SECONDARY> db.blog.find().pretty();
{
"_id" : ObjectId("65dffbd95fb2f87c1658757c"),
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}docker stop mongo1
[root@localhost.localdomain /tmp/mongo/conf]#docker stop mongo1
mongo1
[root@localhost.localdomain /tmp/mongo/conf]#docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
664266bbd0de mongo "docker-entrypoint.s…" 3 hours ago Up 3 hours 0.0.0.0:30003->27017/tcp, :::30003->27017/tcp mongo3
0a5fcba70801 mongo "docker-entrypoint.s…" 3 hours ago Up 3 hours 0.0.0.0:30002->27017/tcp, :::30002->27017/tcp mongo2
[root@localhost.localdomain /tmp/mongo/conf]#
[root@localhost.localdomain /tmp/mongo/conf]#docker exec -it mongo2 bash
root@0a5fcba70801:/# mongo -uroot -proot
docker run --net mongo-cluster --restart always --name mongo4 \
-p 30004:27017 \
-v /tmp/mongo/mongo4/data:/data/db \
-v /tmp/mongo/conf:/etc/mongo \
-v /etc/localtime:/etc/localtime \
-d mongo -f /etc/mongo/mongodb.conf
[root@localhost.localdomain /tmp/mongo]#docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
074c419b8612 mongo "docker-entrypoint.s…" 8 seconds ago Up 7 seconds 0.0.0.0:30004->27017/tcp, :::30004->27017/tcp mongo4
7be6253cd72c mongo "docker-entrypoint.s…" 3 hours ago Up 10 minutes 0.0.0.0:30001->27017/tcp, :::30001->27017/tcp mongo1
664266bbd0de mongo "docker-entrypoint.s…" 3 hours ago Up 3 hours 0.0.0.0:30003->27017/tcp, :::30003->27017/tcp mongo3
0a5fcba70801 mongo "docker-entrypoint.s…" 3 hours ago Up 3 hours 0.0.0.0:30002->27017/tcp, :::30002->27017/tcp mongo2[root@localhost.localdomain /tmp/mongo]#docker exec -it mongo2 bash
root@0a5fcba70801:/# mongo -uroot -proot
mongo-repliset:PRIMARY> rs.add("mongo4:27017")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709183402, 1),
"signature" : {
"hash" : BinData(0,"L3J9VytdcJDCge3ibEc86HheWA4="),
"keyId" : NumberLong("7340852824084840452")
}
},
"operationTime" : Timestamp(1709183402, 1)
}
mongo-repliset:PRIMARY> rs.isMaster()
{
"topologyVersion" : {
"processId" : ObjectId("65dfea2efca2f2225b8e02d3"),
"counter" : NumberLong(9)
},
"hosts" : [
"mongo1:27017",
"mongo2:27017",
"mongo3:27017",
"mongo4:27017"
],
"setName" : "mongo-repliset",
"setVersion" : 3,
"ismaster" : true,
"secondary" : false,
"primary" : "mongo2:27017",
"me" : "mongo2:27017",
"electionId" : ObjectId("7fffffff0000000000000002"),
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1709183404, 1),
"t" : NumberLong(2)
},
"lastWriteDate" : ISODate("2024-02-29T05:10:04Z"),
"majorityOpTime" : {
"ts" : Timestamp(1709183404, 1),
"t" : NumberLong(2)
},
"majorityWriteDate" : ISODate("2024-02-29T05:10:04Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2024-02-29T05:10:13.578Z"),
"logicalSessionTimeoutMinutes" : 30,
"connectionId" : 56,
"minWireVersion" : 0,
"maxWireVersion" : 13,
"readOnly" : false,
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709183404, 1),
"signature" : {
"hash" : BinData(0,"i31RYOAm1tebeB4+2L43kHYpbkQ="),
"keyId" : NumberLong("7340852824084840452")
}
},
"operationTime" : Timestamp(1709183404, 1)
}mongo-repliset:SECONDARY> use test
switched to db test
mongo-repliset:SECONDARY> db.setSecondaryOk()
mongo-repliset:SECONDARY> db.blog.find().pretty();
{
"_id" : ObjectId("65dffbd95fb2f87c1658757c"),
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}
rs.remove("mongo4:27017")
mongo-repliset:PRIMARY> rs.remove("mongo4:27017")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709183879, 1),
"signature" : {
"hash" : BinData(0,"k5qRlT/aZ+KUx5TIkNiho8EKA7c="),
"keyId" : NumberLong("7340852824084840452")
}
},
"operationTime" : Timestamp(1709183879, 1)
}
mongo-repliset:PRIMARY> rs.isMaster()
{
"topologyVersion" : {
"processId" : ObjectId("65dfea2efca2f2225b8e02d3"),
"counter" : NumberLong(10)
},
"hosts" : [
"mongo1:27017",
"mongo2:27017",
"mongo3:27017"
],
"setName" : "mongo-repliset",
"setVersion" : 4,
"ismaster" : true,
"secondary" : false,
"primary" : "mongo2:27017",
"me" : "mongo2:27017",
"electionId" : ObjectId("7fffffff0000000000000002"),
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1709183879, 1),
"t" : NumberLong(2)
},
"lastWriteDate" : ISODate("2024-02-29T05:17:59Z"),
"majorityOpTime" : {
"ts" : Timestamp(1709183879, 1),
"t" : NumberLong(2)
},
"majorityWriteDate" : ISODate("2024-02-29T05:17:59Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2024-02-29T05:18:06.680Z"),
"logicalSessionTimeoutMinutes" : 30,
"connectionId" : 77,
"minWireVersion" : 0,
"maxWireVersion" : 13,
"readOnly" : false,
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709183879, 1),
"signature" : {
"hash" : BinData(0,"k5qRlT/aZ+KUx5TIkNiho8EKA7c="),
"keyId" : NumberLong("7340852824084840452")
}
},
"operationTime" : Timestamp(1709183879, 1)
}搭建ConfigServer副本集
我们先来搭建ConfigServer的副本集,这里面涉及到三个节点,我们需要创建配置文件以及启动容器
创建挂载目录
我们需要创建对应的挂载目录来存储配置文件以及日志文件
# 创建配置文件目录
mkdir -p /tmp/mongo-cluster/config-server/conf
# 创建数据文件目录
mkdir -p /tmp/mongo-cluster/config-server/data/{1..3}
# 创建日志文件目录
mkdir -p /tmp/mongo-cluster/config-server/logs/{1..3}
创建密钥文件
因为我们知道搭建的话一定要高可用,而且一定要权限,这里mongo之间通信采用秘钥文件,所以我们先进行生成密钥文件
# 创建密钥文件
openssl rand -base64 756 > /tmp/mongo-cluster/config-server/conf/mongo.key
# 设置
chmod 600 /tmp/mongo-cluster/config-server/conf/mongo.key
chown 999:999 /tmp/mongo-cluster/config-server/conf/mongo.key
创建配置文件
因为由多个容器,配置文件是一样的,我们只需要创建一个配置文件,其他的容器统一读取该配置文件即可
cat /tmp/mongo-cluster/config-server/conf/mongo.conf
# 日志文件
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
bindIp: 0.0.0.0 #绑定ip
replication:
replSetName: configsvr #副本集名称
sharding:
clusterRole: configsvr # 集群角色,这里配置的角色是配置节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径docker run --name config-server1 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/config-server:/data/configdb \
-v /tmp/mongo-cluster/config-server/data/1:/data/db \
-v /tmp/mongo-cluster/config-server/logs/1:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name config-server2 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/config-server:/data/configdb \
-v /tmp/mongo-cluster/config-server/data/2:/data/db \
-v /tmp/mongo-cluster/config-server/logs/2:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name config-server3 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/config-server:/data/configdb \
-v /tmp/mongo-cluster/config-server/data/3:/data/db \
-v /tmp/mongo-cluster/config-server/logs/3:/data/logs \
mongo --config /data/configdb/conf/mongo.confrs.initiate(
{
_id: "configsvr",
members: [
{ _id : 1, host : "config-server1:27017" },
{ _id : 2, host : "config-server2:27017" },
{ _id : 3, host : "config-server3:27017" }
]
}
)
如果出现OK表示MongoDB配置服务器已经初始化成功
> rs.initiate(
... {
... _id: "configsvr",
... members: [
... { _id : 1, host : "config-server1:27017" },
... { _id : 2, host : "config-server2:27017" },
... { _id : 3, host : "config-server3:27017" }
... ]
... }
... )
{
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(1709190408, 1),
"electionId" : ObjectId("000000000000000000000000")
},
"lastCommittedOpTime" : Timestamp(1709190408, 1)
}use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})# 创建配置文件目录
mkdir -p /tmp/mongo-cluster/shard{1..3}-server/conf
# 创建数据文件目录
mkdir -p /tmp/mongo-cluster/shard{1..3}-server/data/{1..3}
# 创建日志文件目录
mkdir -p /tmp/mongo-cluster/shard{1..3}-server/logs/{1..3}cat /tmp/mongo-cluster/shard1-server/conf/mongo.conf
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
# bindIp: 127.0.0.1 #绑定ip
replication:
replSetName: shard1 #复制集名称是 shardsvr
sharding:
clusterRole: shardsvr # 集群角色,这里配置的角色是分片节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径docker run --name shard1-server1 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard1-server:/data/configdb \
-v /tmp/mongo-cluster/shard1-server/data/1:/data/db \
-v /tmp/mongo-cluster/shard1-server/logs/1:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name shard1-server2 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard1-server:/data/configdb \
-v /tmp/mongo-cluster/shard1-server/data/2:/data/db \
-v /tmp/mongo-cluster/shard1-server/logs/2:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name shard1-server3 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard1-server:/data/configdb \
-v /tmp/mongo-cluster/shard1-server/data/3:/data/db \
-v /tmp/mongo-cluster/shard1-server/logs/3:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker exec -it shard1-server1 bin/bash
mongo -port 27017
登录后进行初始化节点,这里面arbiterOnly:true是设置为仲裁节点
#进行副本集配置
rs.initiate(
{
_id : "shard1",
members: [
{ _id : 0, host : "shard1-server1:27017" },
{ _id : 1, host : "shard1-server2:27017" },
{ _id : 2, host : "shard1-server3:27017",arbiterOnly:true }
]
}
);
显示OK即副本集创建成功use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})rs.isMaster()
shard1:PRIMARY> rs.isMaster()
{
"topologyVersion" : {
"processId" : ObjectId("65e02e0599a3a0d36aa1cec9"),
"counter" : NumberLong(7)
},
"hosts" : [
"shard1-server1:27017",
"shard1-server2:27017"
],
"arbiters" : [
"shard1-server3:27017"
],
"setName" : "shard1",
"setVersion" : 1,
"ismaster" : true,
"secondary" : false,
"primary" : "shard1-server1:27017",
"me" : "shard1-server1:27017",
"electionId" : ObjectId("7fffffff0000000000000001"),
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1709190837, 9),
"t" : NumberLong(1)
},
"lastWriteDate" : ISODate("2024-02-29T07:13:57Z"),
"majorityOpTime" : {
"ts" : Timestamp(1709190837, 9),
"t" : NumberLong(1)
},
"majorityWriteDate" : ISODate("2024-02-29T07:13:57Z")
},
"isImplicitDefaultMajorityWC" : false,
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2024-02-29T07:14:05.679Z"),
"logicalSessionTimeoutMinutes" : 30,
"connectionId" : 1,
"minWireVersion" : 0,
"maxWireVersion" : 13,
"readOnly" : false,
"ok" : 1cat /tmp/mongo-cluster/shard2-server/conf/mongo.conf
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
bindIp: 0.0.0.0 #绑定ip
replication:
replSetName: shard2 #复制集名称是 shard2
sharding:
clusterRole: shardsvr # 集群角色,这里配置的角色是分片节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径docker run --name shard2-server1 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard2-server:/data/configdb \
-v /tmp/mongo-cluster/shard2-server/data/1:/data/db \
-v /tmp/mongo-cluster/shard2-server/logs/1:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name shard2-server2 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard2-server:/data/configdb \
-v /tmp/mongo-cluster/shard2-server/data/2:/data/db \
-v /tmp/mongo-cluster/shard2-server/logs/2:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name shard2-server3 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard2-server:/data/configdb \
-v /tmp/mongo-cluster/shard2-server/data/3:/data/db \
-v /tmp/mongo-cluster/shard2-server/logs/3:/data/logs \
mongo --config /data/configdb/conf/mongo.conf docker exec -it shard2-server1 bin/bash
mongo -port 27017
#进行副本集配置
rs.initiate(
{
_id : "shard2",
members: [
{ _id : 0, host : "shard2-server1:27017" },
{ _id : 1, host : "shard2-server2:27017" },
{ _id : 2, host : "shard2-server3:27017",arbiterOnly:true }
]
}
);use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})cat /tmp/mongo-cluster/shard3-server/conf/mongo.conf
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
bindIp: 0.0.0.0 #绑定ip
replication:
replSetName: shard3 #复制集名称是 shard3
sharding:
clusterRole: shardsvr # 集群角色,这里配置的角色是分片节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径docker run --name shard3-server1 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard3-server:/data/configdb \
-v /tmp/mongo-cluster/shard3-server/data/1:/data/db \
-v /tmp/mongo-cluster/shard3-server/logs/1:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name shard3-server2 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard3-server:/data/configdb \
-v /tmp/mongo-cluster/shard3-server/data/2:/data/db \
-v /tmp/mongo-cluster/shard3-server/logs/2:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name shard3-server3 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard3-server:/data/configdb \
-v /tmp/mongo-cluster/shard3-server/data/3:/data/db \
-v /tmp/mongo-cluster/shard3-server/logs/3:/data/logs \
mongo --config /data/configdb/conf/mongo.conf docker exec -it shard3-server1 bin/bash
mongo -port 27017
#进行副本集配置
rs.initiate(
{
_id : "shard3",
members: [
{ _id : 0, host : "shard3-server1:27017" },
{ _id : 1, host : "shard3-server2:27017" },
{ _id : 2, host : "shard3-server3:27017",arbiterOnly:true }
]
}
);use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})# 创建配置文件目录
mkdir -p /tmp/mongo-cluster/mongos-server/conf
# 创建数据文件目录
mkdir -p /tmp/mongo-cluster/mongos-server/data/{1..3}
# 创建日志文件目录
mkdir -p /tmp/mongo-cluster/mongos-server/logs/{1..3}cat /tmp/mongo-cluster/mongos-server/conf/mongo.conf
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
bindIp: 0.0.0.0 #绑定ip
# 配置分片,这里面配置的是需要读取的配置节点的信息
sharding:
configDB: configsvr/config-server1:27017,config-server2:27017,config-server3:27017
security:
keyFile: /data/configdb/conf/mongo.key #keyFile路径docker run --name mongos-server1 -d \
-p 30001:27017 \
--net=mongo-cluster \
--privileged=true \
--entrypoint "mongos" \
-v /tmp/mongo-cluster/mongos-server:/data/configdb \
-v /tmp/mongo-cluster/mongos-server/logs/1:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name mongos-server2 -d \
-p 30002:27017 \
--net=mongo-cluster \
--privileged=true \
--entrypoint "mongos" \
-v /tmp/mongo-cluster/mongos-server:/data/configdb \
-v /tmp/mongo-cluster/mongos-server/logs/2:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name mongos-server3 -d \
-p 30003:27017 \
--net=mongo-cluster \
--privileged=true \
--entrypoint "mongos" \
-v /tmp/mongo-cluster/mongos-server:/data/configdb \
-v /tmp/mongo-cluster/mongos-server/logs/3:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker exec -it mongos-server1 /bin/bash
mongo -port 27017
登录Mongos
use admin;
db.auth("root","root");
配置分片
sh.addShard("shard1/shard1-server1:27017,shard1-server2:27017,shard1-server3:27017")
sh.addShard("shard2/shard2-server1:27017,shard2-server2:27017,shard2-server3:27017")
sh.addShard("shard3/shard3-server1:27017,shard3-server2:27017,shard3-server3:27017")docker exec -it mongos-server2 /bin/bash
mongo -port 27017
登录Mongos
use admin;
db.auth("root","root");
配置分片
sh.addShard("shard1/shard1-server1:27017,shard1-server2:27017,shard1-server3:27017")
sh.addShard("shard2/shard2-server1:27017,shard2-server2:27017,shard2-server3:27017")
sh.addShard("shard3/shard3-server1:27017,shard3-server2:27017,shard3-server3:27017")docker exec -it mongos-server3 /bin/bash
mongo -port 27017
登录Mongos
use admin;
db.auth("root","root");
配置分片
sh.addShard("shard1/shard1-server1:27017,shard1-server2:27017,shard1-server3:27017")
sh.addShard("shard2/shard2-server1:27017,shard2-server2:27017,shard2-server3:27017")
sh.addShard("shard3/shard3-server1:27017,shard3-server2:27017,shard3-server3:27017")mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("65e02d139d6b86c251f4b918")
}
shards:
{ "_id" : "shard1", "host" : "shard1/shard1-server1:27017,shard1-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191698, 2) }
{ "_id" : "shard2", "host" : "shard2/shard2-server1:27017,shard2-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191701, 2) }
{ "_id" : "shard3", "host" : "shard3/shard3-server1:27017,shard3-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191704, 2) }
active mongoses:
"5.0.5" : 3
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: yes
Collections with active migrations:
config.system.sessions started at Thu Feb 29 2024 07:31:40 GMT+0000 (UTC)
Failed balancer rounds in last 5 attempts: 0
Migration results for the last 24 hours:
55 : Success
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 969
shard2 27
shard3 28
too many chunks to print, use verbose if you want to force print# 创建配置文件目录
mkdir -p /tmp/mongo-cluster/shard4-server/conf
# 创建数据文件目录
mkdir -p /tmp/mongo-cluster/shard4-server/data/{1..3}
# 创建日志文件目录
mkdir -p /tmp/mongo-cluster/shard4-server/logs/{1..3}
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/shard4-server/conf/cat /tmp/mongo-cluster/shard4-server/conf/mongo.conf
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
bindIp: 0.0.0.0 #绑定ip
replication:
replSetName: shard3 #复制集名称是 shard3
sharding:
clusterRole: shardsvr # 集群角色,这里配置的角色是分片节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径docker run --name shard4-server1 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard4-server:/data/configdb \
-v /tmp/mongo-cluster/shard4-server/data/1:/data/db \
-v /tmp/mongo-cluster/shard4-server/logs/1:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name shard4-server2 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard4-server:/data/configdb \
-v /tmp/mongo-cluster/shard4-server/data/2:/data/db \
-v /tmp/mongo-cluster/shard4-server/logs/2:/data/logs \
mongo --config /data/configdb/conf/mongo.confdocker run --name shard4-server3 -d \
--net=mongo-cluster \
--privileged=true \
-v /tmp/mongo-cluster/shard4-server:/data/configdb \
-v /tmp/mongo-cluster/shard4-server/data/3:/data/db \
-v /tmp/mongo-cluster/shard4-server/logs/3:/data/logs \
mongo --config /data/configdb/conf/mongo.conf docker exec -it shard4-server1 bin/bash
mongo -port 27017
#进行副本集配置
rs.initiate(
{
_id : "shard4",
members: [
{ _id : 0, host : "shard4-server1:27017" },
{ _id : 1, host : "shard4-server2:27017" },
{ _id : 2, host : "shard4-server3:27017",arbiterOnly:true }
]
}
);use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})docker exec -it mongos-server1 /bin/bash
mongo -port 27017
use admin;
db.auth("root","root");
sh.addShard("shard4/shard4-server1:27017,shard4-server2:27017,shard4-server3:27017")
{
"shardAdded" : "shard4",
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709522847, 5),
"signature" : {
"hash" : BinData(0,"8VTIt28VX2jvg5S/F1ukmssrSwk="),
"keyId" : NumberLong("7340916952241537047")
}
},
"operationTime" : Timestamp(1709522847, 5)
}
查看状态
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("65e02d139d6b86c251f4b918")
}
shards:
{ "_id" : "shard1", "host" : "shard1/shard1-server1:27017,shard1-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191698, 2) }
{ "_id" : "shard2", "host" : "shard2/shard2-server1:27017,shard2-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191701, 2) }
{ "_id" : "shard3", "host" : "shard3/shard3-server1:27017,shard3-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191704, 2) }
{ "_id" : "shard4", "host" : "shard4/shard4-server1:27017,shard4-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709522847, 3) }
use admin
db.runCommand({removeshard: "shard4"})
mongos> use admin
switched to db admin
mongos> db.runCommand({removeshard: "shard4"})
{
"msg" : "draining started successfully",
"state" : "started",
"shard" : "shard4",
"note" : "you need to drop or movePrimary these databases",
"dbsToMove" : [ ],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709527298, 3),
"signature" : {
"hash" : BinData(0,"6v99e7IFQnmV/y0UJkIhnhhXiCA="),
"keyId" : NumberLong("7340916952241537047")
}
},
"operationTime" : Timestamp(1709527298, 3)
等待平衡器将需要删除的分片节点中数据全部迁移完毕
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("65e02d139d6b86c251f4b918")
}
shards:
{ "_id" : "shard1", "host" : "shard1/shard1-server1:27017,shard1-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191698, 2) }
{ "_id" : "shard2", "host" : "shard2/shard2-server1:27017,shard2-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191701, 2) }
{ "_id" : "shard3", "host" : "shard3/shard3-server1:27017,shard3-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191704, 2) }
{ "_id" : "shard4", "host" : "shard4/shard4-server1:27017,shard4-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709522847, 3), "draining" : true }
active mongoses:
"5.0.5" : 3
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: yes #正在进行负载均衡
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 273
shard2 273
shard3 274
shard4 204 # 逐渐减少
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 341
shard2 342
shard3 341use admin
db.runCommand({removeShard:"shard4"})
mongos> db.runCommand({removeShard:"shard4"})
{
"msg" : "removeshard completed successfully",
"state" : "completed",
"shard" : "shard4",
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709527930, 3),
"signature" : {
"hash" : BinData(0,"y2I4mj4Y3YNXI4sGCCNqW4HL+EA="),
"keyId" : NumberLong("7340916952241537047")
}
},
"operationTime" : Timestamp(1709527930, 3)
}mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("65e02d139d6b86c251f4b918")
}
shards:
{ "_id" : "shard1", "host" : "shard1/shard1-server1:27017,shard1-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709527930, 1) }
{ "_id" : "shard2", "host" : "shard2/shard2-server1:27017,shard2-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191701, 2) }
{ "_id" : "shard3", "host" : "shard3/shard3-server1:27017,shard3-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191704, 2) }
active mongoses:
"5.0.5" : 3# 创建config-server 目录
# 创建配置文件目录
mkdir -p /tmp/mongo-cluster/config-server/conf
# 创建数据文件目录
mkdir -p /tmp/mongo-cluster/config-server/data/{1..3}
# 创建日志文件目录
mkdir -p /tmp/mongo-cluster/config-server/logs/{1..3}
# 创建shard-server 目录
# 创建配置文件目录
mkdir -p /tmp/mongo-cluster/shard{1..3}-server/conf
# 创建数据文件目录
mkdir -p /tmp/mongo-cluster/shard{1..3}-server/data/{1..3}
# 创建日志文件目录
mkdir -p /tmp/mongo-cluster/shard{1..3}-server/logs/{1..3}
# 创建mongos-server 目录
# 创建配置文件目录
mkdir -p /tmp/mongo-cluster/mongos-server/conf
# 创建数据文件目录
mkdir -p /tmp/mongo-cluster/mongos-server/data/{1..3}
# 创建日志文件目录
mkdir -p /tmp/mongo-cluster/mongos-server/logs/{1..3}# 创建密钥文件
openssl rand -base64 756 > /tmp/mongo-cluster/config-server/conf/mongo.key
# 设置
chmod 600 /tmp/mongo-cluster/config-server/conf/mongo.key
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/shard1-server/conf/
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/shard2-server/conf/
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/shard3-server/conf/
cp /tmp/mongo-cluster/config-server/conf/mongo.key /tmp/mongo-cluster/mongos-server/conf/cat /tmp/mongo-cluster/config-server/conf/mongo.conf
# 日志文件
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
# bindIp: 127.0.0.1 #绑定ip
replication:
replSetName: configsvr #副本集名称
sharding:
clusterRole: configsvr # 集群角色,这里配置的角色是配置节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径
cat /tmp/mongo-cluster/shard1-server/conf/mongo.conf
# 日志文件
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
# bindIp: 127.0.0.1 #绑定ip
replication:
replSetName: shard1 #复制集名称是 shardsvr
sharding:
clusterRole: shardsvr # 集群角色,这里配置的角色是分片节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径
cat /tmp/mongo-cluster/shard2-server/conf/mongo.conf
# 日志文件
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
# bindIp: 127.0.0.1 #绑定ip
replication:
replSetName: shard2 #复制集名称是 shard2
sharding:
clusterRole: shardsvr # 集群角色,这里配置的角色是分片节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径
cat /tmp/mongo-cluster/shard3-server/conf/mongo.conf
# 日志文件
storage:
# mongod 进程存储数据目录,此配置仅对 mongod 进程有效
dbPath: /data/db
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
# bindIp: 127.0.0.1 #绑定ip
replication:
replSetName: shard3 #复制集名称是 shard3
sharding:
clusterRole: shardsvr # 集群角色,这里配置的角色是分片节点
security:
authorization: enabled #是否开启认证
keyFile: /data/configdb/conf/mongo.key #keyFile路径
cat /tmp/mongo-cluster/mongos-server/conf/mongo.conf
# 日志文件
systemLog:
destination: file
logAppend: true
path: /data/logs/mongo.log
# 网络设置
net:
port: 27017 #端口号
bindIp: 0.0.0.0 #绑定ip
# 配置分片,这里面配置的是需要读取的配置节点的信息
sharding:
configDB: configsvr/config-server1:27017,config-server2:27017,config-server3:27017
security:
keyFile: /data/configdb/conf/mongo.key #keyFile路径version: '3'
services:
config-server1:
image: mongo
container_name: config-server1
privileged: true
networks:
- mongo-cluster-network
command: --config /data/configdb/conf/mongo.conf
volumes:
- /etc/localtime:/etc/localtime
- /tmp/mongo-cluster/config-server:/data/configdb
- /tmp/mongo-cluster/config-server/data/1:/data/db
- /tmp/mongo-cluster/config-server/logs/1:/data/logs
config-server2:
image: mongo
container_name: config-server2
privileged: true
networks:
docker exec -it config-server1 bash
mongo -port 27017
rs.initiate(
{
_id: "configsvr",
members: [
{ _id : 1, host : "config-server1:27017" },
{ _id : 2, host : "config-server2:27017" },
{ _id : 3, host : "config-server3:27017" }
]
}
)
use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})
db.auth("root","root")
db.createUser({user:"test",pwd:"test",roles:[{role:'readWrite',db:'test'}]})
docker exec -it shard1-server1 bin/bash
mongo -port 27017
#进行副本集配置
rs.initiate(
{
_id : "shard1",
members: [
{ _id : 0, host : "shard1-server1:27017" },
{ _id : 1, host : "shard1-server2:27017" },
{ _id : 2, host : "shard1-server3:27017",arbiterOnly:true }
]
}
);
use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})
db.auth("root","root")
db.createUser({user:"test",pwd:"test",roles:[{role:'readWrite',db:'test'}]})
docker exec -it shard2-server1 bin/bash
mongo -port 27017
#进行副本集配置
rs.initiate(
{
_id : "shard2",
members: [
{ _id : 0, host : "shard2-server1:27017" },
{ _id : 1, host : "shard2-server2:27017" },
{ _id : 2, host : "shard2-server3:27017",arbiterOnly:true }
]
}
);
use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})
db.auth("root","root")
db.createUser({user:"test",pwd:"test",roles:[{role:'readWrite',db:'test'}]})
docker exec -it shard3-server1 bin/bash
mongo -port 27017
#进行副本集配置
rs.initiate(
{
_id : "shard3",
members: [
{ _id : 0, host : "shard3-server1:27017" },
{ _id : 1, host : "shard3-server2:27017" },
{ _id : 2, host : "shard3-server3:27017",arbiterOnly:true }
]
}
);
use admin
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})
db.auth("root","root")
db.createUser({user:"test",pwd:"test",roles:[{role:'readWrite',db:'test'}]})docker exec -it mongos-server1 /bin/bash
mongo -port 27017
use admin;
db.auth("root","root");
sh.addShard("shard1/shard1-server1:27017,shard1-server2:27017,shard1-server3:27017")
sh.addShard("shard2/shard2-server1:27017,shard2-server2:27017,shard2-server3:27017")
sh.addShard("shard3/shard3-server1:27017,shard3-server2:27017,shard3-server3:27017")
docker exec -it mongos-server2 /bin/bash
mongo -port 27017
use admin;
db.auth("root","root");
sh.addShard("shard1/shard1-server1:27017,shard1-server2:27017,shard1-server3:27017")
sh.addShard("shard2/shard2-server1:27017,shard2-server2:27017,shard2-server3:27017")
sh.addShard("shard3/shard3-server1:27017,shard3-server2:27017,shard3-server3:27017")
docker exec -it mongos-server3 /bin/bash
mongo -port 27017
use admin;
db.auth("root","root");
sh.addShard("shard1/shard1-server1:27017,shard1-server2:27017,shard1-server3:27017")
sh.addShard("shard2/shard2-server1:27017,shard2-server2:27017,shard2-server3:27017")
sh.addShard("shard3/shard3-server1:27017,shard3-server2:27017,shard3-server3:27017")mongos> use test
switched to db test
mongos> db.blog.insert({ "title": "MongoDB 教程", "description": "MongoDB 是一个 Nosql 数据库", "by": "我的博客", "url": "http://www.baiyp.ren", "tags": [ "mongodb", "database", "NoSQL" ], "likes": 100 });
WriteResult({ "nInserted" : 1 })
mongos> db.blog.find().pretty();
{
"_id" : ObjectId("65e03e9ab6cc796e9b2f1353"),
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}# 对集合所在的数据库启用分片功能
sh.enableSharding("test")
mongos> sh.enableSharding("test")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709194949, 2),
"signature" : {
"hash" : BinData(0,"pWbSDDl1LolQXj/cpfqEWsVRvKg="),
"keyId" : NumberLong("7340916952241537047")
}
},
"operationTime" : Timestamp(1709194949, 2)
}mongos> db.blog.createIndex({title:1})
{
"raw" : {
"shard2/shard2-server1:27017,shard2-server2:27017" : {
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"createdCollectionAutomatically" : false,
"commitQuorum" : "votingMembers",
"ok" : 1
}
},
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709194989, 6),
"signature" : {
"hash" : BinData(0,"iSx4avfuxIn+YGD28+DgF+5V+iA="),
"keyId" : NumberLong("7340916952241537047")
}
},
"operationTime" : Timestamp(1709194989, 6)
}
mongos> db.blog.createIndex({"by":"hashed","likes":1})
{
"raw" : {
"shard2/shard2-server1:27017,shard2-server2:27017" : {
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"createdCollectionAutomatically" : false,
"commitQuorum" : "votingMembers",
"ok" : 1
}
},
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709194989, 12),
"signature" : {
"hash" : BinData(0,"iSx4avfuxIn+YGD28+DgF+5V+iA="),
"keyId" : NumberLong("7340916952241537047")
}
},
"operationTime" : Timestamp(1709194989, 12)
}
mongos> db.blog.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_"
},
{
"v" : 2,
"key" : {
"title" : 1
},
"name" : "title_1"
},
{
"v" : 2,
"key" : {
"by" : "hashed",
"likes" : 1
},
"name" : "by_hashed_likes_1"
}
]sh.shardCollection("test.blog", {"by":"hashed","likes":1})
mongos> sh.shardCollection("test.blog", {"by":"hashed","likes":1})
{
"collectionsharded" : "test.blog",
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1709195137, 25),
"signature" : {
"hash" : BinData(0,"6fGLfUb6wMGtH1MPE2vlQyX8L3I="),
"keyId" : NumberLong("7340916952241537047")
}
},
"operationTime" : Timestamp(1709195137, 21)
}sh.status()
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("65e02d139d6b86c251f4b918")
}
shards:
{ "_id" : "shard1", "host" : "shard1/shard1-server1:27017,shard1-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191698, 2) }
{ "_id" : "shard2", "host" : "shard2/shard2-server1:27017,shard2-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191701, 2) }
{ "_id" : "shard3", "host" : "shard3/shard3-server1:27017,shard3-server2:27017", "state" : 1, "topologyTime" : Timestamp(1709191704, 2) }
active mongoses:
"5.0.5" : 3
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration results for the last 24 hours:
682 : Success
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 342
shard2 341
shard3 341
too many chunks to print, use verbose if you want to force print
{ "_id" : "test", "primary" : "shard2", "partitioned" : true, "version" : { "uuid" : UUID("27b88c5a-6dd7-4c21-a2a0-75b2600f59ed"), "timestamp" : Timestamp(1709194905, 1), "lastMod" : 1 } }
test.blog
shard key: { "by" : "hashed", "likes" : 1 }
unique: false
balancing: true
chunks:
shard2 1
{ "by" : { "$minKey" : 1 }, "likes" : { "$minKey" : 1 } } -->> { "by" : { "$maxKey" : 1 }, "likes" : { "$maxKey" : 1 } } on : shard2 Timestamp(1, 0)
mongos> db.blog.getShardDistribution();
Shard shard2 at shard2/shard2-server1:27017,shard2-server2:27017
data : 220B docs : 1 chunks : 1
estimated data per chunk : 220B
estimated docs per chunk : 1
Totals
data : 220B docs : 1 chunks : 1
Shard shard2 contains 100% data, 100% docs in cluster, avg obj size on shard : 220Bmongos> db.blog.getShardDistribution();
Shard shard2 at shard2/shard2-server1:27017,shard2-server2:27017
data : 220B docs : 1 chunks : 1
estimated data per chunk : 220B
estimated docs per chunk : 1
Totals
data : 220B docs : 1 chunks : 1
Shard shard2 contains 100% data, 100% docs in cluster, avg obj size on shard : 220B