mongodb集群之副本集

  • 什么是副本集

那什么是副本集呢?打魔兽世界总说打副本,其实这两个概念差不多一个意思。游戏里的副本是指玩家集中在高峰时间去一个场景打怪,会出现玩家暴多怪物少的情况,游戏开发商为了保证玩家的体验度,就为每一批玩家单独开放一个同样的空间同样的数量的怪物,这一个复制的场景就是一个副本,不管有多少个玩家各自在各自的副本里玩不会互相影响。
mongoDB的副本也是这个,主从模式其实就是一个单副本的应用,没有很好的扩展性和容错性。而副本集具有多个副本保证了容错性,就算一个副本挂掉了还有很多副本存在,并且解决了上面第一个问题“主节点挂掉了,整个集群内会自动切换”。难怪mongoDB官方推荐使用这种模式。我们来看看mongoDB副本集的架构图:

这里写图片描述

由图可以看到客户端连接到整个副本集,不关心具体哪一台机器是否挂掉。主服务器负责整个副本集的读写,副本集定期同步数据备份,一但主节点挂掉,副本节点就会选举一个新的主服务器,这一切对于应用服务器不需要关心。我们看一下主服务器挂掉后的架构:

这里写图片描述

副本集中的副本节点在主节点挂掉后通过心跳机制检测到后,就会在集群内发起主节点的选举机制,自动选举一位新的主服务器。

官方推荐的副本集机器数量为至少3个,那我们也按照这个数量配置测试。

规划部署
因设备有限,暂时在一台服务器上,配置3个MongoDB;在/home/mongo目录下的mongo1,mongo2,mongo3,端口分别为:28017、28018、28019

    主节点:192.168.0.197:28017
    从节点:192.168.0.197:28018
    从节点:192.168.0.197:28019
  • 启动配置

先配置mongo1

存放整个mongodb文件

mkdir /home/mongo/mongo1

存放mongodb数据文件

mkdir /home/mongo/mongo1/data

进入mongo1的bin目录

cd /home/mongo/mongo1/bin

在/home/mongo/mongo1/bin目录下编写配置文件mongod1.conf

以下为具体内容:

#数据库文件路径
dbpath=/home/mongo/mongo1/data/

#日志文件
logpath=/home/mongo/mongo1/log/mongod.log

#副本集配置变量
replSet=repset

#修改数据目录存储模式,每个数据库的文件存储在DBPATH指定目录的不同的文件夹中
directoryperdb=true

#定义端口
port=28017

#后台启动
fork=true

#以追加的模式写入日志
logappend=true

在/home/mongo/mongo1/bin目录下编写启动脚本startmongod.sh

./mongod --config mongod1.conf

mongo2,mongo3的配置方法一样,但是注意目录和端口的区别

分别启动3个数据库服务器:mongo1,mongo2,mongo3

./startmongod.sh
  • 副本集

登录任意一台mongo

./mongo --port 28017    #默认的是27017,这里需要指定

使用admin数据库

>use admin
  • 配置副本集
>config = { _id:"repset", members:[
... {_id:0,host:"192.168.0.197:28017"},
... {_id:1,host:"192.168.0.197:28018"},
... {_id:2,host:"192.168.0.197:28019"}]
... }

输出

{
        "_id" : "repset",
        "members" : [
                {
                        "_id" : 0,
                        "host" : "192.168.0.197:28017"
                },
                {
                        "_id" : 1,
                        "host" : "192.168.0.197:28018"
                },
                {
                        "_id" : 2,
                        "host" : "192.168.0.197:28019"
                }
        ]
}
  • 初始化副本集
>rs.initiate(config)

输出成功

{
        "info" : "Config now saved locally.  Should come online in about a minute.",
        "ok" : 1
}

成功之后,当前节点会出现repset:Primary>的标示
注意,如果提示失败,有可能是数据库目录/home/mongo/mongo1/data在启动之前存在多余的文件或者空白文件夹,关闭所有MongoDB,删掉data里面的东西,重新启动
如果要导入数据库文件,在初始化副本集之前,就必须以导入
比如,在data下新建edu目录,然后再edu目录下放置 edu.ns edu.0 edu.1 等数据库文件。前面配置文件mongod1.conf 里面也配置了directoryperdb=true,它的作用就是修改数据目录存储模式,每个数据库的文件存储在DBPATH指定目录的不同的文件夹中

查看集群节点的状态

repset:Primary> rs.status()

输出

{
    "set" : "repset",
    "date" : ISODate("2016-06-15T07:13:43Z"),
    "myState" : 2,
    "syncingTo" : "127.0.0.1:28017",
    "members" : [
        {
            "_id" : 0,
            "name" : "127.0.0.1:28017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 545,
            "optime" : Timestamp(1465974632, 1),
            "optimeDate" : ISODate("2016-06-15T07:10:32Z"),
            "lastHeartbeat" : ISODate("2016-06-15T07:13:42Z"),
            "lastHeartbeatRecv" : ISODate("2016-06-15T07:13:41Z"),
            "pingMs" : 0,
            "electionTime" : Timestamp(1465974285, 1),
            "electionDate" : ISODate("2016-06-15T07:04:45Z")
        },
        {
            "_id" : 1,
            "name" : "127.0.0.1:28018",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 623,
            "optime" : Timestamp(1465974632, 1),
            "optimeDate" : ISODate("2016-06-15T07:10:32Z"),
            "self" : true
        },
        {
            "_id" : 2,
            "name" : "127.0.0.1:28019",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 545,
            "optime" : Timestamp(1465974632, 1),
            "optimeDate" : ISODate("2016-06-15T07:10:32Z"),
            "lastHeartbeat" : ISODate("2016-06-15T07:13:42Z"),
            "lastHeartbeatRecv" : ISODate("2016-06-15T07:13:42Z"),
            "pingMs" : 0,
            "syncingTo" : "127.0.0.1:28017"
        }
    ],
    "ok" : 1
}

