MongoDB入门三步曲3--部署技术:主备、副本集和数据分片

mongodb部署--主备、副本及数据分片

主备复制

主备复制是最基本的一种多点部署方案,在读写分离、热备份、数据恢复等方面具有重要作用。
在真实的生产环境,主备库肯定需要部署在不同的服务器中,但鉴于学习测试,这里以一台机器的不同端口进行模拟。
准备工作:

  • 安装Mongodb的二进制程序安装步骤 假设已经安装在/usr/local/mongodb/目录
  • 为主库及备库创建数据目录:
    • 主库目录:/var/mongodb_master/data/ /var/mongodb_master/logs/
    • 备库目录:/var/mongodb_slave/data/ /var/mongodb_slave/logs/
  • 启动主备库服务:
    • 启动主库:
      sudo -u mongodb /usr/local/mongodb/bin/mongod --dbpath=/var/mongodb_master/data/ --logpath=/var/mongodb_master/logs/log.log --master --port 27017 -fork
    • 启动备库:
      sudo -u mongodb /usr/local/mongodb/bin/mongod --dbpath=/var/mongodb_slave/data/ --logpath=/var/mongodb_slave/logs/log.log --slave --port 27117 --source=127.0.0.1:27017 -fork

说明:在启动主库时,比普通启动多指定一个--master选项;在启动库备时比普通启动多指定一个--slave和--source选项。

  • master 说明当前实例以主库模式启动
  • slave 说明当前实例以备库模式启动
  • source 给备库指定主库的位置

通过上面几个步骤,其实就已经部署好了一主一备的mongodb集群。可以启动两个不同的mongo shell 连接到不同机器上,看主备数据是否能同步呢?

sudo -u mongodb /usr/local/mongodb/bin/mongo 127.0.0.1:27017 ## 连到主库
sudo -u mongodb /usr/local/mongodb/bin/mongo 127.0.0.1:27117 ## 连到备库

在主库上添加几条数据:

use test
for(var i = 0; i < 10; i++) {
db.blog.insert({"author":"enjiex_" + i, "title":"mongodb title " + i});
}

到备库的shell上看下:

use test
db.blog.find()

很神奇,数据竟然已经同步到备库上了。
如果只有一个主服务,另外一个计划外的服务如果想成为备库,也不需要重启服务的,只需要在将成为备库的local库里把主备source添加进来就ok。

use local
db.sources.insert("host":"127.0.0.1:27017")

不过,在备库上只能查询,并不能写入数据,并且当主备宕机或需要主备互换时甚至需要停止服务,所以对于热切换来说,还有更好的选择:副本集。

副本集

副本集,即副本的集合,每个mongodb服务在启动时并不区分主库备库,在运行中也没有特定的主库,所有的选择都是靠选举决定的。如果主库宕机,就会自动推选出新的主库。
先以两个副本为例:

sudo -u mongodb /usr/local/mongodb/bin/mongod --dbpath=/usr/mongodb_s1/data/ --logpath/usr/mongodb_s1/logs/log.log --port 27017 --replSet enjiex/127.0.0.1:27117 -fork
sudo -u mongodb /usr/local/mongodb/bin/mongod --dbpath=/usr/mongodb_s2/data/ --logpath/usr/mongodb_s2/logs/log.log --port 27117 --replSet enjiex/127.0.0.1:27017 -fork

创建副本也并没什么特别的地方,只需要在启动服务时指定--replSet选项即可,表示服务以副本集的方式部署。replSet后的参数:enjiex/127.0.0.1:27117中的enjiex为副本名称,后面的127.0.0.1:27117为副本集中另一副本的主机地址,也就是说需要在replSet后面指定副本名称和副本集中除自己外的其他副本服务的主机地址,如果有多个副本,用","隔开主机地址。
好了,副本集创建好了,但这时副本集还不能使用,因为需要先对他做下初始化。很简单,只需要通过mongo shell登录到任一副本服务,执行如下初始化命令即可:

db.runCommand({"replSetInitiate":{
"_id":"enjiex",
"members":[{
"_id":1,
"host":"127.0.0.1:27017"
},
{
"_id":2,
"host":127.0.0.1:27117
}
]
}})

具有两个副本的副本集初始化完成,在初始化过程中,指定了副本集名称id:enjiex,以及两个副本成员。
一般情况下,执行副本初始化命令的那个服务会成为主服务,能提供正常的读写操作,并且其上的写操作会同步到各副本上。而其他的副本只有打开slaryOk后才能提供读服务,但始终不能提供写服务,除非其成为主服务。在副本节点上打开slaveOk命令如下:

rs.slaveOk()

