Mongodb副本集高可用架构
1.简介
Mongodb复制集由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点。
Mongodb Driver(客户端)的所有数据都写入Primary,Secondary从Primary同步写入的数据,以保持复制集内所有成员存储相同的数据集,实现数据的高可用。
使用场景:
1. 数据冗余,用做故障恢复使用,当发生硬件故障或者其它原因造成的宕机时,可以使用副本进行恢复。
2.读写分离,读的请求分流到副本上,减轻主节点的读压力。
一个典型的副本集架构如下图所示:
2.副本集角色
主节点(Primary)
接收所有的写请求,然后把修改同步到所有Secondary。一个Replica Set只能有一个Primary节点,当Primary挂掉后,其他Secondary或者Arbiter节点会重新选举出来一个主节点。默认读请求也是发到Primary节点处理的,可以通过修改客户端连接配置以支持读取Secondary节点。
副本节点(Secondary)
与主节点保持同样的数据集。当主节点挂掉的时候,参与选主。
仲裁者(Arbiter)
不保有数据,不参与选主,只进行选主投票。使用Arbiter可以减轻数据存储的硬件需求,Arbiter几乎没什么大的硬件资源需求,但重要的一点是,在生产环境下它和其他数据节点不要部署在同一台机器上。
3.两种架构模式
1.PSS
Primary + Secondary + Secondary模式,通过Primary和Secondary搭建的Replica Set
该模式下 Replica Set节点数必须为奇数,目的是选主投票的时候要出现大多数才能进行选主决策,由一个主和两个次级组成的3个成员副本集的图:
2.PSA
Primary + Secondary + Arbiter模式,使用Arbiter搭建Replica Set
偶数个数据节点,加一个Arbiter构成的Replica Set
4.数据同步
Primary 与 Secondary 之间通过 oplog 来同步数据,Primary 上的写操作完成后,会向特殊的 local.oplog.rs 特殊集合写入一条 oplog,Secondary 不断的从 Primary 取新的 oplog 并应用。
因 oplog 的数据会不断增加,local.oplog.rs 被设置成为一个 capped 集合,当容量达到配置上限时,会将最旧的数据删除掉。另外考虑到 oplog 在 Secondary 上可能重复应用,oplog 必须具有幂等性,即重复应用也会得到相同的结果。
在异常回滚方面,当 Primary 宕机时,如果有数据未同步到 Secondary,当 Primary 重新加入时,如果新的 Primary 上已经发生了写操作,则旧 Primary 需要回滚部分操作,以保证数据集与新的 Primary 一致。旧 Primary 将回滚的数据写到单独的 rollback 目录下,数据库管理员可根据需要使用 mongorestore 进行恢复
如下 oplog 的格式,包含 ts、h、op、ns、o 等字段。
{
"ts" : Timestamp(1446011584, 2),
"h" : NumberLong("1687359108795812092"),
"v" : 2,
"op" : "i",
"ns" : "test.nosql",
"o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), "name" : "mongodb", "score" : "100" }
}
属性说明:
ts 操作时间,当前 timestamp + 计数器,计数器每秒都被重置
h 操作的全局唯一标识
v oplog 版本信息 op 操作类型
op.i 插入操作 op.u 更新操作
op.d 删除操作 op.c 执行命令(如 createDatabase,dropDatabase)
op.n 空操作,特殊用途 ns 操作针对的集合
o 操作内容 o2 操作查询条件,仅 update 操作包含该字段
5.安装前准备
操作系统:CentOS Linux release 7.5.1804 (Core)
MongoDB版本:mongodb-linux-x86_64-rhel70-3.4.18
下载地址: https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.4.18.tgz
副本集模式:PSA
设备3台:
192.168.1.246(27020端口, primary)
192.168.1.247(27020端口, secondary)
192.168.1.248(27020端口, arbiter)
在三台机器上进行下面操作:
1.创建相关文件夹
mkdir /data/mongodb
将安装包mongodb-linux-x86_64-rhel70-3.4.18.tgz解压到/data/mongodb
tar -zxvf mongodb-linux-x86_64-rhel70-3.4.18.tgz -C /data/mongodb
2.创建用于保存配置文件,日志文件,数据库。
mkdir /data/mongodb/{conf,logs,db}
3.将/data/mongodb/bin加入到环境变量.bash_profile方便日后使用。
vi /root/.bash_profile
export PATH=$PATH:/data/mongodb/bin
source /root/.bash_profile
4.开放防火墙端口。
firewall-cmd --zone=public --add-port=27020/tcp --permanent
firewall-cmd --reload
6.主节点安装
1.在/data/mongodb/conf新增下面配置文件mongod.conf
systemLog:
destination: file
path: /data/mongodb/logs/mongod.log
logAppend: true
storage:
dbPath: /data/mongodb/db
journal:
enabled: true
directoryPerDB: true
processManagement:
fork: true
pidFilePath: /data/mongodb/mongod.pid
net:
port: 27070
bindIp: 192.168.1.246
setParameter:
failIndexKeyTooLong: false
security:
keyFile: /data/mongodb/mongodb.keyfile
authorization: enabled
replication:
replSetName: mongodb_set
2.启动MongoDB服务
mongod -f /data/mongodb/conf/mongod.conf
3.连接MongoDB,必须指定端口号,因为默认的端口为27017
mongo 172.17.30.250:27020
4.创建管理员账号
use admin;
db.createUser(
{
user: "admin",
pwd: "admin", #密码设置一定复杂
roles: [ "__system","backup","clusterAdmin","dbAdminAnyDatabase","readWriteAnyDatabase","userAdminAnyDatabase" ] #设置权限
}
);
5.关闭MongoDB服务
mongod -f /data/mongodb/conf/mongod.conf --shutdown
6.生成keyfile文件
openssl rand -base64 741 > /data/mongodb/mongodb.keyfile
chmod 600 mongodb.keyfile #权限必须为600
7.新增配置文件项
vi /data/mongodb/conf/mongod.conf
security:
keyFile: /data/mongodb/mongodb.keyfile #使用keyfile认证
authorization: enabled
replication: #主从复制
replSetName: mongodb_set #复制集名称,可自定义,但主节点,从节点,仲裁者设置需要一致。
7.配置从节点,仲裁节点
1.将主节点mongod.conf和mongodb.keyfile拷贝到从节点和仲裁节点的相应目录。
2.需修改仲裁节点mongod.conf。
#注意,尝试3.4.18版本可以设置,4.0.4设置false无法启动,有待进一步测试
3.启动各节点MongoDB
8.初始化集群
一、在主节点登录MongoDB
mongo 172.17.30.250:27020/admin -uadmin -p
二、执行下面命令,初始化副本集配置。确认返回的是{ “ok” : 1 }
use admin;
config={_id:"mongodb_set",members:
[{_id:0,host:" 192.168.1.246:27020","priority":1}]}
rs.initiate(config);
三、添加从节点
rs.add("192.168.1.247:27020");
四、添加仲裁节点
rs.addArb("192.168.1.248:27020");
五、在主节点执行rs.config();查看集群配置。
rs.config();
9.测试集群
1.插入数据
1.1 在主节点执行下面语句插入数据。
db.use.insert({username: "test1", age: 26})
1.2 在从节点依次执行下面三条语句测试验证
rs.slaveOk(); #明确从节点参数,暂时设置为可读
show collections; #查看当前集合
db.use.find(); #查看数据
1.3 在从节点尝试插入数据。因从节点是不能写的,所以会报no-master.
db.use.insert({username: "test2", age: 27})
2.测试故障转移
2.1 强行停止主节点的MongoDB。(不建议使用Kill停止mongodb服务)
mongod -f /data/mongodb/conf/mongod.conf --shutdown
2.2 查看从节点和仲裁节点的日志。可以发现显示检测不到主节点的心跳
2.3 可以发现从节点的输入栏从SECONDARY变为PRIMARY
2.4 重新启动之前的主节点,发现PRIMARY变成SECONDARY。
节点故障转移成功
10.其他设置
1. 加入服务、开机自启
cd /usr/lib/systemd/system
vi mongod.service
[Unit]
Description=mongodb
After=network.target
[Service]
Type=forking
ExecStart=/data/mongodb/bin/mongod -f /data/mongodb/conf/mongod.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/data/mongodb/bin/mongod --shutdown -f /data/mongodb/conf/mongod.conf
PrivateTmp=true
[Install]
WantedBy=multi-user.target
chmod 754 mongod.service
systemctl enable mongod.service
2. 日志分割:
编辑配置文件
新增 logRotate: rename
mkdir /usr/local/mongodb/sh/
vi /usr/local/mongodb/sh/mongod_LogCut.sh
#!/bin/bash
#Rotate the MongoDB logs to prevent a single logfile from consuming too much disk space.
service=mongod
mongodPath=/data/mongodb/bin/
pidArray=$(pidof $mongodPath/$service)
for pid in $pidArray;do
if [ $pid ]
then
kill -SIGUSR1 $pid
fi
done
exit
chmod +x mongodb_LogCut.sh
vi /etc/crotab
59 23 * * * root /usr/local/mongodb/sh/mongodb_LogCut.sh