到此,副本集已经搭建成功

  • 副本集数据复制功能

登录到在主节点mongo1,并新建test数据库

repset:Primary> use test

插入数据库

repset:Primary> db.testdb.insert({"test1":"testval1"})

在副本节点mongo2、mongo3上连接到mongodb查看数据是否复制过来。

使用test 数据库。

repset:SECONDARY> use test

repset:SECONDARY> show tables;

输出

Sun Dec 29 21:50:48.590 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:128

mongodb默认是从主节点读写数据的,副本节点上不允许读,需要设置副本节点可以读。

repset:SECONDARY> db.getMongo().setSlaveOk()

可以看到数据已经复制到了副本集。

repset:SECONDARY> db.testdb.find()

输出

{ "_id" : ObjectId("52c028460c7505626a93944f"), "test1" : "testval1" }
  • 副本集故障转移功能

先停掉主节点mongo1,可通过kill -2 进程数 的方法关闭MongoDB
在从节点下查看整个集群的状态

repset:SECONDARY> rs.status()

输出

{
        "set" : "repset",
        "date" : ISODate("2013-12-29T14:28:35Z"),
        "myState" : 2,
        "syncingTo" : "192.168.0.197:28018",
        "members" : [
                {
                        "_id" : 0,
                        "name" : "192.168.0.197:28017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 9072,
                        "optime" : Timestamp(1388324934, 1),
                        "optimeDate" : ISODate("2013-12-29T13:48:54Z"),
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "192.168.0.197:28018",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 7329,
                        "optime" : Timestamp(1388324934, 1),
                        "optimeDate" : ISODate("2013-12-29T13:48:54Z"),
                        "lastHeartbeat" : ISODate("2013-12-29T14:28:34Z"),
                        "lastHeartbeatRecv" : ISODate("2013-12-29T14:28:34Z"),
                        "pingMs" : 1,
                        "syncingTo" : "192.168.1.138:27017"
                },
                {
                        "_id" : 2,
                        "name" : "192.168.0.197:28019",
                        "health" : 0,
                        "state" : 8,
                        "stateStr" : "(not reachable/healthy)",
                        "uptime" : 0,
                        "optime" : Timestamp(1388324934, 1),
                        "optimeDate" : ISODate("2013-12-29T13:48:54Z"),
                        "lastHeartbeat" : ISODate("2013-12-29T14:28:35Z"),
                        "lastHeartbeatRecv" : ISODate("2013-12-29T14:28:23Z"),
                        "pingMs" : 0,
                        "syncingTo" : "192.168.0.197:28018"
                }
        ],
        "ok" : 1
}

mongo2的标示也会变成repset:Primary> ,即mongo2变成了主节点,故障转移功能实现

做完以上测试,就可以开始做权限和认证

  • 权限

需要配置两种用户,一个是数据库用户管理员,一个是数据库管理
进入主节点

repset:Primary> use admin

配置数据库用户管理员,用来管理所有数据库的用户

repset:Primary> db.createUser(
  {
    user: "admin",
    pwd: "password",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)

此权限可进行的操作(暂时只知道以下的)
查看admin库的用户

repset:Primary> show users

查看整个MongoDB全部的用户

repset:Primary> db.system.users.find()

添加admin库的可读写用户

repset:Primary> db.createUser(
   {
     user: "test",
     pwd: "123456",
     roles:
       [
         { role: "readWrite", db: "admin" },
       ]
   })

该用户只能对该用户新增的集合和数据进行读写,对admin库的system.indexes、system.users、system.version 等集合不具有读写权限
添加edu库的可读写用户

repset:Primary> use edu
repset:Primary> db.createUser(
   {
     user: "edu",
     pwd: "password",
     roles:
       [
         { role: "readWrite", db: "edu" },
       ]
   }
)

注意,MongoDB的用户是基于数据库的,要使用该用户的权限时,必须先进去到该用户权限所属的数据库。比如,你要用edu这个用户去查询edu数据库的东西,必须要先登录到edu库

repset:Primary> use edu
repset:Primary> db.auth("username","password")

查看当前位于哪个库

repset:Primary> db

配置完之后,配置信息将同步到其他节点

  • 认证

配置完用户验证之后,停掉副本集,先用openssl生成密码文件

openssl rand -base64 90 > /home/mongo/mongo1/bin/keyfile

然后将keyfile文件复制到 mongo2和mongo3的bin目录下
注意,需要给keyfile文件赋予600的权限,文件才能被调用

chmod 600 /home/mongo/mongo1/bin/keyfile

然后再MongoDB启动脚本startmongod.sh中加入 keyfile

./mongod --config mongod1.conf --keyFile keyfile

或者在mongod1.conf配置文件中加入keyfile

#数据库文件路径
dbpath=/home/mongo/mongo1/data/

#日志文件
logpath=/home/mongo/mongo1/log/mongod.log

#副本集配置变量
replSet=repset

#修改数据目录存储模式,每个数据库的文件存储在DBPATH指定目录的不同的文件夹中
directoryperdb=true

#定义端口
port=28017

#后台启动
fork=true

#以追加的模式写入日志
logappend=true

#认证文件
keyFile=/home/mongo/mongo1/bin/keyfile

mongo2、mongo3也需要做以上的操作,要保持一致
逐一启动副本,只有经过密码文件认证的节点才能加入;数据库操作也有密码认证,大大提高了安全性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值