分享

基于docker搭建mongodb副本集

 馒头的人生 2018-04-02

什么是mognodb副本集

官网上这么描述

A replica set in MongoDB is a group of mongod processes that maintain the same data set. Replica sets provide redundancy and high availability, and are the basis for all production deployments. This section introduces replication in MongoDB as well as the components and architecture of replica sets. The section also provides tutorials for common tasks related to replica sets.

为什么需要副本集

  • 先看看为什么mongodb官方不推荐使用主从复制

    1. 主节点不可用之后,无法自动切换到从节点,无法确保业务访问的不间断性
    2. 所有的读写操作都是对主节点的,造成主节点的访问压力较大
  • 因此,使用副本集的意义在于

    1. 自动故障转移
    2. 负载均衡和读写分离
  • 官方给出的特点: Redundancy and Data Availability

    Replication provides redundancy and increases data availability. With multiple copies of data on different database servers, replication provides a level of fault tolerance against the loss of a single database server.
    In some cases, replication can provide increased read capacity as clients can send read operations to different servers. Maintaining copies of data in different data centers can increase data locality and availability for distributed applications. You can also maintain additional copies for dedicated purposes, such as disaster recovery, reporting, or backup.

副本集复制原理

参考这个博客MongoDB 副本集的原理、搭建、应用
副本集中数据同步过程: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,不能提供服务。

基于docker搭建最简单的副本集

基本思路是这个

mongodb副本集

以下所有文件的项目地址在这里

配置docker环境

这里省略,我当前的环境如下:
docker version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Client:
 Version:	17.12.0-ce
 API version:	1.35
 Go version:	go1.9.2
 Git commit:	c97c6d6
 Built:	Wed Dec 27 20:10:14 2017
 OS/Arch:	linux/amd64

Server:
 Engine:
  Version:	17.12.0-ce
  API version:	1.35 (minimum version 1.12)
  Go version:	go1.9.2
  Git commit:	c97c6d6
  Built:	Wed Dec 27 20:12:46 2017
  OS/Arch:	linux/amd64
  Experimental:	false

docker-compose version

1
2
3
4
docker-compose version 1.10.0, build 4bd6f1a
docker-py version: 2.0.1
CPython version: 2.7.9
OpenSSL version: OpenSSL 1.0.1t  3 May 2016

mongo, 用的版本较新,稳定版是3.2

1
2
MongoDB shell version: 3.3.10
MongoDB server version: 3.3.10

编写docker-compose.yml

一次性把所有事情做了,让副本集直接可用

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

docker-compose.yml中 awarecloud.com.cn/mongodb:latest 为docker tag后的本地化镜像

修改为 mongo:latest即可拉取最新镜像


version: '2'

services:
   mongo1:
     image: awarecloud.com.cn/mongodb:latest
     container_name: "mongo1"
     ports:
       - "30001:27017"
     volumes:
       - /opt/replset/mongo1:/data/db
     command: mongod --replSet yw_replset
     restart: "always"
     networks:
         mongo_replset:
               ipv4_address: 162.16.1.10

   mongo2:
     image: awarecloud.com.cn/mongodb:latest
     container_name: "mongo2"
     ports:
       - "30002:27017"
     volumes:
       - /opt/replset/mongo2:/data/db
     command: mongod --replSet yw_replset
     restart: "always"
     networks:
         mongo_replset:
               ipv4_address: 162.16.1.11
   mongo3:
     image: awarecloud.com.cn/mongodb:latest
     container_name: "mongo3"
     ports:
       - "30003:27017"
     volumes:
       - /opt/replset/mongo3:/data/db
     command: mongod --replSet yw_replset
     restart: "always"
     networks:
         mongo_replset:
               ipv4_address: 162.16.1.12

  #mongo-repl:
  #   image: replset-mongo-config
  #   container_name: mongo-repl
  #   links:
  #     - mongo1:mongo1
  #     - mongo2:mongo2
  #     - mongo3:mongo3
  #   networks:
  #       mongo_replset:
  #             ipv4_address: 162.16.1.13

networks:
    mongo_replset:
        driver: bridge
        driver_opts:
            com.docker.network.enable_ipv6: "false"
        ipam:
            driver: default
            config:
              - subnet: 162.16.1.0/24
                gateway: 162.16.1.1

启动

执行命令docker-compose up -d,复本集群就搭建完成了,连接mongo1,插入数据,在mongo2中查询,就可以看到了,默认SECONDARY不支持查询操作,需要执行命令rs.setSlaveOk(),然后执行查询,就没问题了


replset.sh


  • #!/bin/bash

    MONGO_MASTER=162.16.1.10  #docker-compose.yml master-salver ip

    MONGO_SECONDARY=162.16.1.11,162.16.1.12

    MONGO_REPLSET_NAME=yw_replset    #mongo replset name

    mongo $MONGO_MASTER:27017/admin --eval "rs.initiate({\"_id\": \"$MONGO_REPLSET_NAME\", \"members\": [{\"_id\": 0, \"host\": \"$MONGO_MASTER:27017\"}]})"

    mongo $MONGO_MASTER:27017/admin --eval "rs.reconfig(rs.config(),{"force":false})"

    #mongo $MONGO_MASTER:27017/admin --eval "rs.reconfig(configuration, force)"

    hosts=$(echo $MONGO_SECONDARY | tr "," "\n")

    for hst in $hosts

    do

      mongo $MONGO_MASTER:27017 --eval "rs.add(\"$hst:27017\")";

    done

  • 执行 sh replset.sh 初始化副本集相关信息

  • 查看副本集信息

  • mongo --host  192.168.10.158 --port 30003

  • rs.status()

  • 副本节点不支持查询操作, db.getMongo().setSlaveOk() 当前session有效

  • 查看复制的情况

    db.printSlaveReplicationInfo()

注意

上面有几个点比较关键

  1. 读写分离的关键
    • 连接时候设置slaveOk: true,这样才能从SECONDARY节点取数据
    • 连接时候设置readPreference: secondary,设定只能从SECONDARY节点取数据
  2. 怎么做负载均衡,自己的理解
    连接数据库的时候,配置readPreference: nearest,实现负载均衡
  3. 自动故障转移,mongodb副本集已经帮我们做好了,docker stop mongo1关掉主节点,你会发现mongo2,或者是mongo3就会自动变成主节点,docker start mongo1,重新启动mongo1,发现它会变为SECONDARY节点,并自动同步这down掉期间写入的数据

readPreference参数解释

  • primary 默认参数,只从主节点上进行读取操作;
  • primaryPreferred 大部分从主节点上读取数据,只有主节点不可用时从secondary节点读取数据。
  • secondary 只从secondary节点上进行读取操作,存在的问题是secondary节点的数据会比primary节点数据“旧”。
  • secondaryPreferred 优先从secondary节点进行读取操作,secondary节点不可用时从主节点读取数据;
  • nearest 不管是主节点、secondary节点,从网络延迟最低的节点上读取数据。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多