上面的主服务一般称为主节点,副本服务称为副本节点。对于上面的场景,假如主节点宕机,副本节点是否能顺利的晋升为主节点提供写服务呢?先来了解下选举算法吧。在mongodb的选举算法中,当主机宕机所有其他活跃的节点进行投票,当得票数大于副本集节点(包括已宕机的主节点)半数的节点才能成为主节点。所以对于上面的场景,如果主节点宕机,只有一个副本节点对自己投了一票,不满足当前主节点的条件,因此时间副本集就会处于不可写状态,直到主节点恢复。
为了避免上面的问题,在生产场景一般部署的副本集节点为奇数,所以可以基于上面的场景,再在副本集中添加一个副本节点或仲裁节点。副本节点在上面我们已经有所了解,那仲裁节点呢?其实也可看作是一个不能开启slaveOk的副本节点,也就是说完成不能提供读写服务,也不会成为主节点的节点,只能参与投票的节点。
添加仲裁节点和副本节点的方式基本是一样的,都需要先把副本启动:

sudo -u mongodb /usr/local/mongodb/bin/mongod --dbpath=/usr/mongodb_s2/data/ --logpath/usr/mongodb_s2/logs/log.log --port 27217 --replSet enjiex/127.0.0.1:27017,127.0.0.1:27117 -fork

如果是添加副本节点,在主节点上执行:

rs.add("127.0.0.1:27217")

如果添加的是仲裁节点,则在主节点上执行:

rs.addAbr("127.0.0.1:27217")

好了,现在副本集中有3个节点,假如这时主节点宕机了,那么另外存活的副本节点就会投票选出一个新的主节点出来。(记住:仲裁节点只参与投票,但不能被选举)。如果原来宕机的主机又恢复服务了,那它也就只能以普通副本存在了。
在运行过程中,可以随机在副本集的任一台机器上执行如下命令查看副本集状态:

rs.status()

该命令会列出副本集中的各节点及每个节点的状态:PRIMARY(主节点)、SECONDARY(副本节点)、ARBITER(仲裁节点),还能看到各节点的健康状态等信息。
最后,一个副本不再需要的话,可以在主节点上执行remove删除副本:

rs.remove("127.0.0.1:27217")

数据分片

数据分片技术是为避免单个集合数据量过大影响性能,而把单个集合拆分到不同的mongodb服务集群中;因此至少需要两个mongod实例用于分片存储数据,另外还需要一个mongo-configdb用于存储分片配置及片键(即分片规则),基于mongo-configdb,执行mongos命令即可启动分片服务。

  • 启动mongo-configdb
    sudo -u mongodb /usr/local/mongodb/bin/mongod --dbpath=/var/mongodb_config/data/ --logpath=/var/mongodb_config/logs/log.log --port27017 -fork

可以看出,mongo-configdb就是一个普通的mongod服务。

  • 开启mongos分片服务
    sudo -u mongodb /usr/local/mongodb/bin/mongos --logpath=/var/mongodb_mongos/logs/log.log --port 27117 --configdb=127.0.0.1:27017 -fork

mongos可以看作是一个对分片数据的路由,其本身不存储数据,因此无须dbpath,但其配置是基于mongo-configdb,所以需要通过configdb参数指定配置信息

  • 启动两个mongod服务

    sudo -u mongodb /usr/local/mongodb/bin/mongod --dbpath=/usr/mongodb_s1/data/ --logpath/usr/mongodb_s1/logs/log.log --port 27217 -fork
    sudo -u mongodb /usr/local/mongodb/bin/mongod --dbpath=/usr/mongodb_s2/data/ --logpath/usr/mongodb_s2/logs/log.log --port 27317 -fork
  • 服务配置
    在分片集群中,mongos作为服务入口,因此客户端只需要连接到mongos服务上,无须知道后端的实际存储服务的位置。分片服务的配置也是在mongos上完成的:

    sudo -u mongodb /usr/local/mongodb/bin/mongo 127.0.0.1:27117
    db.runCommand({"addshard":"127.0.0.1:27217", "allowLocal":true})
    db.runCommand({"addshard":"127.0.0.1:27317", "allowLocal":true})

    上面添加了两个mongod服务作为mongos分片的数据存储服务,然后还需要指定需要分片的库和表、以及分片字段规则:

    db.runCommand({"enablesharding":"blogs"})
    db.runCommand({"shardcollection":"blogs.blog", "key":{"author":1}})

    尝试在mongos上添加些数据:

    use blogs
    for(var i = 0; i < 100; i++) {
    db.blog.insert({"author":"enjiex" + i, "title":"monge title" + i})
    }
    db.blog.find()
  • 查看分片情况:

    db.printShardingStatue()
上一篇:B2B、B2C、C2C、O2O


下一篇:java中Array/List/Map/Object与Json互相转换详解