MongoDB副本集
简介
mongodb复制(replication)是将数据同步在多个服务器的过程。主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性,并保证数据的安全性。复制还允许您从硬件故障和服务中断中恢复数据。
而副本集(replica set)是从mongodb 1.6 提供的新功能,比复制功能要强大一些并增加了故障自动切换和自动修复成员节点,各个DB之间数据完全一致。Replica Sets的结构类似一个集群,完全可以把它当成一个集群,因为它确实与集群实现的作用是一样的,如果其中一个节点出现故障,其他节点马上回将业务接管过来而无需停机操作。
提示:关于mongodb相关核心理论知识,建议去看对应的文档以及书籍,我这里就不做对应的介绍(因为理论的东西写起来太费劲)。
安装
提示:本环境为3台主机的环境,IP分别为192.168.58.128(PRIMARY)、192.168.58.129(SECONDARY)、192.168.58.130(ARBITER);
一、安装mongodb
1.1 安装mongodb
下载:https://www.mongodb.org/dl/linux/x86_64-rhel70;
mkdir /data tar zxf mongodb-linux-x86_64-rhel70-3.2.0.tgz mv mongodb-linux-x86_64-rhel70-3.2.0 /data/mongodb-3.2.0 mkdir /data/mongodb-3.2.0/{data,conf,logs}
1.2 配置mongodb
首先关闭透明页面,自CentOS6版本开始引入了Transparent Huge Pages(THP),从CentOS7版本开始,该特性默认就会启用。尽管THP的本意是为提升内存的性能,不过某些数据库厂商还是建议直接关闭THP(比如Redis和MongoDB等),否则可能会导致性能出现下降。
# 查看是否启用
[root@localhost ~]# cat /sys/kernel/mm/transparent_hugepage/defrag [always] madvise never [root@localhost ~]# cat /sys/kernel/mm/transparent_hugepage/enabled [always] madvise never
# 禁用HTP功能
将以下内容加入到"/etc/rc.d/rc.local"文件中,记得执行"chmod +x /etc/rc.d/rc.local"。
# disable THP(Transparent Huge Pages) echo never >> /sys/kernel/mm/transparent_hugepage/enabled echo never >> /sys/kernel/mm/transparent_hugepage/defrag
# 创建keyfile文件
openssl rand -base64 756 > /data/mongodb-3.2.0/conf/mongodb_authkey chmod 600 /data/mongodb-3.2.0/conf/mongodb_authkey scp /data/mongodb-3.2.0/conf/mongodb_authkey 192.168.58.129:/data/mongodb-3.2.0/conf/ scp /data/mongodb-3.2.0/conf/mongodb_authkey 192.168.58.130:/data/mongodb-3.2.0/conf/
提示:
keyfile文件是副本集不可缺少的,他们之间的通信依赖于此。不过我在测试yum安装的时候,似乎不需要该配置,然而在二进制安装的时候,如果缺少keyfile就提示认证失败。
# 配置mongodb配置文件
[root@localhost ~]# cat /data/mongodb-3.2.0/conf/mongodb.conf bind_ip=192.168.58.128 port=5336 dbpath=/data/mongodb-3.2.0/data logpath=/data/mongodb-3.2.0/logs/mongodb.logs logappend=true replSet=mongodb01 fork=true auth=true directoryperdb=true maxConns=8000 cpu=true oplogSize=8000
提示:建议先关闭"auth=true"参数以及禁用掉keyFile,因为如果开启该配置项在初次添加副本集的过程中,需要进行相关认证。但是,此时你并没有相关用户和密码,导致你无法通过mongodb认证。如果不禁用,就会出现如下错误:
> db.createUser({
... user: "admin",
... pwd: "123456",
... roles: [{
... role: "userAdminAnyDatabase",
... db: "admin"
... }]
... })
2017-10-11T17:17:19.247+0800 E QUERY [thread1] Error: couldn't add user: not authorized on admin to execute command { createUser: "admin", pwd: "xxx", roles: [ { role: "userAdminAnyDatabase", db: "admin" } ], digestPassword: false, writeConcern: { w: "majority", wtimeout: 30000.0 } } :
_getErrorWithCode@src/mongo/shell/utils.js:23:13
DB.prototype.createUser@src/mongo/shell/db.js:1225:11
所以先禁止掉该参数并在添加完新用户之后再开启认证功能。在其中一台关闭就行,我这里选择在192.168.58.128(PRIMARY)主机上操作。
1.3 启动mongodb
/data/mongodb-3.2.0/bin/mongod -f /data/mongodb-3.2.0/conf/mongodb.conf
三、配置副本集
3.1 创建一个管理用户
/data/mongodb-3.2.0/bin/mongo 192.168.58.128:5336 > rs.initiate() { "info2" : "no configuration specified. Using a default configuration for the set", "me" : "192.168.58.128:5336", "ok" : 1 } mongodb01:OTHER> db.createUser( { user: "admin", pwd: "admin@123", roles: [ { role: "root", db: "admin" } ] } ) mongodb01:PRIMARY> exit
3.2 开启用户认证并重启服务
提示:在日常维护过程中,mongodb关闭建议使用kill -2而不应该使用kill -9。
3.3 配置mongodb副本集
/data/mongodb-3.2.0/bin/mongo 192.168.58.128:5336 -u admin -p --authenticationDatabase admin
# 添加副本集
mongodb01:PRIMARY> show dbs admin 0.000GB local 0.000GB mongodb01:PRIMARY> rs.add("192.168.58.129:5336") mongodb01:PRIMARY> rs.addArb("192.168.58.130:5336") mongodb01:PRIMARY> rs.status()
# 测试复制
在插入数据
for(var i=0;i<100000;i++)db.test.insert({title: 'MongoDB 教程'+i, description: 'MongoDB 是一个 Nosql 数据库'+i, by: '菜鸟教程'+i, url: 'http://www.runoob.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 })
在PRIMARY和SECONDARY查看数据是否一致
db.test.count()
# 测试切换
kill 掉PRIMARY,并在SECONDARY查看状态
mongodb01:PRIMARY> rs.status() { "set" : "mongodb01", "date" : ISODate("2017-09-20T02:15:23.819Z"), "myState" : 1, "term" : NumberLong(3), "heartbeatIntervalMillis" : NumberLong(2000), "members" : [ { "_id" : 0, "name" : "192.168.58.128:5336", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2017-09-20T02:15:21.902Z"), "lastHeartbeatRecv" : ISODate("2017-09-20T02:01:16.163Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "Connection refused", "configVersion" : -1 }, { "_id" : 1, "name" : "192.168.58.129:5336", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 69990, "optime" : { "ts" : Timestamp(1505872886, 2), "t" : NumberLong(3) }, "optimeDate" : ISODate("2017-09-20T02:01:26Z"), "electionTime" : Timestamp(1505872886, 1), "electionDate" : ISODate("2017-09-20T02:01:26Z"), "configVersion" : 3, "self" : true }, { "_id" : 2, "name" : "192.168.58.130:5336", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 69615, "lastHeartbeat" : ISODate("2017-09-20T02:15:23.303Z"), "lastHeartbeatRecv" : ISODate("2017-09-20T02:15:21.905Z"), "pingMs" : NumberLong(0), "configVersion" : 3 } ], "ok" : 1 }
可以看到原 SECONDARY 已经变为 PRIMARY。此时我们在向该PRIMARY插入数据;
mongodb01:PRIMARY> for(var i=0;i<100000;i++)db.test.insert({title: 'MongoDB 教程'+i,
description: 'MySQL 是一个 关系型数据库'+i, by: '菜鸟教程'+i, url: 'http://www.runoob.com', tags: ['MySQL', 'database', 'SQL'], likes: 100 })
重启刚kill掉的 "PRIMARY",查看数据是否同步
mongodb01:SECONDARY> db.getMongo().setSlaveOk() mongodb01:SECONDARY> db.test.count() 200000
最后,在给一些在生产环境中的建议,当某个节点宕机后重新启动该节点会有一段的时间(时间长短视集群的数据量和宕机时间而定)导致整个集群中所有节点都成为secondary而无法进行写操作(如果应用程序没有设置相应的ReadReference也可能不能进行读取操作)。
因此官方推荐的最小的副本集也应该具备一个primary节点和两个secondary节点。两个节点的副本集不具备真正的故障转移能力。
最后的最后,MongoDB相关文章,参考http://www.cnblogs.com/zhanjindong/p/3268963.html,文章相当不错。