MongoDB 副本集原理
什么是复制
- 复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性,并可以保证数据的安全性
- 复制还允许从硬件故障和服务中断中恢复数据
为什么要复制
- 数据备份
- 数据灾难恢复
- 读写分离
- 高(24* 7)数据可用性
- 无宕机维护
- 副本集对应用程序是透明
复制的工作原理
- 复制至少需要两个节点A、B...(最好为奇数,它们之间通过oplog进行)
- A是主节点,负责处理客户端请求
- 其余的都是从节点,负责复制主节点上的数据
- 节点常见的搭配方式为:一主一从、一主多从
- 主节点记录在其上的所有操作,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致
- 主节点与从节点进行数据交互保障数据的一致性
mongodb 读写分离
Primary 机器接收所有的写操作(无法改变的),我们可以配置read preference,使得读操作可以发生在secondary机器上。如果读操作发生在primary机器上,那么数据就是强一致性的;如果读操作发生secondary 就可能数据不一致
对于secondary机器,可以进行如下配置.
a) 禁止某台secondary机器成为primary机器,priority 为0
b) 禁止客户端读取某台机器的数据。隐藏成员。
c) 仅记录历史快照的secondary,延迟成员。比如说延迟一小时。
d) 最常见的secondary机器依然是进行数据一部复制与保持数据的一致性。
e) 副本集最多有50台机器,其中具有投票功能的机器数量最多是7台。
如果进行读写分离,那么要注意到是读会有延迟。
Secondary 机器要通过oplog 异步复制primary机器的数据,因此从整体来看,primary与secondary机器的读速度是大体相当的。
默认情况下都是从primary 机器上面读取的。
对于Read preference(读取数据首选项设置):
a) primary(默认值)读操作都从这个地方读取
b) primaryPreferred(大多数情况primary 读取,一旦primary不可用,就从secondary读取)
c) secondary(从secondary读取)
d) secondaryPreferred(优先从secondary读取)
e) nearest(延迟最低机器)
关于延迟成员(delayed member)
a) 延迟成员的priority必须为0,表示它无法成为primary
b) 延迟成员也是隐藏成员,应用是无法通过延迟成员查询数据的,
c) 可以对primary的选举进行投票。
请确保副本集中成员的个数为奇数,如果是偶数的话,请添 加一个哨兵成员。
关于MongoDB投票与故障恢复
a) MongoDB要求投票时系统中可用的机器数量要是全体副本集成员个数的大多数(一半以上)。
b) 如果副本集中有3(1主 2副)台机器,那么有几台机器宕掉还可以确保MongoDB副本集可以使用吗?(1台)
c) 如果副本集中有4台机器,那么有几台机器宕掉还可以确保MongoDB副本集可以使用吗?(1台)
d) 如果副本集中有5台机器,那么有几台机器宕掉还可以确保MongoDB副本集可以使用吗?(2台)
e) 如果副本集中有6台机器,那么有几台机器宕掉还可以确保MongoDB副本集可以使用吗?(2台)
f) 如果副本集中有7台机器,那么有几台机器宕掉还可以确保MongoDB副本集可以使用吗?(3台)
开始搭建
我们这里就准备两台虚拟机就可以了我这里定义了两台
- 192.168.13.134 主机名: mongodb134 master节点
- 192.168.13.135 主机名: mongodb135 slave节点 配置主机名,实际生成环境都是通过域名映射成主机名连接副本集
修改主机名保存后重启,查看是否生效:
- 134节点 vi /etc/hostname 修改成mongodb134
- 135节点 vi /etc/hostname 修改成mongodb135
分别在134 135 两台机器上面添加映射关系 vi /etc/hosts
- 192.168.13.134 mongodb134
192.168.13.135 mongodb135
配置一个ssh 免密登录,主要是为了方便后面scp 文件不需要每次输入密码
# 我们这里只需要在134 免密登录135 所以在134 上面生成key
# 生成一个key ,一直回车就是
ssh-keygen -t rsa
# 切换到ssh目录下面
cd ~/.ssh
# copy 认证信息到对方的机器上面,我们这里是134 要登录135 ,这里第一次需要输入密码
ssh-copy-id root@mongodb135
# 通过ssh 测试是否能够免密登录到 135
ssh root@mongodb135
# 从135 退回到134机器上面
exit;
开始安装mongodb 这里采用yum 安装,安装社区版就可以了 这里给一个官网的安装地址: 官网安装地址
# 安装前先关闭防火墙 和 SELinux 否则后面可能一直无法启动
# 查看防火墙状态
firewall-cmd --state
#停止防火墙
systemctl stop firewalld.service
# 开机禁用防火墙
systemctl disable firewalld.service
# 关闭selinux
sudo vi /etc/selinux/config
修改
SELINUX=disabled
然后两台机器需要重启 reboot
# 创建一个yum源文件
vi /etc/yum.repos.d/mongodb-org-4.2.repo
# 拷贝下面的内容到文件中去
[mongodb-org-4.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.2/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc
# 执行安装命令(一个命令搞定)
sudo yum install -y mongodb-org
# 利用rpm 查看mongodb 有哪些服务
rpm -qa |grep mongod
# 查询具体的服务里面文件的安装位置
rpm -ql mongodb-org-server-4.2.1-1.el7.x86_64
# 下面讲解几个配置目录
/etc/mongod.conf // mogod启动配置目录
/var/log/mongodb/mongod.log // mongodb 启动日志文件,如果启动报错可以查看该文件
/var/lib/mongo // mongodb 的数据存放目录
同理另外一台机器也是如此安装
# 先尝试是否能正常启动
systemctl start mongod
(注意:
如果遇到安装后启动就报错:
mongod.service: control process exited, code=exited status=1
并且连启动日志都没有生成,这是某些云服务器上面出现过,我记录一下我这边的问题是怎么解决的
1. vi /etc/mongod.conf
fork=true改为false
2. vi /usr/lib/systemd/system/mongod.service
注释:Type=forking
一般服务器是没有这个问题的,但是笔者遇到的两台云服务器就有这个问题,排除了很长时间才解决掉。
)
# 查看启动状态
systemctl status mognod
# 重启
systemctl status mognod
# 停止
systemctl stop mongod
# 到这里基本安装就完成了,下面介绍一下卸载
注意: 我们用root 用户来安装mongodb 默认安装后的 /var/lib/mongo /var/log/mongodb 目录的所属用户和用户组都是mongod
只要上面能够顺利的安装起来,那么我们就算完成了一半工作了,可能不同的机器环境安装可能会报各种各样的错,只能遇到自己在逐渐一一排查
配置副本集了
# 首先第一步要编辑/etc/mongod.conf
bindIp: 127.0.0.1 默认只能本机连接,如果我们想通过外部其它客户端连接这里要改成
# 所有客户端都可以连接上来,注意 中间有空格,很多情况下是我们改了配置文件,启动报错,很多情况下都是空格导致的
bindIpAll: true
# 第二部配置副本集名称,我们这里副本集名称配置成rs0
replication:
replSetName: rs0
然后保存启动服务。
那么另外一台服务器也需要做相同的修改。为了快捷我们直接通过scp 拷贝到135 上面
scp /etc/mongod.conf root@mongodb135:/etc/
然后启动服务器开始副本集初始化:
134 135 都要启动起来,我们只需要在134 一台服务器上面初始化
systemctl restart mongod
# 连接客户端进行初始化
mongo 192.168.13.134:27017
# 开始配置副本集
这里我们定义一个变量config_myset 里面记录了我们得主机初始化
rs0 是我们得副本集名称,里面有两个成员
在客户端输入下面配置变量:
config_myset={_id:'rs0',members:[{_id:0,host:'mongodb134:27017'},{_id:1,host:'mongodb135:27017'}]};
# 初始化命令
rs.initiate(config_myset)
# 查看副本集状态
rs.status();
# 查看是否是Master 节点
rs.isMaster();
到这里基本副本集已经初始完成。接下来就是配置一个连接用户,我们数据库不可能没有用户名和密码。
# 在这之前我们得建立一个账户,后面配置用户名密码远程连接。在mongodb 中账户和用户都是在admin 这个数据库里面,我们添加一个root 用户,关于 权限这块mongodb 还是挺多权限得,自己感兴趣可以去官方查询进行学习。
# 切换到admin 数据库下
use admin;
# 执行
db.createUser({
user:'root',
pwd:'123456',
roles:[{role:'root',db:'admin'}]
})
上面完成了副本集和用户得创建下面配一些图
初始化副本集
创建用户
启用用户名密码认证
mongodb 副本集之间通信有一定认证机制有两种,一种是通过keyFile 另外一种是通过证书x.509 ,官网推荐使用证书得方式,我们这里搭建测试和开发环境没必要去弄证书,我们直接通过配置keyfile 就可以实现安全通信。
生成keyFile(keyFile的用途是作为所有mongod后台进程允许加入集群的凭证, 所有集群中的节点共用一个keyFile, 避免其他mongod非法加入集群)
# 在主节点生成keyFile ,我们这里放到mongodb 得数据目录下面去
openssl rand -base64 756 > /var/lib/mongo/access.key
# 修改权限,如果权限过大启动mongodb 会报权限过大错误
chmod 600 /var/lib/mongo/access.key
# 这两步很重要,一定要修改access.key 得所属用户和所属组一定是mongod 否则启动会报权限不足错误
chown mongod /var/lib/mongo/access.key
chgrp mongod /var/lib/mongo/access.key
修改完成后记得要查看文件是否已经修改成mongod用户和组
然后这个文件要拷贝到135 服务器上面去,权限也必须修改成mongod
scp /var/lib/mongo/access.key root@mongodb135:/var/lib/mongo/
chown mongod /var/lib/mongo/access.key
chgrp mongod /var/lib/mongo/access.key
# 下面就要启用用户和密码
# 修改 /etc/mognod.conf
security:
keyFile: "/var/lib/mongo/access.key"
authorization: enabled
同样拷贝替换135 salve 机器上面得配置文件
scp /etc/mongod.conf root@mongodb135:/etc/
然后先后重启启动 134 135
systemctl restart mongod
上面基本配置完成了认证相关操作 下面来验证一下是否成功
mongo 192.168.13.134:27017
此时需要认证
use admin;
db.auth("root","123456")
那么我们来测试一下数据是否同步
# 在134 主节点上面创建一个数据库
use mytest;
db.order.insert({"name":"The shy"})
# 登录135 slave 节点,同样需要验证,查询看数据是否同步
mongo 192.168.13.135:27017
use admin;
db.auth("root","123456")
#切换到数据库
use mytest
# 执行查询
db.order.find({})
rs0:SECONDARY> db.order.find({});
Error: error: {
"operationTime" : Timestamp(1573893068, 2),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1573893068, 2),
"signature" : {
"hash" : BinData(0,"pamg++rMbeTiGEt7aUGX20xIumg="),
"keyId" : NumberLong("6759810260799586307")
}
}
}
从节点需要查询没有权限,需要执行一下
rs.slaveOk();
然后在执行查询就没有问题了。
另外我们如果扩容副本集可以手动添加和移除,这里就不演示了,自己有兴趣去尝试一下。
rs.add('192.168.13.102:27017')
删除从节点
rs.remove('192.168.13.102:27017')
最后我们在用Rebo3T 连接一下,这里必须升级到最新版的Rebo3T 否则无法连接mongodb4.0 以后的版本 这里要注意了必须带上用户名和密码了
总结: 在搭建副本集的过程中,坑很多,所以遇到问题的朋友要慢慢去研究一下,每种环境下可能产生的问题不一样,这里面最大的问题就是要注意权限,mongodb 是运行在所属用户mongod 和所属组mongod 下面。