一、概述

MMMMaster-Master Replication Manager for MySQLmysql主主复制管理器)

关于MySQL主主复制配置的监控、故障转移和管理的一套可伸缩的脚本套件
(在任何时候只有一个节点可以被写入),

这个套件也能对居于标准的主从配置的任意数量的从服务器进行读负载均衡,
所以你可以用它来在一组居于复制的服务器启动虚拟ip
除此之外,它还有实现数据备份、节点之间重新同步功能的脚本。

MySQL本身没有提供replication failover的解决方案,
通过MMM方案能实现服务器的故障转移,从而实现mysql的高可用。

MMM不仅能提供浮动IP的功能,更可贵的是如果当前的主服务器挂掉后,
会将你后端的从服务器自动转向新的主服务器进行同步复制,
不用手工更改同步配置。这个方案是目前比较成熟的解决方案。

由于MMM无法完全的保证数据一致性,所以MMM适用于对数据的一致性要求不是很高,
但是又想最大程度的保证业务可用性的场景。
对于那些对数据的一致性要求很高的业务,不建议采用MMM这种高可用架构。

总结作用:

  • MMM监控MySQL主从复制健康情况
  • 在主库出现宕机时进行故障转移并自动配置其它从对新主的复制
  • 提供了主,写虚拟IP,在主从服务器出现问题时可以自动迁移虚拟IP

优点:

  • 使用Perl脚本语言开发及完全开源
  • 提供了读写VIP(虛拟IP),使服务器角色的变更对前端应用透明
  • MMM提供了从服务器的延迟监控,如果某一台从服务器的主从延迟超过了某一个配置的值,
    就会自动把产生延迟的这个从服务器的读vip迁移到一台没有延迟的从服务器上,
    使得用户不用担心从服务器延迟或宕机二产生的业务逻辑上的错误
  • MMM提供了主数据库故障转移后从服务器对新主的重新同步功能
  • 很容易对发生故障的主数据库重新上线
  • MMM提供了从服务器的延迟监控

缺点

  • 发布时间比较早不支持 MySQL新的复制功能(比如不支持,GTID复制)
  • 对于 MySQL5.6 后所提供的多线程复制技术也不支持
  • 没有读负载均衡的功能
  • 在进行主从切换时,容易造成数据丢失
    MMM在进行主从切换过程中,并不是通过多个从服务器的日志同步点进行行对比,
    然后与切换后的新主服务器来同步的,而是强硬的从原主服务器,强制切换到主备服务器作为主服务器。
    MySQL这种异步复制的特性,并不能保证我们主备服务器日志点是最新的,所以切换过程中,容易导致事务的丢失的情况。
    同时如果其它从服务器的日志点比主备服务器更新,就会导致重复的数据在从服务器执行。
  • MMM监控服务存在单点故障

二、MMM架构

MMM 基于主主复制建立的,且是基于主主的主备模式,如图虚线部分就是主备服务器


MMM部署所需资源

名称资源 数量 说明
主DB服务器 2 用于主备模式的主主复制配置
从DB服务器 0-N 可以配置0台或多台从服务器,但不建议太多
监控服务器 1 用于监控MSQL复制集群
IP地址 2*(n+1) n为MSQL服务器的数量
监控用户 1 用户于监控数据库状态的MySQL用户(replication client)
代理用户 1 用户MMM代理的 MySQL用户(super,replication client,process)
复制用户 1 用户配置 MySQL复制的MSQL用户(replication slave)

三、MMM部署步骤与拓扑

  1. 配置主主复制及主从同步集群
  2. 安装主从节点所需要的支持包
  3. 安装及配置MMM工具集
  4. 运行MMM监控服务
  5. 测试

MMM演示拓扑图

如图,本机创建了3台服务器,分别是:

主服务器:01 MMM-master:192.168.10.110
主备服务器:02 MMM-master-bak:192.168.10.111
从服务器:03 MMM-slave:192.168.10.112

因为做测试,监控服务器,我们也是用从服务器来做

如图的“虚拟ip”(vip)可以根据自己的情况设置,以下为真实演示配置的vip

192.168.10.90 写vip
192.168.10.91 读vip
192.168.10.92 读vip
192.168.10.93 读vip

四、MMM步骤演示

