mongodb副本集搭建
副本集(replica set)是由一组拥有相同数据集的mongod实例做组成的集群,是增加冗余及提升MongoDB数据集群性能的有效途径。当 Primary 节点挂掉时,mongo的选举机制会将该副本集中的其他备节点中优先级最高的选为主节点。
mongodb副本集搭建
- 机器规划清单
| 节点 | 端口 | 角色 | 优先级 | 版本信息 |
|---|---|---|---|---|
| 192.168.31.101 | 3717 | 主库 | 15,与节点2互为主备 | Oralce Linux 8.9 x64、Mongodb 6.0.6 |
| 192.168.31.102 | 3717 | 从库 | 15,与节点1互为主备 | Oralce Linux 8.9 x64、Mongodb 6.0.6 |
| 192.168.31.103 | 3717 | 从库 | 0,隐藏节点 | Oralce Linux 8.9 x64、Mongodb 6.0.6 |
1.系统初始化
#.set timezone
cat /etc/resolv.conf | grep "^nameserver" || echo "nameserver 223.5.5.5" > /etc/resolv.conf
timedatectl set-timezone Asia/Shanghai
#.set ulimit
ulimit -n 65536
cat /etc/security/limits.conf | grep nofile | grep 65536 || echo "* - nofile 65536" >> /etc/security/limits.conf
cat /etc/rc.local | grep ulimit | grep 65536 || echo "ulimit -n 65536" >> /etc/rc.local
#.disable hugepage
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
#.set vm.max_map_count
cat /etc/sysctl.conf | grep max_map_count || echo "vm.max_map_count=655360" >> /etc/sysctl.conf
/sbin/sysctl -p /etc/sysctl.conf
#.disable iptables
/usr/sbin/iptables -F
systemctl stop firewalld.service
systemctl disable firewalld.service
systemctl status firewalld.service
2.安装 mongodb 单节点
- 2.1.所有节点:创建用户(不允许用户登录)
cat /etc/group | grep mongodb || groupadd mongodb
cat /etc/passwd | grep mongodb || useradd mongodb -g mongodb -s /usr/sbin/nologin
- 2.2.所有节点:安装yum依赖
# yum install -y numactl openssl
rpm -ivh http://iso.sqlfans.cn/linux/numactl-2.0.12-5.el7.x86_64.rpm
rpm -ivh http://iso.sqlfans.cn/linux/openssl-1.0.2k-26.el7_9.x86_64.rpm
- 2.3.所有节点:下载 mongodb 及 mongosh 客户端,示例 安装文件
rhel80基于 Oracle Linux 8.9
cd /opt
wget -c http://iso.sqlfans.cn/mongodb/mongodb-linux-x86_64-rhel80-6.0.6.tgz
wget -c http://iso.sqlfans.cn/mongodb/mongosh-1.6.0-linux-x64.tgz
tar -xvf mongodb-linux-x86_64-rhel80-6.0.6.tgz -C /opt/
tar xvf /opt/mongosh-1.6.0-linux-x64.tgz -C /opt/
mv /opt/mongodb-linux-x86_64-rhel80-6.0.6 /opt/mongodb
cp /opt/mongosh-1.6.0-linux-x64/bin/mongosh /opt/mongodb/bin/
rm -rf /opt/mongosh-1.6.0-linux-x64
- 2.4.所有节点:修改配置文件(启用replSet、注释掉auth和keyFile)
mkdir -p /data/mongo_3717/{data,log,pid}
cat >/data/mongo_3717/mongo_3717.conf<<EOF
quiet=false
timeStampFormat=iso8601-local
logappend=true
journal=true
#auth=true
directoryperdb=true
fork=true
oplogSize=20480
replSet=set3717
bind_ip=0.0.0.0
port=3717
profile=1
slowms=500
cpu=true
storageEngine=wiredTiger
wiredTigerCacheSizeGB=4
wiredTigerDirectoryForIndexes=true
wiredTigerIndexPrefixCompression=true
wiredTigerJournalCompressor=zlib
wiredTigerCollectionBlockCompressor=snappy
dbpath=/data/mongo_3717/data
#keyFile=/data/mongo_3717/data/keyfile
pidfilepath=/data/mongo_3717/pid/pid_3717.pid
logpath=/data/mongo_3717/log/mongo_3717.log
EOF
- 2.5.主节点:创建秘钥文件,然后拷贝到所有节点相关目录下
openssl rand -base64 741 > /data/mongo_3717/data/keyfile
scp -r -P22 /data/mongo_3717/data/keyfile 192.168.31.102:/data/mongo_3717/data/
scp -r -P22 /data/mongo_3717/data/keyfile 192.168.31.103:/data/mongo_3717/data/
- 2.6.所有节点:修改权限,并启动服务
chmod 600 /data/mongo_3717/data/keyfile
chown -R mongodb.mongodb /data/mongo_3717
sudo -u mongodb numactl --interleave=all /opt/mongodb/bin/mongod -f /data/mongo_3717/mongo_3717.conf
netstat -lnpt | grep mongo
- 2.7.所有节点:加入开机启动
cat /etc/rc.local | grep mongo_3717 || echo "sudo -u mongodb numactl --interleave=all /opt/mongodb/bin/mongod -f /data/mongo_3717/mongo_3717.conf" >> /etc/rc.local
3.配置 mongodb 副本集
- 3.1.主节点:搭建单节点replicaSet,并添加其他节点
注:若节点3配置高,则建议配置为数据节点(3个数据节点不需要仲裁);若节点3配置差,则配置为仲裁节点(优先级为0);
注:当新节点加入或重启主节点都会触发选举,优先级最高的永远为primary,建议将节点1-2设置相同的优先级可实现互为主备,并设置节点3为hidden(隐藏节点的优先级必须为0)
/opt/mongodb/bin/mongosh --port 3717 <<EOF
use admin;
var cfg={_id:"set3717",members:[{_id:0,host:"192.168.31.101:3717"}]};
rs.initiate(cfg);
sleep(5000);
rs.add("192.168.31.102:3717");
rs.add("192.168.31.103:3717");
rs.isMaster();
sleep(5000);
var cfg=rs.conf()
cfg.members[0].priority=15;
cfg.members[1].priority=15;
cfg.members[2].priority=0;
cfg.members[2].hidden=true;
rs.reconfig(cfg);
sleep(5000);
db.createUser({user:'dba_admin',pwd:'cf_rB1NKCzbaQuPH',roles:[{role:'root',db:'admin'}]});
show users;
exit;
EOF
- 3.2.所有节点:取消注释,重启mongod进程
sed -i 's/#auth/auth/g' /data/mongo_3717/mongo_3717.conf
sed -i 's/#keyFile/keyFile/g' /data/mongo_3717/mongo_3717.conf
sed -i 's/#replSet=set3717/replSet=set3717/g' /data/mongo_3717/mongo_3717.conf
ps aux | grep mongod | grep -v grep | awk '{print $2}' | xargs kill -9 2> /dev/null
sudo -u mongodb numactl --interleave=all /opt/mongodb/bin/mongod -f /data/mongo_3717/mongo_3717.conf
netstat -lnpt | grep mongo
4.验证副本集状态
- 4.1.任意节点:确认集群状态
/opt/mongodb/bin/mongosh -u dba_admin -p cf_rB1NKCzbaQuPH --authenticationDatabase admin --port 3717 <<EOF
rs.conf();
exit;
EOF
- 4.2.主节点:创建测试db
/opt/mongodb/bin/mongosh -u dba_admin -p cf_rB1NKCzbaQuPH --authenticationDatabase admin --port 3717 <<EOF
use testdb;
db.createCollection("test");
db.getCollection("test").insert({id:1});
show dbs;
exit;
EOF
- 4.3.从节点:确认新db已存在
/opt/mongodb/bin/mongosh -u dba_admin -p cf_rB1NKCzbaQuPH --authenticationDatabase admin --port 3717 <<EOF
rs.secondaryOk();
show dbs;
exit;
EOF
5.灾难演练 - 模拟主节点宕机
- 5.1.主节点:将主节点的 mongodb 进程杀掉(示例主节点
192.168.31.101:3717),模拟主节点宕机
ps aux | grep mongod | grep -v grep | awk '{print $2}' | xargs kill -9 2> /dev/null
- 5.2.任意节点:执行
rs.isMaster();查看 primary 节点已顺利切换到节点2,示例primary: '192.168.31.102:3717'
6.灾难演练 - 模拟从节点宕机
- 6.1.从节点:将从节点的 mongodb 进程杀掉(示例从节点
192.168.31.103:3717),模拟主节点宕机
ps aux | grep mongod | grep -v grep | awk '{print $2}' | xargs kill -9 2> /dev/null
- 6.2.任意节点:执行
rs.isMaster();查看 primary 节点未发生变化
遇到的问题
场景1:如何彻底卸载mongodb
ps aux | grep mongod | grep -v grep | awk '{print $2}' | xargs kill -9 2> /dev/null
rm -rf /data/mongo*
rm -rf /opt/mongo*
userdel -r mongodb
sed -i '/mongodb/d' /etc/rc.local
场景2:关于仲裁节点、延迟节点、备份节点
| 比较项 | 仲裁节点 | 备份节点 | 延迟节点 |
|---|---|---|---|
| 优先级设置 | 建议 priority=0<防止被选为主节点> | 建议 priority=0<防止被选为主节点> | 建议 priority=0<防止被选为主节点> |
| 是否隐藏 | 不必设置隐藏 | 必须设置隐藏<防止备份影响业务> | 必须设置隐藏<防止请求被分发到延时节点> |
| 字符串 | 字符串不要提供该节点 | 字符串不要提供该节点 | 字符串不要提供该节点 |
| 设置方式 | rs.addArb("127.0.0.1:3717") | - | cfg.members[2].secondaryDelaySecs=3600 |
- 初次登录仲裁节点失败,需要注释掉replSetName并重启mongo进程,再次创建账号,然后再取消注释replSetName并重启mongo进程。
场景3:关于偶数节点的几个疑问
- 问题:假如同一个RepliSet中使用了偶数个成员,那么当主节点发生故障时,其它的节点都会变成只读。由于剩下待选节点的数目不满足票选主节点的规定,此时无法选出新的PRIMARY节点。
- 结论:使用ReplSet机制的成员数量必须控制在奇数数目个。
- 实测:当ReplSet成员是2个时,PRIMARY挂了,的确SECONDARY无法升级为PRIMARY;但是,当ReplSet成员是4个时,PRIMARY挂了,SECONDARY的确是可以升级为PRIMARY的。
- 结论:4个等同于3个,6个等同于5个,这是浪费。
场景4:如何配置连接字符串
- 主节点:创建数据库(示例
xxx_gateway)、普通账号(示例user_gateway)及密码(示例Admin_147)
use xxx_gateway;
db.createUser({user:"user_gateway",pwd:"Admin_147",roles:[{"role":"readWrite","db":"xxx_gateway"}]});
show users;
- 以下是一个mongodb副本集的连接地址,示例
192.168.31.101:3717,192.168.31.102:3717是副本集(3节点)中互为主备的2个节点:
#.副本集最基本的参数
mongodb://user_gateway:Admin_147@192.168.31.101:3717,192.168.31.102:3717/xxx_gateway?authSource=admin&replicaSet=set3717
#.副本集+读操作首选从节点
#.write conern 默认 {w:1} 数据写入Primary就向客户端发送确认
#.readPreference 读策略推荐 secondaryPreferred, 若数据时效性较高(读延迟2s内)则使用 primaryPreferred
mongodb://user_gateway:Admin_147@192.168.31.101:3717,192.168.31.102:3717/xxx_gateway?authSource=admin&replicaSet=set3717&readPreference=secondarypreferred&connectTimeoutMS=30000&w=1