暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

支持SSL连接的MongoDB双节点热备方案

耑辰随笔 2021-07-12
1390
 请注意 
由于公众号推文规则变更,读者将错过文章更新,为避免观众老爷们错过好文,请点击上方“耑辰随笔”关注,设为星标,及时得到内容更新~耑辰团队感谢您的支持,竭诚问您服务!

前言

熟悉MongoDB的朋友们都知道它是非关系型数据库,文档查询速度快,适用于当下数据结构复杂的互联网业务。随着许多公司逐渐转向使用非关系型数据库,用户对数据容灾的需求也在加强。尤其对小型业务来说,如何用更少的资源兼顾数据库连接安全和数据备份,成为许多用户所关注的痛点。


一、MongoDB的主从备份模式

MongoDB在官方手册上有两种常见备份模式,分别是主从模式(Master-Slave)和副本集合模式(Replication Set)。两种模式最明显的区别是,主从模式要求至少有2个mongod实例在运行,主节点可读可写,从节点只读;而副本集模式要求至少有3个mongod实例在运行,主节点可读可写,备节点只读。
从官方手册上看,主从模式从3.0版本开始已经不作为推荐的备份模式了,取而代之的是形式多变的副本集模式逐渐成为主流。不过因其需要3个以上奇数个实例,所以通常需要3台主机。