注意:MMM发布时间较早,不支持myslq新的复制功能,必须是基于日志点的复制
所以我们配置主从的过程,就是按日志点的模式配置

log_slave_updates = on 选项,在主服务器和主备服务器上配置必须打开!
因为主服务器和主备服务器是主主模式,有时会相互作为主服务器或相互作为从服务器,
必须把relay-log里的日志内容再记录到slave本地的binlog里,作为另一个服务器的主服务器时使用


1. 主服务器配置

my.cnf 配置:

bin_log = mysql-bin # 开启bin日志
server_id=110       # 在复制集群中必须唯一

log_slave_updates = on     # 必选,因为主服务器和主备服务器是主主模式,相互作为主服务器或相互作为从服务器
                           # 把relay-log里的日志内容再记录到slave本地的binlog里,作为另一个服务器的主服务器时使用

创建用于从服务器连接的帐号:主服务器、主备服务器都必须要设置

mysql> grant replication slave on *.* to repl@'192.168.10.%' identified by '12345678';
Query OK, 0 rows affected, 1 warning (0.01 sec)

2. 初始化数据库

数据备份,除以是否要备份触发器,存储过程

$ mysqldump --master-data=2 --single-transaction --all-databases  -uroot -p > all.sql

把备份好的数据库文件,传送到其它两台服务器

$ scp -p all.sql 192.168.10.111:/root
$ scp -p all.sql 192.168.10.112:/root

分别在主备,和从服务器上初始化数据

# 如果之前配置过主从,无法导入,可以使用 reset master 或 reset slave重置
$ mysql -uroot -p < all.sql

3. 配置从服务器复制

注意:如果是虚拟机复制的机子,记得修改my.cnf中的server-id,删除数据目录下的auto.cnf
重启对配置文件生效,并初始化server uuid

主备服务器和从服务器分别配置:

bin_log = mysql-bin
server_id = 111            # 这里主备服务器配置是111,从服务器是112
relay_log = mysql-rely-bin # relay_log(中继日志),这个参数默认启用,但是默认名是主机名

log_slave_updates = on     # 主服务器和主备服务器必选,从服务器可选

read_only = on             # 可选,禁止非super权限的用户写权限(建议主从复制的从库启用,只接受从主库过来的数据变更)

4. 启动复制链路

分别在主备,和从服务器上启动链路

基于日志点的复制模式

mysql> change master to master_host='192.168.10.110',
master_user='repl',
master_password='12345678',
master_log_file='mysql-bin.000012',
master_log_pos=194;

启动从服务

mysql> start slave;

查看从服务器状态

mysql> show slave status \G

5. 主与主备相互master - slave

前面已经在主备上设置为从库了,现在反过来,我们要把主备当作主服务器,主服务器当作从库服务器

在主服务器(192.168.10.110)上配置

mysql> change master to master_host='192.168.10.111',
master_user='repl',
master_password='12345678',
master_log_file='mysql-bin.000004',
master_log_pos=154;
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status \G

注意:上面的日志点位置,根据的是主备服务器当前的日志文件,当前的日志偏移量

在主备服务器上执行(192.168.10.111)

mysql> show master status \G
*************************** 1. row ***************************
             File: mysql-bin.000004
         Position: 154
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 719007ed-cb27-11e9-ba47-000c295d2479:1-3
1 row in set (0.00 sec)

6. 安装 EPEL

官方的rpm repository提供的rpm包往往是很滞后的,且提供的rpm包也不够丰富

EPEL恰恰可以解决这两方面的问题,
EPEL是由Fedora社区打造,装上了EPEL之后,就相当于添加了一个第三方源,


安装阿里云提供的 EPEL

wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

7. 安装 mmm

查看要安装的包

$ yum search mmm
mysql-mmm-agent.noarch : MMM Database Server Agent Daemon and Libraries
mysql-mmm-monitor.noarch : MMM Monitor Server Daemon and Libraries
mysql-mmm-tools.noarch : MMM Control Scripts and Libraries
mysql-mmm.noarch : Multi-Master Replication Manager for MySQL
$ yum install mysql-mmm-agent.noarch -y  # 所有db服务器都要安装这个 代理包
$ yum install mysql-mmm* -y              # 在监控的服务器上安装所有的包

8. 新建监控帐号

