搭建一个MongoDB副本集系统
在任何服务系统中,要提供系统服务高可用,必须要解决单点故障及实现故障自动转移。mongodb的副本集提供了这样的功能,副本集由多个mongodb实例组成,其中一个为主,其他为从,解决了单点故障。另外主实例无法服务时,mongodb会重新选举主实例进行故障转移。
一、mongodb实例启动准备
下载解压
cd /usr/local
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.6.tgz
tar -xvf mongodb-linux-x86_64-3.4.6.tgz
mv mongodb-linux-x86_64-3.4.6 mongodb
设置环境
vim /etc/profile
export MONGODB_HOME=/usr/local/mongodb
export PATH=$MONGODB/bin:$PATH
source /etc/profile
由于这里搭建mongodb副本集,所以至少需要三个mongodb实例,两个数据实例,一个仲裁实例,首先创建三个数据目录
mkdir -p /data/mongodb1
mkdir -p /data/mongodb1/{log,conf}
touch /data/mongodb1/log/mongodb.log
mkdir -p /data/mongodb2
mkdir -p /data/mongodb2/{log,conf}
touch /data/mongodb2/log/mongodb.log
mkdir -p /data/mongodb3
mkdir -p /data/mongodb3/{log,conf}
touch /data/mongodb3/log/mongodb.log
创建配置文件,配置文件放在/data/mongodb1/conf/目录下,文件名为mongodb.conf,配置如下:
dbpath=/data/mongodb1
logpath=/data/mongodb1/log/mongodb.log
logappend=true
noprealloc=true
port=27011
fork=true
replSet=test
其他两个实例配置文件内容和位置一样,修改目录和端口就可以了,其他两个实例端口分别为:27012、27013。其中,replSet参数表示副本集名,三个实例必须配置一致。
二、启动实例
执行下面命令启动三个实例
mongod -f /data/mongodb1/conf/mongodb.conf
mongod -f /data/mongodb2/conf/mongodb.conf
mongod -f /data/mongodb3/conf/mongodb.conf
三个实例启动成功后,不代表副本集已经搭建成功了,还需要进行副本集初始化。
三、初始化副本集
连接任何一个实例进行初始化
mongo --port 27011
use admin
config={
_id:'test',
members:[
{_id:1, host:'localhost:27011',priority:2},
{_id:2, host:'localhost:27012',priority:1},
{_id:3, host:'localhost:27013',arbiterOnly:true}
]
}
rs.initiate(config)
上面执行成功后,可以使用rs.status()
查看副本集当前状态。
上面配置文件中,_id:'test'
表示副本集名称,与前面mongodb.conf配置文件中的replSet参数配置的名称要一致。
priority:2
表示优先级,优先级越高,副本集初始化时会选举为主。arbiterOnly:true
表示该实例为仲裁节点,不存储数据,只参与投票。
四、创建管理员用户和读写用户
连接到主实例,创建用户
mongo --port 27011
use admin
db.createUser({
user:'dba',
pwd:'dba',
roles:[{role:"userAdminAnyDatabase", db:"admin"}, {role:"readWriteAnyDatabase", db:"admin"}]
})
db.createUser({
user:'rd',
pwd:'rd',
roles:[{role:'readWrite', db:'test'}]
})
创建好后,可以使用show users
查看所有创建的用户信息
五、为副本集增加权限认证
副本集采用keyfile文件来实现权限认证,并且副本集中的所有成员使用的keyfile必须一样。
# 生成keyfile文件
openssl rand -base64 90 > /data/mongodb1/conf/keyfile
cp /data/mongodb1/conf/keyfile /data/mongodb2/conf/keyfile
cp /data/mongodb1/conf/keyfile /data/mongodb3/conf/keyfile
另外需要注意,keyfile文件权限必须是X00,也就是说,不能给group和other成员分配任何权限,否则实例无法启动。
chmod 400 /data/mongodb1/conf/keyfile
chmod 400 /data/mongodb2/conf/keyfile
chmod 400 /data/mongodb3/conf/keyfile
生成好keyfile之后,将keyfile写入mongodb.conf配置文件中,在mongodb.conf配置文件中增加如下配置:
keyFile=/data/mongodb1/conf/keyfile
其他实例做同样修改,重启所有实例。
在配置文件中开启了keyFile,就不需要开启auth认证,因为开启keyFile,就默认开启了auth。
六、验证
连接主实例
mongo --port 27011
查看当前数据库
发现没有权限执行,使用db.auth('dba', 'dba')
进行权限认证,再次执行就可以查看了。
创建一个数据库test,然后写入一些数据。
写入数据退出客户端重新连接,不认证无法进行数据库读写操作。
重新连接下面使用前面创建的rd读写用户来认证,发现认证失败。这是因为,rd用户是在admin库下面创建,所以必须要到admin库下面认证,mongodb下的用户是随着库走的。
下面连接到从实例上面,虽然用户已经认证可以了,但无法查看数据。
从实例操作这是因为mongodb默认是从主节点读写数据的,副本节点上不允许读(更不能写入),但可以设置副本节点可以读,使用db.getMongo().setSlaveOk()
命令就可以了。
七、PHP实现
首先连接主实例,在test库下面创建一个读写用户
# 登录管理员权限
use admin
db.auth('dba', 'dba')
# 切换到test库下创建用户
use test
db.createUser({
user:'test',
pwd:'test',
roles:[{role:'readWrite', db:'test'}]
})
创建新用户
php代码如下:
<?php
$m = new MongoClient(
"mongodb://test:test@192.168.99.100:27012,192.168.99.100:27011/test",
array(
'connectTimeoutMS' => 100,
'readPreference' => MongoClient::RP_PRIMARY_PREFERRED,
)
);
$db = $m->test;
$collection = $db->person;
$collection->insert(array(
'name' => 'li',
'age' => 22,
));
$cursor = $collection->find();
foreach ($cursor as $document) {
var_dump($document);
}
执行结果
执行结果最后,副本集的故障转移可以自行验证下。