介绍:

mongodb副本集即客户端连接到整个副本集,不关心具体哪一台机器是否挂掉。主服务器负责整个副本集的读写,副本集定期同步数据备份,一旦主节点挂掉,副本节点就会选举一个新的主服务器,这一切对于应用服务器不需要关心
副本集中的副本节点在主节点挂掉后通过心跳机制检测到后,就会在集群内发起主节点的选举机制,自动选举一位新的主服务器
选举还有个前提条件,参与选举的节点数量必须大于副本集总节点数量的一半,如果已经小于一半了所有节点保持只读状态。因此,官方推荐我们的副本集机器数量至少为3个:[一个主节点,两个副本节点] 也可以为[一个主节点,一个副本节点,一个仲裁节点]
其中有一个仲裁节点,即当参与选举的节点无法选出主节点时仲裁节点充当仲裁的作用。仲裁节点不存储数据,只是仲裁。所以,我们的副本集可以设置为:1主+1从+1仲裁

副本同步主的数据的过程:

Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并且将复制信息写入到自己的oplog。如果某个操作失败,则备份节点停止从当前数据源复制数据。如果某个备份节点由于某些原因挂掉了,当重新启动后,就会自动从oplog的最后一个操作开始同步,同步完成后,将信息写入自己的oplog,由于复制操作是先复制数据,复制完成后再写入oplog,有可能相同的操作会同步两份,不过MongoDB在设计之初就考虑到这个问题,将oplog的同一个操作执行多次,与执行一次的效果是一样的。简单的说就是:

当Primary节点完成数据操作后,Secondary会做出一系列的动作保证数据的同步:
1:检查自己local库的oplog.rs集合找出最近的时间戳。
2:检查Primary节点local库oplog.rs集合,找出大于此时间戳的记录。
3:将找到的记录插入到自己的oplog.rs集合中,并执行这些操作 

副本集的同步和主从同步一样,都是异步同步的过程,不同的是副本集有个自动故障转移的功能。其原理是:slave端从primary端获取日志,然后在自己身上完全顺序的执行日志所记录的各种操作(该日志是不记录查询操作的),这个日志就是local数据 库中的oplog.rs表,默认在64位机器上这个表是比较大的,占磁盘大小的5%,oplog.rs的大小可以在启动参数中设 定:--oplogSize 1000,单位是M。

注意:在副本集的环境中,要是所有的Secondary都宕机了,只剩下Primary。最后Primary会变成Secondary,不能提供服务

搭建

环境说明

IP 角色
172.16.1.216 primary(主节点)
172.16.1.223 secondary(副本节点)
172.16.1.215 arbiterOnly(仲裁节点)

三台机器解压mongodb安装包

# curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon-3.4.6.tgz
# tar -zxvf mongodb-linux-x86_64-amazon-3.4.6.tgz
# mv mongodb-linux-x86_64-amazon-3.4.6/ /usr/local/mongodb

分别在三台机器上创建mongoDB的data,log以及配置目录

# cd /usr/local/mongodb
# mkdir -p data/db
# mkdir log
# touch log/mongod.log
# mkdir etc
# touch etc/mongod.conf

分别在三台机器上配置config文件

vim /usr/local/mongodb/etc/mongod.conf

dbpath = /usr/local/mongodb/data/db        # 指定数据库路径
logpath = /usr/local/mongodb/log/mongod.log          # 指定mongodb日志文件
logappend = true        # 使用追加的方式写日志
port = 27017               #设置端口号为27017
fork = true                   #设置以守护进程的方式启动mongod
replSet = timecash            #设置副本集的名字为myrs,同一副本集群的replSet名称必需相同

分别在三台机器上启动副本集

./usr/local/mongodb/bin/mongod -f /usr/local/mongodb/etc/mongod.conf    #指定以mongod.conf配置启动mongod

初始化副本集

登录任意一台机器的mongodb执行

./usr/local/mongodb/bin/mongo
>>>use admin
>>>config = {
"_id":"myrs",
"members":[
{"_id":0,"host":"172.16.1.216:27017"},
{"_id":1,"host":"172.16.1.223:27017"},
{"_id":2,"host":"172.16.1.215:27017",arbiterOnly:true} #这个节点就是仲裁节点
]
}
>>>rs.initiate(config); #初始化配置
{ "ok" : 1 }

查看集群节点

>>>rs.status();
{
"set" : "timecash",
"date" : ISODate("2018-03-08T08:29:32.268Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1520497764, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1520497764, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1520497764, 1),
"t" : NumberLong(1)
}
},
"members" : [
{
"_id" : 0,
"name" : "172.16.1.216:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 788,
"optime" : {
"ts" : Timestamp(1520497764, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-03-08T08:29:24Z"),
"electionTime" : Timestamp(1520497194, 1),
"electionDate" : ISODate("2018-03-08T08:19:54Z"),
"configVersion" : 1,
"self" : true
},
{
"_id" : 1,
"name" : "172.16.1.223:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 591,
"optime" : {
"ts" : Timestamp(1520497764, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1520497764, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-03-08T08:29:24Z"),
"optimeDurableDate" : ISODate("2018-03-08T08:29:24Z"),
"lastHeartbeat" : ISODate("2018-03-08T08:29:30.443Z"),
"lastHeartbeatRecv" : ISODate("2018-03-08T08:29:30.680Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "172.16.1.216:27017",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "172.16.1.215:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 591,
"lastHeartbeat" : ISODate("2018-03-08T08:29:30.431Z"),
"lastHeartbeatRecv" : ISODate("2018-03-08T08:29:27.927Z"),
"pingMs" : NumberLong(0),
"configVersion" : 1
}
],
"ok" : 1
}
#可以看出172.16.1.216是主节点,172.16.1.223是副本节点,172.16.1.215是仲裁节点

测试

1.测试副本集的数据复制功能

登录172.16.1.216主节点,用mongo登录到交互模式

./usr/local/mongodb/bin/mongo
timecash:PRIMARY> use test #创建test数据库
timecash:PRIMARY> db.testdb.insert({"name":"alex"}); #插入数据

登录172.16.1.223副本节点,用mongo登录到交互模式

./usr/local/mongodb/bin/mongo

timecash:SECONDARY>use test
timecash:SECONDARY>show collections
[thread1] Error: listCollections failed: {
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk"
}
#可以看到报错了
因为mongodb默认是从主节点读写数据的,副本节点上不允许读,需要设置副本节点可以读
timecash:SECONDARY>db.getMongo().setSlaveOk();
#此时副本节点就可以读取数据了
timecash:SECONDARY>db.testdb.find();
{ "_id" : ObjectId("59676d711881041abab44477"), "name" : "alex" }

2.测试副本集的故障转移功能

timecash:PRIMARY> use admin
timecash:PRIMARY> db.shutdownServer() #停掉 主节点

此时可以登录到副本节点查看,副本节点已经升级为主节点

验证(Pyhton)

1.主节点断开,看是否影响写入

(现在主是216,从是223)

脚本

#!/bin/env python

import time
from pymongo import MongoClient
#两地址
CONN_ADDR1 = '172.16.1.216:27017'
CONN_ADDR2 = '172.16.1.223:27017'
REPLICAT_SET = 'timecash'
#username = 'demouser'
#password = '123456'
#获取mongoclient
client = MongoClient([CONN_ADDR1, CONN_ADDR2], replicaSet=REPLICAT_SET) for i in range(1000):
try:
client.test.tt.insert({"name":"test" + str(i)})
time.sleep(1)
print(client.primary,'主')
print(client.secondaries,'从')
except Exception as e:
print(e)

脚本执行打印的内容

# python3.5 test.py
('172.16.1.216', 27017) 主 #刚开始 216是主,223是从
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
('172.16.1.216', 27017) 主
{('172.16.1.223', 27017)} 从
connection closed #到这的时候,我把主(216)停了,然后发现写不进数据了
('172.16.1.223', 27017) 主 #到这的时候,mongo副本集的高可用自动把主切换到223了,216起来的时候 就会变成从
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主
set() 从
('172.16.1.223', 27017) 主 #到这的时候,216起来了 就称为从了
{('172.16.1.216', 27017)} 从
('172.16.1.223', 27017) 主
{('172.16.1.216', 27017)} 从
('172.16.1.223', 27017) 主
{('172.16.1.216', 27017)} 从
('172.16.1.223', 27017) 主
{('172.16.1.216', 27017)} 从
('172.16.1.223', 27017) 主
{('172.16.1.216', 27017)} 从

上面是 在执行脚本的时候,模拟主(216)宕机,看到主 迁移到了223上,在把216起来之后 变成 从了.  其中在主(216)挂了之后 切换的过程中 有一段数据写入丢了

{ "name" : "GOODODOO15" }
{ "name" : "GOODODOO592" }
{ "name" : "GOODODOO593" }
#其实这部分数据是由于在选举过程期间丢失的,要是不允许数据丢失,则把在选举期间的数据放到队列中,等到找到新的Primary,再写入

MongoDB副本集的原理,搭建的更多相关文章

  1. MongoDB 副本集的原理、搭建、应用

    概念: 在了解了这篇文章之后,可以进行该篇文章的说明和测试.MongoDB 副本集(Replica Set)是有自动故障恢复功能的主从集群,有一个Primary节点和一个或多个Secondary节点组 ...

  2. mongodb副本集仲裁节点搭建

    服务器准备: 主节点192.168.100.106 从节点192.168.100.107 仲裁节点192.168.100.108 三台服务器: 关闭防火墙 service iptables stop ...

  3. mongodb副本集搭建过程中的问题和解决技巧

    在我以往的认知中,一个系统一旦正式上线,多半不会轻易的迁移服务器,尤其是那种涉及到多个关联应用,涉及到多台硬件服务器的系统,因为这种迁移将是牵一发而动全身的. 但是,却仍然有这种情况存在,就如我这几天 ...

  4. MongoDB副本集的常用操作及原理

    本文是对MongoDB副本集常用操作的一个汇总,同时也穿插着介绍了操作背后的原理及注意点. 结合之前的文章:MongoDB副本集的搭建,大家可以在较短的时间内熟悉MongoDB的搭建和管理. 下面的操 ...

  5. MongoDB 副本集的常用操作及原理

    本文是对MongoDB副本集常用操作的一个汇总,同时也穿插着介绍了操作背后的原理及注意点. 结合之前的文章:MongoDB副本集的搭建,大家可以在较短的时间内熟悉MongoDB的搭建和管理. 下面的操 ...

  6. Docker下搭建mongodb副本集

    背景 有需求需要对mongodb做一个容灾备份.根据官网,发现mongodb最新版本(4.0)已经抛弃了主从模式而采用副本集进行容灾.副本集的优势在于:"有自动故障转移和恢复特性,其任意节点 ...

  7. mongdb 副本集的原理、搭建、应用

    在了解了这篇文章之后,可以进行该篇文章的说明和测试.MongoDB 副本集(Replica Set)是有自动故障恢复功能的主从集群,有一个Primary节点和一个或多个Secondary节点组成.类似 ...

  8. MongoDB副本集学习(一):概述和环境搭建

    MongoDB副本集概述 以下图片摘自MongoDB官方文档:http://docs.mongodb.org/manual/core/replication-introduction/ Primary ...

  9. MongoDB副本集搭建及备份恢复

    一.MongoDB副本集(repl set)介绍 早起版本使用master-slave,一主一从和MySQL类似,但slave在此架构中为只读,当主库宕机后,从库不能自动切换为主: 目前已经淘汰了ma ...

随机推荐

  1. Linux基础学习-基本命令

    基本命令 date命令 参数 作用 %t 跳格 %H 小时(00-23) %I 小时(00-12) %M 分钟(00-59) %S 秒(00-59) %j 今年中的第几天 [root@qdlinux ...

  2. python数据类型、字符编码、文件处理-练习

    练习-字符串 # 写代码,有如下变量,请按照要求实现每个功能 (共6分,每小题各0.5分) name = " aleX" # ) 移除 name 变量对应的值两边的空格,并输出处理 ...

  3. laravel模型关联与列表展示

    上面这个是一个模型关联的图,其实我们很容易去理解 比如说,一对一,也就是说一个用户对应的是一个手机号. 一对多,比如说一篇文章可以有多条评论 一对多反向:如一篇文章可以有多条评论,但对应每条评论也只针 ...

  4. redis 散列学习要点记录

    散列类型键值也是种字典结构,存储了字段和字段值的映射,字段值只能是字符串,不可以是其他类型(redis数据类型都不可嵌套使用其他类型),散列类型键可以有2的32次方减1个字段 散列的命令组  hset ...

  5. java 获取计算机内存

    文章来源:https://www.cnblogs.com/hello-tl/p/9341900.html package com.boot.demo.springbootdemo.common.uti ...

  6. 和为s的两个数字 和为s的连续正数序列

    输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s,如果有多对数字的和等于s,输出任意一对即可. #include <iostream> using namesp ...

  7. Java-获取一个类的父类

    如何使用代码获取一个类的父类 package com.tj; public class MyClass implements Cloneable { public static void main(S ...

  8. tinyMCE获取鼠标选中的值

    今天遇到一个需求就是要在WordPress的文章编辑页面增加选中文字时要将选中值传递到弹出窗口中 解决方法: 去网上找到了下面这段代码,可以获取到选中文本 { type: 'textbox', nam ...

  9. iOS学习笔记03-UITableView

    一.UITableView基本介绍 默认的UITableView有2种风格: UITableViewStylePlain(不分组) UITableViewStyleGrouped(分组) UITabl ...

  10. 【bzoj4408】[Fjoi 2016]神秘数 主席树

    题目描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1+1+14 = 45 = 4+16 = 4+1+1 ...