REPLICATION SLAVE 常用于建立复制时所需要用到的用户权限,
也就是slave server必须被master server授权具有该权限的用户,才能通过该用户复制。
并且”SHOW SLAVE HOSTS”这条命令和REPLICATION SLAVE权限有关,否则执行时会报错:

ERROR 1227 (42000): Access denied; you need (at least one of) the REPLICATION SLAVE privilege(s) for this operation

REPLICATION CLIENT 不可用于建立复制,
有该权限时,只是多了可以使用如”SHOW SLAVE STATUS”、”SHOW MASTER STATUS”等命令。
5.6.6版本以后,也可以使用”SHOW BINARY LOGS”。

主服务器新建监控用户:主服务器、主备服务器都必须要设置

mysql> grant replication client on *.* to mmm_monitor@'192.168.10.%' identified by '12345678';

主服务器新建代理用户:为了故障转移,主从切换;主服务器、主备服务器都必须要设置

mysql> grant super, replication client,process on *.* to mmm_agent@'192.168.10.%' identified by '12345678';

9. mmm 配置

安装完mmm后,在目录 /etc/mysql-mmm 有两个配置文件

mmm_agent.conf
mmm_common.conf

主服务配置 mmm_common.conf,要求这个配置文件在所有的集群节点中都是一致的

注意:如下配置文件的注释,在真实服务器上配置,必须把注释删除,否则报错

active_master_role      writer  # 活动的主服务器上写

<host default>
    cluster_interface       ens33 # 可以使用 ifconfig 查看网络接口
    pid_path                /run/mysql-mmm-agent.pid
    bin_path                /usr/libexec/mysql-mmm/
    replication_user        repl      # 复制的用户
    replication_password    12345678  # 复制的密码
    agent_user              mmm_agent # 代理用户
    agent_password          12345678  # 代理用户密码
</host>

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

<host db2>
    ip      192.168.10.111   # 和 db1 互为主备
    mode    master
    peer    db1
</host>

<host db3>
    ip      192.168.10.112   # 从服务器
    mode    slave
</host>

<role writer>
    hosts   db1, db2         # 写服务器,就是主服务器和主备服务器;一个挂了,就会切换到另一个db作为写
    ips     192.168.10.90   # 对外提供的写操作的虚拟IP
    mode    exclusive        # exclusive代表只允许存在一个主,也就是只能提供一个写的IP
</role>

<role reader>
    hosts   db1, db2, db3    # 对外提供读操作的服务器的host名,当然这里也可以把master加进来
    ips     192.168.10.91,192.168.10.92,192.168.10.93 # 对外提供读操作的虚拟ip,90已经分配到写了,所以这里不要设置90;与上一行host不需要对应
    mode    balanced
</role>

把文件传送到另外两台服务器

scp -p mmm_common.conf root@192.168.10.111:/etc/mysql-mmm/
scp -p mmm_common.conf root@192.168.10.112:/etc/mysql-mmm/

分别把每台服务器的 mmm_agent.conf 修改

include mmm_common.conf

# The 'this' variable refers to this server.  Proper operation requires
# that 'this' server (db1 by default), as well as all other servers, have the
# proper IP addresses set in mmm_common.conf.
this db1  # 服务器分别对应配置的 db1 db2 db3

10. 配置监控服务器

因为是做测试,我们把从服务器当作监控服务器(192.168.10.112

配置 mmm_mon.conf

注意:如下配置文件的注释,在真实服务器上配置,必须把注释删除,否则报错

include mmm_common.conf

<monitor>
    ip                  127.0.0.1
    pid_path            /run/mysql-mmm-monitor.pid
    bin_path            /usr/libexec/mysql-mmm
    status_path         /var/lib/mysql-mmm/mmm_mond.status
    ping_ips            192.168.10.110,192.168.10.111,192.168.10.112 # 网络监测使用的Ips;包括本机ip和db节点的ip
    auto_set_online     60 # 从AWAITING_RECOVERY状态切换到ONLINE状态的时间,单位秒,0=disabled

    # The kill_host_bin does not exist by default, though the monitor will
    # throw a warning about it missing.  See the section 5.10 "Kill Host
    # Functionality" in the PDF documentation.
    #
    # kill_host_bin     /usr/libexec/mysql-mmm/monitor/kill_host
    #
</monitor>

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

debug 0  # 等于1时,启用调试模式

11. 启动 mmm

首先启动db服务器的3个代理

centos7之前的版本,在安装完mmm后,会在 /etc/init.d/ 下生成两个脚本文件

mysql-mmm-agent   # mysql-mmm-agent start 启动代理
mysql-mmm-monitor # mysql-mmm-monitor start 启动监控

centos7直接使用一下方法:

所有db节点,都要启动agent

systemctl enable mysql-mmm-agent
systemctl start mysql-mmm-agent

在监控服务器(监控服务器和从服务器放在一起了)启动monitor

systemctl enable mysql-mmm-monitor
systemctl start mysql-mmm-monitor

12. 查看是否正常运行

检查所有的db服务器群集状态

$ mmm_control checks all
db2  ping         [last change: 2019/08/31 12:00:55]  OK
db2  mysql        [last change: 2019/08/31 12:00:55]  OK
db2  rep_threads  [last change: 2019/08/31 12:00:55]  OK
db2  rep_backlog  [last change: 2019/08/31 12:00:55]  OK: Backlog is null
db3  ping         [last change: 2019/08/31 12:00:55]  OK
db3  mysql        [last change: 2019/08/31 12:00:55]  OK
db3  rep_threads  [last change: 2019/08/31 12:00:55]  OK
db3  rep_backlog  [last change: 2019/08/31 12:00:55]  OK: Backlog is null
db1  ping         [last change: 2019/08/31 12:00:55]  OK
db1  mysql        [last change: 2019/08/31 12:00:55]  OK
db1  rep_threads  [last change: 2019/08/31 12:00:55]  OK

检查群集环境在线状况:根据不同配置情况,和不同状态,查看在线情况

online,都在在线,vip90 的既可以读,也可以写(因为90vip,读写配置项我都设置了)

$ mmm_control show
  db1(192.168.10.110) master/ONLINE. Roles: reader(192.168.10.90), writer(192.168.10.90)
  db2(192.168.10.111) master/ONLINE. Roles: reader(192.168.10.91)
  db3(192.168.10.112) slave/ONLINE. Roles: reader(192.168.10.92)

两台处于 AWAITING_RECOVERY 等待恢复状态,读vip都分配到了db3

$ mmm_control show
  db1(192.168.10.110) master/AWAITING_RECOVERY. Roles: 
  db2(192.168.10.111) master/AWAITING_RECOVERY. Roles: 
  db3(192.168.10.112) slave/ONLINE. Roles: reader(192.168.10.91), reader(192.168.10.92), reader(192.168.10.93)

全部在线的情况

$ mmm_control show
  db1(192.168.10.110) master/ONLINE. Roles: reader(192.168.10.92), writer(192.168.10.90)
  db2(192.168.10.111) master/ONLINE. Roles: reader(192.168.10.91)
  db3(192.168.10.112) slave/ONLINE. Roles: reader(192.168.10.93)

13. 测试切换

直接停用db服务器的mysql,在监控服务器查看master是否切换到主备服务器

(1)在监控服务器查看在线情况:
目前,是111服务器作为主服务器,110为主备服务器,112为从服务器

$ mmm_control show
  db1(192.168.10.110) master/ONLINE. Roles: reader(192.168.10.91)
  db2(192.168.10.111) master/ONLINE. Roles: reader(192.168.10.93), writer(192.168.10.90)
  db3(192.168.10.112) slave/ONLINE. Roles: reader(192.168.10.92)

(2)关闭 111 服务器数据库
111服务器执行:

$ lnmp mysql stop

(3)在监控服务器(112)观察
此时,已经切换到110服务器作为主服务了,显示111服务器状态为OFFLINE

$ mmm_control show
  db1(192.168.10.110) master/ONLINE. Roles: reader(192.168.10.91), writer(192.168.10.90)
  db2(192.168.10.111) master/HARD_OFFLINE. Roles: 
  db3(192.168.10.112) slave/ONLINE. Roles: reader(192.168.10.92), reader(192.168.10.93)

且从服务器对应的主服务器是 110 服务器了

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.10.110
                           ......

五、应用如何接入数据库

我们写的程序,比如是PHP需要链接我们的数据库,直接通过vip即可

需要写的直接使用 192.168.10.90 vip
需要读数据库时,直接使用读 vip 即可,如 192.168.10.91