MongoDB集群的几种方式
1. 副本集(replica set)
副本集集群中,有三种角色:
- primary 主节点
- secondary(slave) 从节点
- arbiter 仲裁节点(可选)
在此集群模式下,数据在primary主节点与secondary从节点之间同步,arbiter节点不做数据保存,只做选举投票。 一个副本集中,支持一个primary节点,多个secondary节点,多个arbiter节点。 与主从模式不同的是,副本集模式下的primary节点是动态的。当主节点不可达时,副本集会自动触发选举,推选出新的primary节点。 一般情况下,一个副本集中只有primary节点允许读写,从节点既不可写也不可读。在调用rs.secondaryOk()
、db.getMongo().setSecondaryOk()
之后,允许从secondary从节点读取数据。
每次通过shell连接从节点时,都需要先设置
rs.secondaryOk()
。否则读取数据会报错。
我们可以通过URL: mongo://[username:password@]ip1:port1,ip2:port2,ip3:port3/?replicaSet={replica set name}
连接到一个副本集。
2. 切片(sharding)
切片集群方式是由多个切片(副本集)+ 多个mongos + configServer副本集组成的。 mongos是入口,configServer中配置了数据的路由规则,数据进来之后,被分成多个片,存入不同的切片中。
切片模式还未实践,后续在补充。
一步步搭建副本集
我是通过docker-compose的方式在一台机器上起了两个副本节点一个仲裁节点。
1. 创建配置文件
提前创建一些配置文件以及数据库数据备份等,具体的文件目录如下:
- data/db. 数据库数据挂载到本地,防止数据丢失。
- log
- mongod.log. 日志挂载到本地。
- config
- mongod.conf. mongoDB的配置文件,在容器起来时,指定conf文件。
- key_file.txt. 节点之间通信必须要求安全校验,keyFile就是支持的其中一种。
mongod.conf的内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
systemLog:
#MongoDB发送所有日志输出的目标指定为文件
destination: file
#诊断日志记录信息的日志文件的路径
path: "/var/log/mongod.log"
#当mongos或mongod实例重新启动时,新条目附加到末尾。
logAppend: true
storage:
journal:
#启用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
net:
bindIpAll: true
port: 15001
replication:
replSetName: rs1
security:
keyFile: "/etc/config/key_file.txt"
容器起来加载文件时,可能会报错。它对挂载的文件权限、属性有些特殊的限制:
- mongod.log的文件属性。需求
chown 999 mongod.log
。 - key_file.txt的文件属性。需求
chown 999 key_file.txt
。 - key_file.txt的读取权限。要求
chmod 600 key_file.txt
。mongod默认是不开启权限的。但是,在副本集模式下,开启了keyFile后,默认是开启权限认证的。
2. 创建docker-compose.yml
接着编写docker-compose.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
version: "3"
services:
mongo1:
image: mongo:4.4.6
container_name: mongo_replica_1
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=123456
restart: always
networks:
- mongo_db
volumes:
- "./mongo/replica1/config:/etc/config"
- "./mongo/replica1/data/db:/data/db"
- "./mongo/replica1/log:/var/log"
- "./mongo/replica1/mongorc.js:/etc/mongorc.js"
ports:
- "15001:15001"
command: --config /etc/config/mongod.conf
mongo2:
image: mongo:4.4.6
container_name: mongo_replica_2
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=123456
restart: always
networks:
- mongo_db
volumes:
- "./mongo/replica2/config:/etc/config"
- "./mongo/replica2/data/db:/data/db"
- "./mongo/replica2/log:/var/log"
ports:
- "15002:15002"
command: --config /etc/config/mongod.conf
mongo3:
image: mongo:4.4.6
container_name: mongo_replica_3
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=123456
restart: always
networks:
- mongo_db
volumes:
- "./mongo/replica3/config:/etc/config"
- "./mongo/replica3/data/db:/data/db"
- "./mongo/replica3/log:/var/log"
ports:
- "15003:15003"
command: --config /etc/config/mongod.conf
networks:
mongo_db:
将第一步中建的文件,挂载到容器中去。同时,指定mongo启动时的config文件。
但是,我们在启动时,会发现报错了,提示add user failed啥的。其实就是说,我们通过环境变量创建的root角色添加失败了。暂不清楚这是不是bug,通过docker-compose起来时,如果配置了副本集,会导致预设的角色创建失败。 因此,目前而言,正确的步骤是:
- 将mongod.conf中的replication那一段注释掉
- 启动
docker-compose up -d
- 等待容器起来后,用root登进去,确定root账号创建成功
- 停掉
docker-compose down
- 在将replication那一段打开
- 重新启动
docker-compose up -d
- 进入其中一个容器,使用mongo shell命令登入:
1 2 3 4
mongo --port 15001 -u root -p 123456 rs.initiate() //初始化副本集 rs.add("mongo2:15002") //向副本集中添加节点 rs.addArb("mongo3:15003") //向副本集中添加仲裁节点
- 通过
rs.status()
可以查看当前的副本集状态,通过rs.conf()
查看副本集配置。 需要注意的是,注意rs.conf()
中自己绑定的host,如果host是容器id的话,需要手动修改成容器名或者其他不变的域名、ip等。shell进入mongodb后,具体的命令是:1 2 3
cc=rs.conf() cc.members[0].host="mongo1:15001" rs.reconfig(cc, {force: true})
- 通过
rs.stepDown(millseconds)
中断心跳,来模拟主节点断开心跳。此时会触发选举,当前的主节点会自动从primary节点切换到secondary节点。 - 进入secondary节点。默认是不能读取数据的,通过
rs.secondaryOK()
后,可以从secondary节点读取节点。
如果我们将节点分散到不同的机器上部署的话,会遇到一个问题。因为容器化的关系,在rs.conf()中自己的host不能设置成宿主ip,也不能设置成127.0.0.1这样的,它会同步该信息给到其他的节点。我们要选择一个容器本身能识别、其他节点也能识别的host。有一种方法:host设置成service name, 这样容器自身能识别。然后再宿主机的/etc/hosts中增加宿主ip与service name的路由对应,这样,其他的节点也能识别了。
mongo-express
mongo-express是mongo的web管理页面。我们也通过docker-compose来启动它。 express.yml内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
services:
mongo-express:
image: mongo-express:latest
container_name: mongo_exp
restart: always
environment:
- ME_CONFIG_MONGODB_URL=mongodb://root:123456@mongo1:15001,mongo2:15002,mongo3:15003/?replicaSet=rs1
- ME_CONFIG_MONGODB_ADMINUSERNAME=root
- ME_CONFIG_MONGODB_ADMINPASSWORD=123456
- ME_CONFIG_BASICAUTH_USERNAME=root
- ME_CONFIG_BASICAUTH_PASSWORD=123456
ports:
- "18081:8081"
networks:
- test_mongo_db
networks:
test_mongo_db:
external: true
如果将每个节点分别部署到不同的机器上,host就不能取service_name,可以设置docker compose network_mode: “host”来使用宿主机ip.记得打开防火墙端口。