复制
MongoDB数据库在实际生产环境下,多数基于多服务器集群运行,并进行相应的数据分布式处理。因此,必须考虑数据读写的可用性和安全性,如一台服务器出故障时,应该能保证MongoDB数据处理的正常进行。
复制(Replication,在MongoDB数据库里又称“副本集”①)就是为解决上述问题而产生的,通过复制功能可以实现多服务器的数据冗余备份操作;使备份数据的服务器具备额外提供独立读访问请求的功能(分布式读取数据,可以解决高并发客户端读用户访问问题);当服务器出故障时,提供自动故障转移、自动数据恢复。
1、复制基本原理
在执行复制动作之前,需要先在不同服务器中安装Mongod实例(通常一个服务器安装一个mongod.exe程序)。一个典型副本集包括了几个数据保存节点(这里把一个节点看
作一台服务器),并可以选择另外一个独立节点作为副本集数据复制管理的仲裁节点(Arbiter Node)。在副本集中,只有一个是主节点(Primary Node),其他几个是从节点
(Secondary Node)。一般情况下一个副本集至少需要3个节点(一主二从),如图所示。
主节点负责接收客户端写入数据操作(默认情况下主节点也承担了读的任务,在大访问量情况下,存在访问瓶颈问题)。从节点负责从主节点复制数据,以保证主从节点数据的一致性和安全性。复制依据为本地的Oplog(复制操作日志local.oplog.rs)集合。主节点与从节点进行同步Oplog更新。当副本集只有偶数个节点时,可以增加仲裁节点。作为仲裁节点的服务器只装mongod.exe程序,不承担数据副本的存储任务。仲裁节点通过心跳(Hearbeat)功能保持与
其他节点的联系,一旦主节点出故障,就进行新主节点选举投票,确保新的主节点及时产生并工作。
2、搭建副本集
单机环境搭建一个1主2从的副本集。
新建文件夹,为各个实例存放数据和日志文件还有配置文件:
角色 | 数据 | 日志 | 配置文件 |
主(127.0.0.1:27017) | /data | /log | /etc/mongod.yaml |
从1(127.0.0.1:27018) | /data1 | /log1 | /etc1/mongd1.yaml |
从2(127.0.0.1:27019) | /data2 | /log2 | /etc2/mongd2.yaml |
#主配置 mongod.yaml
net:
bindIp: 127.0.0.1
port: 27017
processManagement:
fork: true
systemLog:
destination: file
path: "/usr/local/mongodb-macos-x86_64-5.0.17/log/mongo.log"
logAppend: true
storage:
dbPath: "/usr/local/mongodb-macos-x86_64-5.0.17/data"
replication:
replSetName: "myapp" #副本集名称
#从1配置 mongod1.yaml
net:
bindIp: 127.0.0.1
port: 27018
processManagement:
fork: true
systemLog:
destination: file
path: "/usr/local/mongodb-macos-x86_64-5.0.17/log1/mongo.log"
logAppend: true
storage:
dbPath: "/usr/local/mongodb-macos-x86_64-5.0.17/data1"
replication:
replSetName: "myapp" #副本集名称
#从2配置 mongod2.yaml
net:
bindIp: 127.0.0.1
port: 27019
processManagement:
fork: true
systemLog:
destination: file
path: "/usr/local/mongodb-macos-x86_64-5.0.17/log2/mongo.log"
logAppend: true
storage:
dbPath: "/usr/local/mongodb-macos-x86_64-5.0.17/data2"
replication:
replSetName: "myapp" #副本集名称
启动3个实例:
mongod -f ./etc/mongod.yaml
mongod -f ./etc1/mongod1.yaml
mongod -f ./etc2/mongod2.yaml
设置集群配置文件:
在任意一个启动的Mongo上设置下配置信息,然后初始化
mongo -port 27017
use admin
config = {
_id: "myapp",
members: [
{_id: 0, host: "127.0.0.1:27017", "priority": 3},
{_id: 1, host: "127.0.0.1:27018", "priority": 2},
{_id: 2, host: "127.0.0.1:27019", "priority": 1}
]
}
//初始化命令
rs.initiate(config)
测试:db.isMaster()
测试:rs.conf()查看副本集配置对象内容
连接从1节点:mongo -port 27018
查询数据报错:
备份节点可能会落后于主节点,可能没有最新写入的数据,所以备份节点在默认情况下会拒绝读取请求,以防止应用程序意外拿到过期的数据。因此,如果在备份节
点上做查询,可能会得到一个错误提示,说当前节点不是主节点。
这是为了保护应用程序,以免意外连接到备份节点,读取到过期数据。如果希望从备份节点读取数据,需要设置“从备份节点读取数据没有问题”标识,如下所示:
rs.secondaryOk()
在主库插入一条数据:
从库查询:
从库写入数据:
可以看到,不能对备份节点执行写操作。备份节点只通过复制功能写入数据,不接受客户端的写入请求。