原创

使用MMM实现MySQL双主复制高可用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://wxy0327.blog.csdn.net/article/details/81359632

一、MMM简介

1. 概述

        MMM(Master-Master replication manager for MySQL)是一套支持双主故障切换和双主日常管理的脚本程序。MMM使用Perl语言开发,主要用来监控和管理MySQL Master-Master(双主)复制,可以说是mysql主主复制管理器。虽然叫做双主复制,但是业务上同一时刻只允许对一个主进行写入,另一台备选主上提供部分读服务,以加速在主主切换时刻备选主的预热,可以说MMM这套脚本程序一方面实现了故障切换的功能,另一方面其内部附加的工具脚本也可以实现多个slave的read负载均衡。MMMM是关于MySQL主主复制配置的监控、故障转移和管理的一套可伸缩的脚本套件(在任何时候只有一个节点可以被写入)。这个套件也能对居于标准的主从配置的任意数量的从服务器进行读负载均衡,所以可以用它在一组居于复制的服务器启动虚拟IP,除此之外,它还有实现数据备份、节点之间重新同步功能的脚本。

        MMM提供了自动和手动两种方式移除一组服务器中复制延迟较高的服务器的虚拟IP,同时它还可以备份数据,实现两节点之间的数据同步等。由于MMM无法完全的保证数据一致性,所以MMM适用于对数据的一致性要求不是很高,但是又想最大程度的保证业务可用性的场景。MySQL本身没有提供replication failover的解决方案,通过MMM方案能实现服务器的故障转移,从而实现MySQL的高可用。对于那些对数据的一致性要求很高的业务,不建议采用MMM这种高可用架构。

2. 优缺点

  • 优点:高可用性,扩展性好,出现故障自动切换,对于主主同步,在同一时间只提供一台数据库写操作,保证的数据的一致性。
  • 缺点:Monitor节点是单点,可以结合Keepalived实现高可用。

3. 工作原理

        MMM是一套灵活的脚本程序,基于perl实现,用来对mysql replication进行监控和故障迁移,并能管理mysql Master-Master复制的配置(同一时间只有一个节点是可写的)。MMM的主要功能通过以下三个脚本提供:

  • mmm_mond:监视守护进程,它执行所有监视工作并做出有关角色切换的所有决定等等。此脚本需要在监管机上运行。
  • mmm_agentd:运行在每个mysql服务器上(Master和Slave)的代理进程,完成监控的探针工作和执行简单的远端服务设置。此脚本需要在被监管机上运行。
  • mmm_control:一个简单的脚本,提供管理mmm_mond进程的命令。

        mysql-mmm的监管端会提供多个虚拟IP(VIP),包括一个可写VIP,多个可读VIP。通过监管的管理,这些IP会绑定在可用MySQL之上,当某一台MySQL宕机时,监管会将VIP迁移至其它MySQL。在整个监管过程中,需要在MySQL中添加相关授权用户,以便让MySQL可以支持监理机的维护。授权的用户包括一个mmm_monitor用户和一个mmm_agent用户,如果想使用mmm的备份工具则还要添加一个mmm_tools用户。

4. 典型用例

(1)双节点设置
        双节点架构如图1所示。

图1

        在双节点主-主设置中,MMM使用五个IP:每个节点的单个永久IP,两个读取VIP(只读)和1个写入VIP(更新)。最后三个IP在节点之间迁移,具体取决于节点可用性。通常在没有复制延迟时,活动主库有2个VIP(读写),备用主库有1个读VIP(只读)。如果发生故障,读写操作都会迁移到工作节点。

(2)双主+一个/多个从
        这种架构如图2所示。

图2

5. 系统需求

        对于使用n个MySQL服务器的MMM设置,有以下需求:

  • n + 1 个主机:每个MySQL服务器一个主机; MMM监视器的一个主机。
  • 2 * n + 1 个IP地址:每个主机一个固定IP + 读角色一个VIP,一个写入VIP。
  • monitor user:具有用于MMM监视器的REPLICATION CLIENT特权的MySQL用户。
  • agent user:具有SUPER,REPLICATION CLIENT,MMM代理进程权限的MySQL用户。
  • replication user:具有REPLICATION SLAVE权限的MySQL用户,用于复制。
  • tools user:具有SUPER,REPLICATION CLIENT,RELOAD for MMM工具权限的MySQL用户。

        监控主机需要安装以下支持包:
(1)perl
(2)fping(如果你想以非root用户身份运行mmm_mond)
(3)Perl模块:

  • Algorithm::Diff
  • Class:Singleton
  • DBI and DBD::mysql
  • File::Basename
  • File::stat
  • File::Temp
  • Log::Dispatch
  • Log::Log4perl
  • Mail::Send
  • Net::Ping
  • Proc::Daemon
  • Thread::Queue
  • Time::HiRes

        对于节点主机,初始应该在所有MySQL服务器的配置中设置read_only=1,MMM将使用active_master_role在活动主机上将其更改为read_only=0。主机需要安装以下支持包:
(1)perl
(2)iproute
(3)send_arp (solaris)
(4)Perl模块:

  • Algorithm::Diff
  • DBI and DBD::mysql
  • File::Basename
  • File::stat
  • Log::Dispatch
  • Log::Log4perl
  • Mail::Send
  • Net::ARP (linux)
  • Proc::Daemon
  • Time::HiRes

        如果要使用MMM工具(mmm_backup,mmm_restore,mmm_clone),则必须将LVM用于MySQL数据库和日志所在的分区。注意,需要对回滚段空间进行自由物理扩展,参见“Estimating Undo Space needed for LVM Snapshot”。MMM工具还需要以下perl模块:

  • Path::Class
  • Data::Dumper

二、实验设计

1. 基本环境

  • 操作系统版本:CentOS Linux release 7.2.1511 (Core)
  • MySQL版本:5.6.14
  • 主机信息:见表1

角色

IP

主机名

网卡

server_id

DB1

172.16.1.125

hdp2

ens32

125

DB2

172.16.1.126

hdp3

ens32

126

Monitor

172.16.1.127

hdp4

-

-

表1

  • VIP信息:见表2

VIP

角色

描述

172.16.1.100

write

应用程序连接该VIP对主库进行写请求

172.16.1.210

read

应用程序连接该VIP进行读请求

172.16.1.211

read

应用程序连接该VIP进行读请求

表2

2. 架构设计

        实验架构如图3所示。

图3


三、MMM安装配置

1. 配置双主复制

        双主复制的详细配置步骤可以参考这篇文章:http://www.cnblogs.com/phpstudy2015-6/p/6485819.html#_label7,这里从略。

2. 安装MMM

        在三台主机执行下面的yum命令安装MMM软件包。

yum -y install mysql-mmm-*

3. 建立数据库用户

        在DB1、DB2中建立mmm_agent和mmm_monitor用户。

grant super,replication client,process on *.* to 'mmm_agent'@'%' identified by '123456';
grant replication client on *.* to 'mmm_monitor'@'%' identified by '123456';

4. 配置MMM

(1)通用配置
        编辑DB1上的/etc/mysql-mmm/mmm_common.conf文件,内容如下:

active_master_role      writer

<host default>
    cluster_interface       ens32
    pid_path                /var/run/mmm_agentd.pid
    bin_path                /usr/libexec/mysql-mmm/
    replication_user        repl
    replication_password    123456
    agent_user              mmm_agent
    agent_password          123456
</host>

<host db1>
    ip      172.16.1.125
    mode    master
    peer    db2
</host>

<host db2>
    ip      172.16.1.126
    mode    master
    peer    db1
</host>

<role writer>
    hosts   db1, db2
    ips     172.16.1.100
    mode    exclusive
</role>

<role reader>
    hosts   db1, db2
    ips     172.16.1.210, 172.16.1.211
    mode    balanced
</role>

        主要配置项说明:

  • active_master_role:活动主机角色名称,agent与monitor使用。
  • replication_user:用于复制的用户。
  • agent_user:mmm-agent用户。
  • host段中的mode:标明是否为主或者备选主,或者从库。
  • role段中的mode:exclusive为独占模式,同一时刻只能有一个主。balanced可能有多个ips,ips将在主机之间平衡。
  • <role write>中hosts:表示目前的主库和备选主的真实主机IP或者主机名,ips为对外提供的虚拟机ip地址。
  • <role readr>中hosts:代表从库真实的ip和主机名,ips代表从库的虚拟ip地址。

        将该文件复制到其它所有节点(DB2、Monitor)。

scp /etc/mysql-mmm/mmm_common.conf 172.16.1.126:/etc/mysql-mmm/
scp /etc/mysql-mmm/mmm_common.conf 172.16.1.127:/etc/mysql-mmm/

(2)agent配置
        DB1的/etc/mysql-mmm/mmm_agent.conf文件内容为:

include mmm_common.conf
this db1

        DB2的/etc/mysql-mmm/mmm_agent.conf文件内容为:

include mmm_common.conf
this db2

(3)monitor配置
        Monitor上的/etc/mysql-mmm/mmm_mon.conf文件内容为:

include mmm_common.conf

<monitor>
    ip                  172.16.1.127
    pid_path            /var/run/mmm_mond.pid
    bin_path            /usr/libexec/mysql-mmm
    status_path         /var/lib/mysql-mmm/mmm_mond.status
    ping_ips            172.16.1.125,172.16.1.126
    auto_set_online     60
</monitor>

<host default>
    monitor_user        mmm_monitor
    monitor_password    123456
</host>

debug 0

        auto_set_online表示将节点状态从AWAITING_RECOVERY切换到ONLINE之前等待的秒数,0表示已禁用。

四、功能测试

1. 启动MMM

(1)在DB1、DB2上启动agent

/etc/init.d/mysql-mmm-agent start
/etc/init.d/mysql-mmm-agent start

        /etc/init.d/mysql-mmm-agent文件内容分如下:

#!/bin/sh
#
# mysql-mmm-agent    This shell script takes care of starting and stopping
#                    the mmm agent daemon.
#
# chkconfig: - 64 36
# description:  MMM Agent.
# processname: mmm_agentd
# config: /etc/mmm_agent.conf
# pidfile: /var/run/mmm_agentd.pid

# Cluster name (it can be empty for default cases)
CLUSTER=''


#-----------------------------------------------------------------------
# Paths
if [ "$CLUSTER" != "" ]; then
    MMM_AGENTD_BIN="/usr/sbin/mmm_agentd @$CLUSTER"
    MMM_AGENTD_PIDFILE="/var/run/mmm_agentd-$CLUSTER.pid"
else 
    MMM_AGENTD_BIN="/usr/sbin/mmm_agentd"
    MMM_AGENTD_PIDFILE="/var/run/mmm_agentd.pid"
fi

echo "Daemon bin: '$MMM_AGENTD_BIN'"
echo "Daemon pid: '$MMM_AGENTD_PIDFILE'"

#-----------------------------------------------------------------------
# See how we were called.
case "$1" in
  start)
        # Start daemon.
        echo -n "Starting MMM Agent daemon... "
        if [ -s $MMM_AGENTD_PIDFILE ] && kill -0 `cat $MMM_AGENTD_PIDFILE` 2> /dev/null; then
            echo " already running."
            exit 0
        fi
        $MMM_AGENTD_BIN
        if [ "$?" -ne 0 ]; then
            echo "failed"
            exit 1
        fi
        echo "Ok"
        exit 0
        ;;

  stop)
        # Stop daemon.
        echo -n "Shutting down MMM Agent daemon"
        if [ -s $MMM_AGENTD_PIDFILE ]; then
            pid="$(cat $MMM_AGENTD_PIDFILE)"
            cnt=0
            kill "$pid"
            while kill -0 "$pid" 2>/dev/null; do
                cnt=`expr "$cnt" + 1`
                if [ "$cnt" -gt 15 ]; then
                    kill -9 "$pid"
                    break
                fi
                sleep 2
                echo -n "."
            done
            echo " Ok"
            exit 0
        fi
        echo " not running."
        exit 0
        ;;

  status)
        echo -n "Checking MMM Agent process:"
        if [ ! -s $MMM_AGENTD_PIDFILE ]; then
            echo " not running."
            exit 3
        fi
        pid="$(cat $MMM_AGENTD_PIDFILE)"
        if ! kill -0 "$pid" 2> /dev/null; then
            echo " not running."
            exit 1
        fi
        echo " running."
        exit 0
        ;;

  restart|reload)
        $0 stop
        $0 start
        exit $?
        ;;

  *)
        echo "Usage: $0 {start|stop|restart|status}"
        ;;
esac

exit 1

(2)在Monitor上启动监控

/etc/init.d/mysql-mmm-monitor start

        /etc/init.d/mysql-mmm-monitor文件内容分如下:

#!/bin/sh
#
# mysql-mmm-monitor  This shell script takes care of starting and stopping
#                    the mmm monitoring daemon.
#
# chkconfig: - 64 36
# description:  MMM Monitor.
# processname: mmm_mond
# config: /etc/mmm_mon.conf
# pidfile: /var/run/mmm_mond.pid

# Cluster name (it can be empty for default cases)
CLUSTER=''


#-----------------------------------------------------------------------
# Paths
if [ "$CLUSTER" != "" ]; then
    MMM_MOND_BIN="/usr/sbin/mmm_mond @$CLUSTER"
    MMM_MOND_PIDFILE="/var/run/mmm_mond-$CLUSTER.pid"
else 
    MMM_MOND_BIN="/usr/sbin/mmm_mond"
    MMM_MOND_PIDFILE="/var/run/mmm_mond.pid"
fi

echo "Daemon bin: '$MMM_MOND_BIN'"
echo "Daemon pid: '$MMM_MOND_PIDFILE'"

#-----------------------------------------------------------------------
# See how we were called.
case "$1" in
  start)
        # Start daemon.
        echo -n "Starting MMM Monitor daemon: "
        if [ -s $MMM_MOND_PIDFILE ] && kill -0 `cat $MMM_MOND_PIDFILE` 2> /dev/null; then
            echo " already running."
            exit 0
        fi
        $MMM_MOND_BIN
        if [ "$?" -ne 0 ]; then
            echo "failed"
            exit 1
        fi
        echo "Ok"
        exit 0
        ;;

  stop)
        # Stop daemon.
        echo -n "Shutting down MMM Monitor daemon: "
        if [ -s $MMM_MOND_PIDFILE ]; then
            pid="$(cat $MMM_MOND_PIDFILE)"
            cnt=0
            kill "$pid"
            while kill -0 "$pid" 2>/dev/null; do
                cnt=`expr "$cnt" + 1`
                if [ "$cnt" -gt 15 ]; then
                    kill -9 "$pid"
                    break
                fi
                sleep 2
                echo -n "."
            done
            echo " Ok"
            exit 0
        fi
        echo " not running."
        exit 0
        ;;

  status)
        echo -n "Checking MMM Monitor process:"
        if [ ! -s $MMM_MOND_PIDFILE ]; then
            echo " not running."
            exit 3
        fi
        pid="$(cat $MMM_MOND_PIDFILE)"
        if ! kill -0 "$pid" 2> /dev/null; then
            echo " not running."
            exit 1
        fi
        echo " running."
        exit 0
        ;;

  restart|reload)
        $0 stop
        $0 start
        exit $?
        ;;

  *)
        echo "Usage: $0 {start|stop|restart|status}"
        ;;
esac

exit 1

(3)检查MMM启动后的状态
        mmm启动成功后,在Monitor上执行mmm_control show和mmm_control checks命令结果如下。

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/ONLINE. Roles: reader(172.16.1.210)
  db2(172.16.1.126) master/ONLINE. Roles: reader(172.16.1.211), writer(172.16.1.100)

[root@hdp4~]#
[root@hdp4~]#mmm_control checks
db2  ping         [last change: 2018/08/02 08:57:38]  OK
db2  mysql        [last change: 2018/08/02 08:57:38]  OK
db2  rep_threads  [last change: 2018/08/02 08:57:38]  OK
db2  rep_backlog  [last change: 2018/08/02 08:57:38]  OK: Backlog is null
db1  ping         [last change: 2018/08/02 08:57:38]  OK
db1  mysql        [last change: 2018/08/02 08:57:38]  OK
db1  rep_threads  [last change: 2018/08/02 08:57:38]  OK
db1  rep_backlog  [last change: 2018/08/02 08:57:38]  OK: Backlog is null

2. 测试切换

(1)停止DB1上MySQL服务

service mysql stop

        查看状态,DB1上的VIP reader(172.16.1.210) 自动迁移到DB2上。

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/HARD_OFFLINE. Roles: 
  db2(172.16.1.126) master/ONLINE. Roles: reader(172.16.1.210), reader(172.16.1.211), writer(172.16.1.100)

[root@hdp4~]#

(2)启动DB1上MySQL服务

service mysql start

        一分钟之后,状态恢复:

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/ONLINE. Roles: reader(172.16.1.210)
  db2(172.16.1.126) master/ONLINE. Roles: reader(172.16.1.211), writer(172.16.1.100)

[root@hdp4~]#

(3)停止DB2上MySQL服务

service mysql stop

        DB2上负责读的VIP(172.16.1.211)以及负责写的VIP(172.16.1.100)会自动迁移到DB1上。

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/ONLINE. Roles: reader(172.16.1.210), reader(172.16.1.211), writer(172.16.1.100)
  db2(172.16.1.126) master/HARD_OFFLINE. Roles: 

[root@hdp4~]#

(4)启动DB2上的MySQL服务

service mysql start

        一分钟之后,DB1上负责读的VIP(172.16.1.210)自动迁移到DB2上,但是负责写的VIP(172.16.1.100),仍在DB1上。

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/ONLINE. Roles: reader(172.16.1.211), writer(172.16.1.100)
  db2(172.16.1.126) master/ONLINE. Roles: reader(172.16.1.210)

[root@hdp4~]#

(5)只读节点上stop slave
        在DB2上停止复制:

mysql> stop slave;

        查看状态,DB2上的VIP(172.16.1.210)会自动迁移到DB1上。

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/ONLINE. Roles: reader(172.16.1.210), reader(172.16.1.211), writer(172.16.1.100)
  db2(172.16.1.126) master/REPLICATION_FAIL. Roles: 

[root@hdp4~]#

(6)只读节点上start slave
        在DB2上启动复制:

mysql> start slave;

        状态恢复:

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/ONLINE. Roles: reader(172.16.1.211), writer(172.16.1.100)
  db2(172.16.1.126) master/ONLINE. Roles: reader(172.16.1.210)

[root@hdp4~]#

(7)读写节点上stop slave
        在DB1上停止复制:

mysql> stop slave;

        查看状态无任何变化。理论上也应该是对现有的环境无任何影响。

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/ONLINE. Roles: reader(172.16.1.211), writer(172.16.1.100)
  db2(172.16.1.126) master/ONLINE. Roles: reader(172.16.1.210)

[root@hdp4~]#

(8)停止MMM监控主机上的monitor服务

/etc/init.d/mysql-mmm-monitor stop

        VIP都还在之前的节点上:

[root@hdp2~]#ip a | grep ens32
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 172.16.1.125/24 brd 172.16.1.255 scope global ens32
    inet 172.16.1.100/32 scope global ens32
    inet 172.16.1.211/32 scope global ens32

[mysql@hdp3~]$ip a | grep ens32
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 172.16.1.126/24 brd 172.16.1.255 scope global ens32
    inet 172.16.1.210/32 scope global ens32

(9)启动MMM监控服务

/etc/init.d/mysql-mmm-monitor start

        对DB1和DB2上的相关服务无影响。

[root@hdp4~]#mmm_control show
  db1(172.16.1.125) master/ONLINE. Roles: reader(172.16.1.211), writer(172.16.1.100)
  db2(172.16.1.126) master/ONLINE. Roles: reader(172.16.1.210)

[root@hdp4~]#

(10)查看监控日志
        以上的角色切换的过程都在监控日志中记录:

[root@hdp4~]#tail -f /var/log/mysql-mmm/mmm_mond.log
...

2018/08/02 09:07:46 FATAL State of host 'db1' changed from ONLINE to HARD_OFFLINE (ping: OK, mysql: not OK)
2018/08/02 09:10:53 FATAL State of host 'db1' changed from HARD_OFFLINE to AWAITING_RECOVERY
2018/08/02 09:11:54 FATAL State of host 'db1' changed from AWAITING_RECOVERY to ONLINE because of auto_set_online(60 seconds). It was in state AWAITING_RECOVERY for 61 seconds
2018/08/02 09:14:06 FATAL State of host 'db2' changed from ONLINE to HARD_OFFLINE (ping: OK, mysql: not OK)
2018/08/02 09:16:22 FATAL State of host 'db2' changed from HARD_OFFLINE to AWAITING_RECOVERY
2018/08/02 09:17:24 FATAL State of host 'db2' changed from AWAITING_RECOVERY to ONLINE because of auto_set_online(60 seconds). It was in state AWAITING_RECOVERY for 62 seconds
2018/08/02 09:20:02 FATAL State of host 'db2' changed from ONLINE to REPLICATION_FAIL
2018/08/02 09:22:14 FATAL State of host 'db2' changed from REPLICATION_FAIL to ONLINE

参考:

文章最后发布于: 2018-08-02 15:45:04
展开阅读全文
0 个人打赏
私信求帮助

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览