1. 如何启动主节点
在mongod启动参数中通过指定 --master 使该实例以主节点模式运行,如:
    /usr/bin/mongod --dbpath=/data --master
    或者创建一个 ini 型配置文件 mongodb.conf 并通过配置文件运行该节点,如:
      /usr/bin/mongod -f etc/mongodb.conf
      配置文件有 ini 型和 yaml 型,MongoDB在2.4以上可以同时兼容两种类型的配置文件。两种类型的配置文件对参数的描述方式不同,但大多数参数都可以通过官方手册查询到。需要注意的是主从相关参数的 yaml 写法并没有在官方文档里出现。而 ini 型配置可参考如下:
        # mongodb.conf


        dbpath = data
        logpath = var/log/mongodb/mongodb.log
        logappend = true
        journal = true
        bind_ip = 0.0.0.0
        port = 27017
        oplogSize = 2048
        master = true

        2. 如何启动从节点
        假设主节点192.168.1.100:27017,从节点192.168.1.200:27017
        通过指定 --slave 使该实例以从节点模式运行,同时通过指定 --source 如192.168.1.100:27017来指定从哪个主节点获取数据,还可增加同步延时和自动同步参数,如:
          /usr/bin/mongod --dbpath=/data --slave --source 192.168.1.100:27017 --slavedelay 1 --autoresync
          如果使用配置文件启动一个从节点 mongod 则可参考以下 ini 格式的配置,如:
            # mongodb.conf
            dbpath = /data
            logpath = /var/log/mongodb/mongodb.log
            logappend = true
            journal = true
            bind_ip = 0.0.0.0
            port = 27017
            oplogSize = 2048
            slave = true
            source = 192.168.1.100:27017
            autoresync = true
            slavedelay = 1


            二、双节点MongoDB备份可能遇到的问题

            随着对MongoDB使用和了解的加深,大家一定会遇见各种各样稀奇古怪的问题,以下针对带SSL连接的双节点备份可能遇到的问题做一些介绍。

            1. 节点角色如何切换
            双节点的 MongoDB 通常会搭配 keepalived 进行节点间监控,keepalived 可以提供一个虚拟IP,在两个节点之间漂移,当访问虚拟IP时,等效于访问主机,当主机挂掉后,虚拟IP会漂移到备机,再访问虚拟IP时,其实访问的是备机。
            假设:
            A节点192.168.1.100:27017,Keepalived主机
            B节点192.168.1.200:27017,Keepalived备机
            但是主从模式下,只有主节点可以写,从节点是只读的,主节点挂掉后虽然数据保留在从节点,但是当访问从节点的时候并不能进行写入操作。这时需要使用 keepalived 脚本切换数据库实例运行的主从身份,达到切换的效果。不过这种切换效果通常不是很理想,一方面受到keepalived本身切换问题(如抢占模式的数据不同步,非抢占模式的身份突变等),另一方面数据库面临同步源变更的问题。
            可能有朋友会想到如果同时指定主节点和从节点参数会怎样。这就引来一个主主模式,它可以看作是主从模式的一个变体。主主模式下,两个节点都有权进行写入操作。既然两个节点都可以写入,也就不需要 keepalived 辅助切换了。对于一些业务相对单一,而且对连接安全性没有要求的项目来说,这种方式是比较简单,既保证了双节点数据一致性,又能让两个节点都能写入,相对来说比较灵活。
            A的 mongodb.conf 配置可以如下:
              # mongodb.conf


              dbpath = data
              logpath = var/log/mongodb/mongodb.log
              logappend = true
              journal = true
              bind_ip = 0.0.0.0
              port = 27017
              oplogSize = 2048
              master = true
              slave = true
              source = 192.168.1.200:27017
              autoresync = true
              slavedelay = 1
              B的 mongodb.conf 配置如下:
                # mongodb.conf


                dbpath = data
                logpath = var/log/mongodb/mongodb.log
                logappend = true
                journal = true
                bind_ip = 0.0.0.0
                port = 27017
                oplogSize = 2048
                master = true
                slave = true
                source = 192.168.1.100:27017
                autoresync = true
                slavedelay = 1

                2. 主从模式变更数据同步源会怎样
                该问题也适用于主主模式,主主模式中互相为对方的数据源。刚才上面的问题其实已经引出本问题,由于同步关系先前已经建立好了,当 keepalived 要更换数据库身份重启实例时,两节点的身份和 source 值发生变化,重新启动 mongod 实例后会报错,查看日志时会发现提示配置文件的 source 与 local 存储的同步源不同,导致无法启动。此时可通过操作数据库 drop 掉 local 库重新启动节点向新的 source 进行同步。

                3. 如何保障连接安全性
                连接安全性是等级保护里很重要的一项,MongoDB连接安全的选项里有KeyFile,SSL等方式,而等级保护一般要求必须通过SSL模式完成认证,MongoDB的SSL模式配置方式在此不做赘述。
                主从模式下,配置使用KeyFile方式后节点间可以相互通信,但遗憾的是,一旦启用了SSL模式,数据库节点间就无法完成同步,日志周期提示连接被拒绝。

                三、兼顾连接安全性与双节点备份特性

                这里介绍一种使用文件级备份方式,使用rsync直接备份MongoDB数据库的二进制文件。请一定注意以下两点:
                第一,由于负责备份的是rsync,所以两个节点MongoDB均以单机模式运行。
                第二,由于备份的是数据库二进制文件,实际在备份过程中,主机将自己的数据发给备机,备机的数据库文件被写入,此时备机的MongoDB不能处于运行状态。因此,需要keepalived确保备机上的MongoDB处于停止状态。

                1. 什么是rsync,如何安装和配置rsync
                rsync 是一个常用的 Linux 文件同步应用程序,可以在本地计算机与远程计算机之间,或者两个本地目录之间同步文件。
                rsync 安装方式如下( ubuntu 和 centos 
                  sudo apt-get install -y rsync inotify-tools
                  sudo yum install -y rsync inotify-tools
                  在 rsync 服务端修改 rsyncd 环境配置文件 /etc/default/rsync
                    RSYNC_ENABLE=true
                    RSYNC_CONFIG_FILE='/etc/rsyncd.conf'
                    RSYNC_OPTS=''
                    RSYNC_NICE=''
                    在 rsync 服务端修改 rsyncd 密码文件 etc/rsyncd.secrets,此处定义 rsync 客户端当以 root 用户访问时,密码为123456。下面的 mongodb 同理,因为本人 mongod 实例是以 mongodb 用户身份运行,为了确保数据同步后文件权限不变化,需要 rsync 同步时以 mongodb 身份访问。
                      root:123456
                      mongodb:123456
                      在 rsync 服务端修改 rsyncd 配置文件 etc/rsyncd.conf,这里添加一个名为 [mongodb] 的同步项目
                        log file=/var/log/rsyncd
                        pid file=/var/run/rsyncd.pid
                        [mongodb]
                        comment = mongodb dbpath
                        path = /var/lib
                        use chroot = yes
                        lock file = /var/lock/rsyncd
                        auth users = mongodb
                        uid = mongodb
                        gid = mongodb
                        include = mongodb
                        list = no
                        hosts allow = *
                        secrets file = /etc/rsyncd.secrets
                        read only = false
                        ignore errors
                        在 rsync 服务端确认各个关键文件权限正确
                          sudo chown 0:0 /etc/default/rsync /etc/rsyncd.conf /etc/rsyncd.secrets
                          sudo chmod 600 /etc/rsyncd.secrets
                          在 rsync 客户端创建同步 MongoDB 需要的密码文件,需要与服务端的 /etc/rsyncd.secrets 中定义的密码内容一致。
                            sudo /bin/sh -c 'echo "123456" >/etc/rsync-mongodb.pass'
                            sudo chmod 600 /etc/rsync-mongodb.pass
                            在 rsync 的服务端提高inotify监控数量
                              sudo /bin/sh -c 'echo "fs.inotify.max_user_watches = 128000" >>/etc/sysctl.conf'
                              sudo sysctl -p
                              启动 rsync 服务端,添加开机自动启动
                                sudo systemctl enable rsync
                                sudo systemctl start rsync

                                2. 如何使用rsync备份MongoDB
                                假设:
                                A节点192.168.1.100:27017,Keepalived主机(非抢占),MongoDB单机(配置SSL模式)
                                B节点192.168.1.200:27017,Keepalived备机(非抢占),MongoDB单机(配置SSL模式
                                外部通过 Keepalived 虚拟IP即可访问当前 Keepalived 主机对应的MongoDB单机。
                                某时刻当A节点以Keepalived主机身份运行时,MongoDB为单机运行,A节点启动一个 rsync 客户端,向B节点传输数据。此时B节点正以Keepalived备机身份运行,MongoDB处于停止状态,rsync服务端正在接收A节点传入的MongoDB数据库文件。
                                某时刻A节点挂掉,B节点升级为Keepalived主机,MongoDB被启动,同时启动一个 rsync 客户端,向A节点传输数据,但A节点因为挂掉无法访问到。
                                当A节点重新启动后,由于Keepalived非抢占,A节点处于Keepalived备机状态,MongoDB停止运行,rsync服务端接收来自B节点传入的MongoDB数据库文件。
                                3. 下面附一个我写的 rsync 客户端同步的demo程序,抛砖引玉,仅供参考。
                                  #!/bin/bash


                                  host="192.168.1.200"
                                  src="/data"
                                  dst=mongodb@$host::mongodb
                                  name=mongodb


                                  console_log() {
                                  echo -e "$(get_date_time)$@"
                                  }


                                  /usr/bin/inotifywait -mrq --format="%T %w%f%e" --timefmt="%Y-%m-%d %H:%M:%S" -e modify,delete,create,attrib $src|while read files; do
                                  console_log "Testing connection: " 1>>/var/log/rsync-$name.log 2>&1
                                  nc -zvn $host 27017
                                  # connection error => safely sync
                                  if [[ $? -ne 0 ]]; then
                                  /usr/bin/rsync -vzrtopg --delete --progress --password-file=/etc/rsync-mongodb.pass $src $dst
                                  console_log "${files} was rsynced" 1>>/var/log/rsync-$name.log 2>&1
                                  else
                                  console_log "${files} not rsync, $host is alive" 1>>/var/log/rsync-$name.log 2>&1
                                  fi
                                  done




                                  文章转载自耑辰随笔,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                  评论