Fork me on GitHub

使用docker搭建mongodb副本集

当你觉得很累的时候,说明你正在走上坡路。

使用docker搭建mongodb副本集

我所使用的环境

1
2
3
docker version: 17.10.0-ce, build f4ffd25
docker-compose: version 1.16.1, build 6d1ac219
mongo version: 3.6

基本思路与副本集工作流程

基本思路

图片解析看这里

副本集工作流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
'在 MongoDB 副本集中,主节点负责处理客户端的读写请求,备份节点则负责映射主节点的 数据。备份节点的工作原理过程可以大致描述为,备份节点定期轮询主节点上的数据操作,
然后对 自己的数据副本进行这些操作,从而保证跟主节点的数据同步。至于主节点上的所有 数据库状态改变 的操作,都会存放在一张特定的系统表中。备份节点则是根据这些数据进
行自己的数据更新。

oplog
上面提到的数据库状态改变的操作,称为 oplog(operation log,主节点操作记录)。oplog 存储在 local 数据库的"oplog.rs"表中。副本集中备份节点异步的从主节点同步 oplog,然后重新 执行它记录的操作,以此达到了数据同步的作用。
关于 oplog 有几个注意的地方:
1)oplog 只记录改变数据库状态的操作
2)存储在 oplog 中的操作并不是和主节点执行的操作完全一样,例如"$inc"操作就会转化为"$set"操作
3)oplog 存储在固定集合中(capped collection),当 oplog 的数量超过 oplogSize,新的操作就会覆盖就的操作

数据同步
在副本集中,有两种数据同步方式:
1)initial sync(初始化):这个过程发生在当副本集中创建一个新的数据库或其中某个节点刚从宕机中恢复,或者向副本集中添加新的成员的时候,默认的,副本集中的节点会从离 它最近
的节点复制 oplog 来同步数据,这个最近的节点可以是 primary 也可以是拥有最新 oplog 副本的 secondary 节点。该操作一般会重新初始化备份节点,开销较大。
2)replication(复制):在初始化后这个操作会一直持续的进行着,以保持各个 secondary 节点之间的数据同步。

initial sync
当遇到无法同步的问题时,只能使用以下两种方式进行 initial sync 了
1)第一种方式就是停止该节点,然后删除目录中的文件,重新启动该节点。这样,这个节 点就会执行 initial sync
注意:通过这种方式,sync 的时间是根据数据量大小的,如果数据量过大,sync 时间就 会很长
同时会有很多网络传输,可能会影响其他节点的工作
2)第二种方式,停止该节点,然后删除目录中的文件,找一个比较新的节点,然后把该节点目 录中的文件拷贝到要 sync 的节点目录中
通过上面两种方式中的一种,都可以重新恢复"port=33333"的节点。不在进行截图了。

副本集管理
1)查看oplog的信息 通过"db.printReplicationInfo()"命令可以查看 oplog 的信息
字段说明:
configured oplog size: oplog 文件大小
log length start to end: oplog 日志的启用时间段
oplog first event time: 第一个事务日志的产生时间
oplog last event time: 最后一个事务日志的产生时间
now: 现在的时间

2)查看 slave 状态 通过"db.printSlaveReplicationInfo()"可以查看 slave 的同步状态
当插入一条新的数据,然后重新检查 slave 状态时,就会发现 sync 时间更新了'

拉取镜像

1
docker pull mongo:latest(可以选择需要的版本)

这里直接拉取的官方的镜像,你也可以使用其他镜像

设置network

1
2
docker network create my-mongo-cluster
docker network ls

这是一个自建的网络,docker1.9之后的版本可以手动创建网络,详情参考命令docker network create,我这里使用自定义的网络,主要的目的是让容器可以通过container_name互联,也就是在这种网络模式下,hosts是docker帮忙配置解析的,为什么要这么做呢?因为docker container的ip不是固定的,一旦down掉然后重启,ip有可能会发生变化,但是hostname是不会变的。

编写docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mongo1:
image: mongo:latest
container_name: "mongo1"
net: "my-mongo-cluster"
ports:
- "27017:27017"
command: mongod --replSet mongoreplset
mongo2:
image: mongo:latest
container_name: "mongo2"
net: "my-mongo-cluster"
ports:
- "27016:27017"
command: mongod --replSet mongoreplset
mongo3:
image: mongo:latest
container_name: "mongo3"
net: "my-mongo-cluster"
ports:
- "27015:27017"
command: mongod --replSet mongoreplset

使用docker-compose -f docker-compose.yml up -d搭建副本集,用docker container ls查看启动的容器

初始化配置

使用docker exec -it mongo1 mongo进入mongo1容器的mongo命令模式,执行以下命令:

1
2
config = {"_id" : "mongoreplset","members" : [{"_id" : 0,"host" : "mongo1:27017"},{"_id" : 1,"host" : "mongo2:27017"},{"_id" : 2,"host" : "mongo3:27017"}]}
rs.initiate(config)

然后可以使用rs.status查看副本集状态

验证同步

  1. 使用docker exec -it mongo1 mongo进入mongo1的mongo命令行,新建数据库test,并向集合people插入几条记录:

  2. 进入m2容器,执行mongo进入mongodb的控制台,查看test数据库的记录,返回错误。mongodb默认读写都是在Primary上进行的,副本节点不允许读写,可以使用如下命令来允许副本读:

    1
    db.getMongo().setSlaveOk()

  3. 在m2上也执行命令db.getMongo().setSlaveOk(),使得m2也能读数据;

验证故障转移

副本集模式下,如果Primary不可用,整个集群将会选举出新的Primary来继续对外提供读写服务,一起来验证一下m0不可用的时候的状况:

  1. 打开一个终端执行docker stop m1停掉m1容器;
  2. 执行 docker exec -it mongo2 mongo,再执行rs.status:


    可以看到mongo1已经不可达了,mongo3被选为primary
  3. 重新启动mongo1,docker start mongo1,进入mongo1的mongo,执行rs.status()

    可以看到monogo1重新连入了副本集,但是是作为secondry,primary任然是mongo3

验证登录配置(后序再补充)

python中的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2018-03-31 16:26:23
# @Author : wushilong
# @Email : 1320185818@qq.com | longofo.wu@gmail.com
# @Link : http://longofo.cc

from pymongo import MongoClient, ReadPreference

client = MongoClient('mongodb://host1:port1,host2:port2,host3:port3',
replicaSet='mongoreplset', readPreference='secondary')
'''
使用3个ip是为了避免primary挂掉时程序无法连接到数据库。也利用到了mongodb副本集的故障转移功能

replicaSet指定副本集名称

readPreference有以下几种选项:
- primary
- primaryPreferred
- secondary
- secondaryPreferred
- nearest
默认primary
'''
db = client['test']
for item in db['people'].find():
print(item)

注:代码中的ip:port填自己的

参考

-------------本文结束感谢您的阅读-------------

本文标题:使用docker搭建mongodb副本集

文章作者:Longofo

发布时间:2018年03月31日 - 21:03

最后更新:2018年04月02日 - 23:04

原始链接:http://longofo.cc/使用docker搭建mongodb副本集.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

请我吃包辣条也好啊!!!
分享到: