MongoDB高可用方案之副本集(Replica Set)

一、介绍

Replicat Set比起传统的Master - Slave结构而言,应用场景更加多,也有了自动failover的能力

二、副本集结构图(参考:https://www.linuxidc.com/Linux/2017-03/142379.htm)

类似于“MySQL中1主2从+mha_manager”的结构。

Replication通过Oplog实现语句复现

三、副本集成员的属性

Replication通过Oplog实现语句复现
分别为Primary、Secondary(Secondaries)
Primary负责处理所有的write请求,并记录到oplog(operation log)中。
Secondary负责复制oplog并应用这些write请求到他们自己的数据集中。(有一些类似于MySQL Replication)

所有的副本集都可以处理读操作,但是需要设置。

最小化的副本集配置建议有三个成员:
1个Primary + 2个Secondary
或者
1个Primary + 1个Secondary + 1个Arbiter(仲裁者)

四、Arbiter和选举机制

Arbiter可以作为副本集的一部分,但它不是一个数据副本,故它不会成为Primary。
Arbiter在Primary不可用的时候,作为一个选举的角色存在。
如果Arbiter不存在,Primary挂掉的情况下,剩下的两个Secondary则也会进行选举。

在1个Primary + 2个Secondary的情况下,failover如下:

五、搭建

1、实验环境

192.168.1.34(Primary)
192.168.1.35(Secondary1)
192.168.1.36(Secondary2)
192.168.1.37(Arbiter)

2、安装mongodb并启动

先在三台安装mongodb, 先关闭防火墙

service iptables stop

在三台机器分别创建对应目录并启动mongodb

# mkdir -p /data/mongo_replset
#./mongod --dbpath=/data/mongo_replset --logpath=/data/mongo_replset/mongo.log --fork --replSet=first_replset

3、配置副本集

登录192.168.1.34(Primary)的mongo shell

# ./mongo
> use admin
switched to db admin
输入
> cnf = {_id:"first_replset", members:[
...         {_id:1, host:"192.168.1.34:27017"},
...         {_id:2, host:"192.168.1.35:27017"},
...         {_id:3, host:"192.168.1.36:27017"},
...         ]
...     }
输出:
{
    "_id" : "first_replset",
    "members" : [
        {
            "_id" : 1,
            "host" : "192.168.1.34:27017"
        },
        {
            "_id" : 2,
            "host" : "192.168.1.35:27017"
        },
        {
            "_id" : 3,
            "host" : "192.168.1.36:27017"
        }
    ]
}

初始化配置:

>  rs.initiate(cnf);
{ "ok" : 1 }
first_replset:OTHER>
first_replset:PRIMARY>
first_replset:PRIMARY>

此时可以发现该mongodb实例已经成为PRIMARY了。

可以查看下这个副本集的各个成员的状态:

first_replset:PRIMARY> rs.status();
{
    "set" : "first_replset",
    "date" : ISODate("2018-01-03T06:37:10.559Z"),
    "myState" : 1,
    "members" : [
        {
            "_id" : 1,
            "name" : "192.168.1.34:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 599,
            "optime" : Timestamp(1514961357, 1),
            "optimeDate" : ISODate("2018-01-03T06:35:57Z"),
            "electionTime" : Timestamp(1514961361, 1),
            "electionDate" : ISODate("2018-01-03T06:36:01Z"),
            "configVersion" : 1,
            "self" : true
        },
        {
            "_id" : 2,
            "name" : "192.168.1.35:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 73,
            "optime" : Timestamp(1514961357, 1),
            "optimeDate" : ISODate("2018-01-03T06:35:57Z"),
            "lastHeartbeat" : ISODate("2018-01-03T06:37:09.308Z"),
            "lastHeartbeatRecv" : ISODate("2018-01-03T06:37:09.316Z"),
            "pingMs" : 1,
            "lastHeartbeatMessage" : "could not find member to sync from",
            "configVersion" : 1
        },
        {
            "_id" : 3,
            "name" : "192.168.1.36:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 73,
            "optime" : Timestamp(1514961357, 1),
            "optimeDate" : ISODate("2018-01-03T06:35:57Z"),
            "lastHeartbeat" : ISODate("2018-01-03T06:37:09.306Z"),
            "lastHeartbeatRecv" : ISODate("2018-01-03T06:37:09.313Z"),
            "pingMs" : 1,
            "lastHeartbeatMessage" : "could not find member to sync from",
            "configVersion" : 1
        }
    ],
    "ok" : 1
}

4、副本集复制状态测试

在PRIMARY上insert:

# ./mongo 127.0.0.1/test
first_replset:PRIMARY> db.test_table.insert({"id": 1})
WriteResult({ "nInserted" : 1 })
first_replset:PRIMARY> db.test_table.find()
{ "_id" : ObjectId("5a4c7b44ecb269292f0de224"), "id" : 1 }

在35、36任意SECONDARY上查询:

同master - slave结构一样,默认SECONDARY是不可读的,需要执行rs.slaveOk()。

first_replset:SECONDARY> rs.slaveOk()
first_replset:SECONDARY> db.test_table.find()
{ "_id" : ObjectId("5a4c7b44ecb269292f0de224"), "id" : 1 }

5、failover测试

此时情况:
192.168.1.34(Primary)
192.168.1.35(Secondary)
192.168.1.36(Secondary)

停掉PRIAMRY:

first_replset:PRIMARY> use admin
switched to db admin
first_replset:PRIMARY> db.shutdownServer()
2018-01-03T14:46:14.048+0800 I NETWORK  DBClientCursor::init call() failed
server should be down...
2018-01-03T14:46:14.052+0800 I NETWORK  trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
2018-01-03T14:46:14.052+0800 I NETWORK  reconnect 127.0.0.1:27017 (127.0.0.1) ok
2018-01-03T14:46:14.053+0800 I NETWORK  DBClientCursor::init call() failed
2018-01-03T14:46:14.056+0800 I NETWORK  trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
2018-01-03T14:46:14.056+0800 I NETWORK  reconnect 127.0.0.1:27017 (127.0.0.1) ok
2018-01-03T14:46:14.397+0800 I NETWORK  Socket recv() errno:104 Connection reset by peer 127.0.0.1:27017
2018-01-03T14:46:14.397+0800 I NETWORK  SocketException: remote: 127.0.0.1:27017 error: 9001 socket exception [RECV_ERROR] server [127.0.0.1:27017]
2018-01-03T14:46:14.397+0800 I NETWORK  DBClientCursor::init call() failed

(原SECONDARY)35上查到,此时35已经为PRIMARY了

first_replset:SECONDARY>
first_replset:PRIMARY> rs.status()
{
    "set" : "first_replset",
    "date" : ISODate("2018-01-03T06:47:14.289Z"),
    "myState" : 1,
    "members" : [
        {
            "_id" : 1,
            "name" : "192.168.1.34:27017",
            "health" : 0,
            "state" : 8,
            "stateStr" : "(not reachable/healthy)",
            "uptime" : 0,
            "optime" : Timestamp(0, 0),
            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
            "lastHeartbeat" : ISODate("2018-01-03T06:47:14.034Z"),
            "lastHeartbeatRecv" : ISODate("2018-01-03T06:46:13.934Z"),
            "pingMs" : 0,
            "lastHeartbeatMessage" : "Failed attempt to connect to 192.168.1.34:27017; couldn‘t connect to server 192.168.1.34:27017 (192.168.1.34), connection attempt failed",
            "configVersion" : -1
        },
        {
            "_id" : 2,
            "name" : "192.168.1.35:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 1180,
            "optime" : Timestamp(1514961732, 2),
            "optimeDate" : ISODate("2018-01-03T06:42:12Z"),
            "electionTime" : Timestamp(1514961976, 1),
            "electionDate" : ISODate("2018-01-03T06:46:16Z"),
            "configVersion" : 1,
            "self" : true
        },
        {
            "_id" : 3,
            "name" : "192.168.1.36:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 676,
            "optime" : Timestamp(1514961732, 2),
            "optimeDate" : ISODate("2018-01-03T06:42:12Z"),
            "lastHeartbeat" : ISODate("2018-01-03T06:47:13.997Z"),
            "lastHeartbeatRecv" : ISODate("2018-01-03T06:47:13.995Z"),
            "pingMs" : 0,
            "configVersion" : 1
        }
    ],
    "ok" : 1
}

6、在副本集中添加一个属性为Arbiter的成员

当然此处只做添加实践,实际上并不建议在Secondary-Primary-Secondary的结构上再多一个Arbiter成员形成偶数个节点。
在192.168.1.37上启动一个mongod实例:

# mkdir -p /data/arb
# ./mongod --dbpath=/data/arb/ --logpath=/data/arb/mongo.log --fork --replSet=first_replset

在failover后的PRIMARY节点添加Arbiter

first_replset:PRIMARY> rs.addArb("192.168.1.37:27017")
{ "ok" : 1 }
first_replset:PRIMARY> rs.status()
{
            "_id" : 4,
            "name" : "192.168.1.37:27017",
            "health" : 1,
            "state" : 7,
            "stateStr" : "ARBITER",
            "uptime" : 82,
            "lastHeartbeat" : ISODate("2018-01-03T07:16:14.872Z"),
            "lastHeartbeatRecv" : ISODate("2018-01-03T07:16:15.497Z"),
            "pingMs" : 1,
            "configVersion" : 2
        }
    ],
    "ok" : 1

此时回到arbiter的mongo shell,发现正如文档所说,arbiter是不会存有副本集中数据的。

first_replset:ARBITER> rs.slaveOk()
first_replset:ARBITER> use test;
switched to db test
first_replset:ARBITER> show tables;
first_replset:ARBITER> db.test_table.find();
Error: error: {
    "$err" : "not master or secondary; cannot currently read from this replSet member",
    "code" : 13436
}

原文地址:https://www.cnblogs.com/guantou1992/p/9729616.html

时间: 2024-10-16 12:34:58

MongoDB高可用方案之副本集(Replica Set)的相关文章

Memcached高可用方案收集(集群及分布式)

Memcached的集群方案有很多,不止magent一个,但是单靠集群软件去实现高可用感觉还是会缺少一步,最推荐的方案应该是软件加编码去实现高可用,至少能保证站点的99.5%的可运行行,以下是集群的方案收集: randy_shandong: memcached演练(1) 搭建memcached服务 memcached演练(2) 访问memcached服务 单台tomcat的session信息的2种持久化方式 memcached演练(3) 使用apache+搭建双节点tomcat集群 memcac

Mongodb高可用架构—Replica Set 集群实战

Replica Set使用的是n个mongod节点,构建具备自动的容错功能(auto-failover),自动恢复的(auto-recovery)的高可用方案. 使用Replica Set来实现读写分离.通过在连接时指定或者在主库指定slaveOk,由Secondary来分担读的压力,Primary只承担写操作. 对于Replica Set中的secondary 节点默认是不可读的. 架构图: 分别在各服务器上运行两个mongod实例: shard11 + shard12 + shard13 -

MongoDB 高可用集群副本集+分片搭建

MongoDB 高可用集群搭建 一.架构概况 192.168.150.129192.168.150.130192.168.150.131 参考文档:https://www.cnblogs.com/vadim/p/7100683.html mongos mongos    mongos Config   server      Config server  Config serverShared1 server 1 Shared1 server 1 副本 Shared1 server 1 仲裁/隐

MongoDB 高可用集群架构简介

在大数据的时代,传统的关系型数据库要能更高的服务必须要解决高并发读写.海量数据高效存储.高可扩展性和高可用性这些难题.不过就是因为这些问题Nosql诞生了. 转载自严澜的博文--<如何搭建高效的MongoDB集群> NOSQL有这些优势: 大数据量,可以通过廉价服务器存储大量的数据,轻松摆脱传统mysql单表存储量级限制. 高扩展性,Nosql去掉了关系数据库的关系型特性,很容易横向扩展,摆脱了以往老是纵向扩展的诟病. 高性能,Nosql通过简单的key-value方式获取数据,非常快速.还有

MySQL集群之五大常见的MySQL高可用方案(转)

1. 概述 我们在考虑MySQL数据库的高可用的架构时,主要要考虑如下几方面: 如果数据库发生了宕机或者意外中断等故障,能尽快恢复数据库的可用性,尽可能的减少停机时间,保证业务不会因为数据库的故障而中断. 用作备份.只读副本等功能的非主节点的数据应该和主节点的数据实时或者最终保持一致. 当业务发生数据库切换时,切换前后的数据库内容应当一致,不会因为数据缺失或者数据不一致而影响业务. 关于对高可用的分级在这里我们不做详细的讨论,这里只讨论常用高可用方案的优缺点以及高可用方案的选型. 2. 高可用方

Codis3.2集群HA高可用方案

Codis高可用方案官方推荐使用Sentinel Redis 本身就是最终一致性的.Master 挂了,Promote Slave 成为新的 Master 需要时间(测试15秒内).其实 Sentinel 就是这个逻辑.Codis3.2 自己没有实现 HA,而是直接依赖 Sentinel 的. 注意事项: Sentinel需要使用原生的Redis-server,版本要等于或高于Codis3.2里面的3.2.8版本, 这里是在Redis3.2.9的下配置测试的,另外Protected-mode n

基于Redis Sentinel的Redis集群(主从&Sharding)高可用方案

基于Redis Sentinel的Redis集群(主从&Sharding)高可用方案 http://www.tuicool.com/articles/naeEJbv 基于Redis Sentinel的Redis集群(主从&Sharding)高可用方案 时间 2014-02-21 15:15:17  IT社区推荐资讯 原文  http://itindex.net/detail/48192-redis-sentinel-redis Redis Sentinel是一个分布式系统,可以部署多个Se

mongodb主从配置:副本集replica set

1. 副本集 mongodb的主从部署,常用方式为副本集(replica set)方式. replica set为多个mongod实例,组成一组group,包括一个主primary,多个从secondary. 这种一主多从的方式的好处是,mongodb自运维,如果主服务器挂了,会通过心跳自动检测,选举出一个新的主来.不需要人工处理. 2. 主-从 三台机器做例子,一主俩从. 主和从之间有心跳,来检测是否都处于激活状态. 每2s互相发一次心跳,如果10秒内没有返回状态,则把这个服务标记为丢弃,不可

基于Redis Sentinel的Redis集群(主从Sharding)高可用方案(转)

本文主要介绍一种通过Jedis&Sentinel实现Redis集群高可用方案,该方案需要使用Jedis2.2.2及以上版本(强制),Redis2.8及以上版本(可选,Sentinel最早出现在Redis2.4中,Redis2.8中Sentinel更加稳定),Redis集群是以分片(Sharding)加主从的方式搭建,满足可扩展性的要求: Redis Sentinel介绍 Redis Sentinel是Redis官方提供的集群管理工具,主要有三大功能: 监控,能持续监控Redis的主从实例是否正常