搭建一个MongoDB副本集系统

1字数 996阅读 633

在任何服务系统中,要提供系统服务高可用,必须要解决单点故障及实现故障自动转移。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);
}

执行结果

执行结果

最后,副本集的故障转移可以自行验证下。

推荐阅读更多精彩内容