MySQL high availability construction solution (MMM)

Sometimes the blog content will change. The first blog is the latest, and other blog addresses may not be synchronized. Check it carefully.https://blog.zysicyj.top

Note: This reprinted article is not original

First blog address

Original address


Preface

There are many types of MySQL high availability, including the MMM architecture, MHA architecture, and MGR architecture that we often talk about. In this article, we first discuss the high availability of the MMM architecture, and then analyze MHA and MGR. MGR is somewhat similar to the PXC cluster launched by percona.

Cluster VS High Availability

In MySQL database, what is a cluster? What is high availability? The first thing I understood was that as long as there is a group slave cluster architecture with separation of reading and writing, it means having a highly available architecture. Now think about it, how naive my original idea was. MySQL cluster and MySQL high availability are two concepts, and we cannot confuse them.

A cluster refers to your multiple MySQL database instances. One can provide writing and multiple can provide reading, or multiple can write and multiple can read. For example, we configure a cluster architecture with one master and multiple slaves that separates reading and writing, or a cluster architecture with dual masters and multiple slaves. At this time, we only have a MySQL cluster, which has improved locking performance in reading and writing, but it is not a highly available MySQL architecture at this time.

High availability means that at any time, our MySQL can provide reading and writing services. MySQL data will not be unable to read and write normally due to the downtime of a certain MySQL database instance. This is high availability. In a sense, high availability can only be achieved on the basis of a cluster. In other words, if you want high availability, you must first build a cluster. Only with MySQL cluster can we talk about the high availability of MySQL. Without the MySQL cluster, talking about the high availability of MySQL is like a castle in the air.

Take the MySQL cluster architecture with dual masters and multiple slaves we mentioned earlier. If two masters are at the same point in time, if only one master provides external write services, if one of the masters goes down, the other master can take over. The master provides external writing services, and other slaves can switch synchronized data sources to the new master. Such a cluster is a highly available architecture.

With a MySQL cluster, MySQL does not necessarily have high availability. But if there is high availability of MySQL, then it must be a MySQL cluster at this time. High availability can only be achieved by cooperating with other components on the basis of a cluster.

MMM high availability architecture

What is MMM

所谓的MMM只是:「M」ulti-「M」aster Replication 「M」anager for MySQL,取其中的三个M开头的单词简写。它是mysql多主复制管理器,基于perl实现,关于mysql主主复制配置的监控、故障转移和管理的一套可伸缩的脚本套件(在任何时候只有一个节点可以被写入),MMM也能对从服务器进行读负载均衡,所以可以用它来在一组用于复制的服务器启动虚拟ip,除此之外,它还有实现数 据备份、节点之间重新同步功能的脚本。

MySQL本身没有提供replication failover的解决方案,通过MMM方案 能实现服务器的故障转移,从而实现mysql的高可用。MMM不仅能提供浮动IP的功能,如果当前的主服务器挂掉后,会将你后端的从服务器自动转向新的主服务器进行同步复制,不用手工更改同步配置。

从字面来理解就是它有两个master节点,并且实现了这两个master节点的高可用。它的架构如下所示:

alt

MMM主要功能,由下面三个脚本提供:

  • mmm_mond 负责所有的监控工作的监控守护进程,决定节点的移除(mmm_mond进程定 时心跳检测,失败则将write ip浮动到另外一台master)

  • mmm_agentd 运行在mysql服务器上的代理守护进 程,通过简单远程服务集提供给监控节点

  • mmm_control 通过命令行管理mmm_mond进程 在整个监管过程中, 需要在mysql中添加相关授权用户,授权的用户包括一个mmm_monitor用户和一个mmm_agent用户,如果想使用mmm的备份工具则还要添加一个mmm_tools用户。

MMM架构的优点

  • 可以兼容不同系列的MySQL来做高可用。比如有MySQL官方社区版本,有percona版本的,有MariaDB版本的MySQL。这样的集群可以可以使用MMM架构来做高可用。

  • 高可用性,扩展性好,出现故障自动切换,对于主主同步,在同一时间只提供一台数据库写操作,保证 的数据的一致性。

  • 当主服务器挂掉以后,另一个主立即接管,其他的从服务器能自动切换,不用人工干预。

MMM架构的缺点

  • 是一种比较老的MySQL高可用实现方式,因为社区不活跃,所以目前已经没有人在维护这个组件了。

  • 只能基于日之点的主从复制集群架构来做高可用,不支持基于GTID的主从复制集群架构。这也是因为社区活跃,没有维护这个组件导致不支持GTID。

  • 数据不能保证100%的一致性,这个是以为它在做故障转移的时候实现的方式所导致的。如果对于数据需要强一致性,则不能选择MMM高可用架构,可以考虑MHA高可用架构。

  • monitor节点是单点,不过这个可以结合keepalived或者haertbeat做成高可用。

  • 至少三个节点,2个master,1个slave,对主机的数量有要求,

  • 在读写非常繁忙的业务系统下表现不是很稳定,可能会出现复制延时、切换失效等问题。

  • MMM方案并不太适应于对数据安全性要求很高,并且读、写 繁忙的环境中。

  • 需要实现读写分离,还需要在前端编写读写分离程序,或者结合数据库中间件如mycat来解决。

如何搭建MMM高可用架构

要想实现MMM高可用架构,我们先来搭建一个双主双从的MySQL集群,然后在这个集群的基础上来完成MMM高可用的架构。

我们准备搭建的MySQL-MMM高可用架构的网络拓扑如下所示:需要注意的是其中的VIP,这几个IP不需要我们自己创建,MMM服务会自动的在各个节点分配这些VIP。其中的绿色字体read vip,它并不会严格的按照我们下图中分配是主机来分配,而是随机的将这4个read vip分布到4个数据库节点上,但是红色字体的write vip只会在master1或master2上面随着master1和master2节点宕机和恢复来回切换。

alt

搭建双主双从的MySQL集群

准备MySQL数据库环境

我们使用docker来启动4个MySQL容器,作为双主双从的四个MySQL数据库实例。容器镜像的名称为mysql:5.7.31
,这个镜像是docker hub上面MySQL官方提供的镜像,它是基于Debian buster
版本制作的MySQL容器镜像。所以,我们的MySQL数据库服务器,可以任务是一个minimal版本的Debian系统。

为了方便管理,我们先创建一个docker虚拟网段,然后在启动四个MySQL数据库的时候,指定数据库服务器的IP地址并且使用这个网段。创建网段的命令如下:

docker network create --subnet=172.20.0.0/24 mysql-ha-mmm-network

我们使用下面的四条命令,启动4个MySQL数据库实例。这里我们把每一个数据库的`my.cnf`  
配置文件已经在本地配置好,然后通过数据卷的方式挂载到MySQL容器中,这样我们启动的MySQL数据库实例就会按照我们配置的`my.cnf`  
配置文件来启动并配置我们的MySQL数据库实例。

#
 启动master1节点  
docker run --net=mysql-ha-mmm-network --hostname master1.mysql --ip 172.20.0.11 --cap-add NET\_ADMIN --name
mysql-ha-mmm-master1 -d -v Users/coder-home/docker\_mysql\_ha/mmm/master1:/etc/mysql/conf.d -e MYSQL\_ROOT_PASSWORD=root
-e TZ="Asia/Shanghai" -p 33011:3306 mysql:5.7.31

#
 启动slave1节点  
docker run --net=mysql-ha-mmm-network --hostname slave1.mysql --ip 172.20.0.12 --cap-add NET\_ADMIN --name
mysql-ha-mmm-slave1 -d -v Users/coder-home/docker\_mysql\_ha/mmm/slave1:/etc/mysql/conf.d -e MYSQL\_ROOT_PASSWORD=root
-e TZ="Asia/Shanghai" -p 33012:3306 mysql:5.7.31

#
 启动master2节点  
docker run --net=mysql-ha-mmm-network --hostname master2.mysql --ip 172.20.0.21 --cap-add NET\_ADMIN --name
mysql-ha-mmm-master2 -d -v Users/coder-home/docker\_mysql\_ha/mmm/master2:/etc/mysql/conf.d -e MYSQL\_ROOT_PASSWORD=root
-e TZ="Asia/Shanghai" -p 33021:3306 mysql:5.7.31

#
 启动slave2节点  
docker run --net=mysql-ha-mmm-network --hostname slave2.mysql --ip 172.20.0.22 --cap-add NET\_ADMIN --name
mysql-ha-mmm-slave2 -d -v Users/coder-home/docker\_mysql\_ha/mmm/slave2:/etc/mysql/conf.d -e MYSQL\_ROOT_PASSWORD=root
-e TZ="Asia/Shanghai" -p 33022:3306 mysql:5.7.31

这里解释一下docker run
后面几个重要的参数和含义。

  • --net=mysql-ha-mmm-network:指定容器运行的时候使用的网段。

  • --hostname slave2.mysql:指定容器的主机名称。

  • --ip 172.20.0.22:指定容器使用的IP地址。

  • --cap-add NET_ADMIN:默认容器运行的时候,没有增加额外的Linux的功能,这里我们要增加上NET_ADMIN的功能,否则我们不能再启动后的容器内使用ifconfig命令增加虚拟IP。否则会有如下错误提示:

root@test:/etc/network# ifconfig eth0:0 192.168.1.100 up  
SIOCSIFADDR: Operation not permitted  
SIOCSIFFLAGS: Operation not permitted  
SIOCSIFFLAGS: Operation not permitted  
root@test:/etc/network#
  • --name mysql-ha-mmm-slave2:指定容器的名称为mysql-ha-mmm-slave2
    ,后面我们在停止或重启容器的时候,可以通过这个名称来操作容器。

  • -d:以demon进程的方式运行容器。

  • -v Users/coder-home/docker_mysql_ha/mmm/slave2: /etc/mysql/conf.d:把本地的/Users/coder-home/docker_mysql_ha/mmm/slave2
    目录挂载到容器中的/etc/mysql/conf.d
    目录下。

  • -e MYSQL_ROOT_PASSWORD=root:向容器内传入参数,我们指定MySQL数据库root用户的密码也为root。

  • -e TZ="Asia/Shanghai":向容器内传入参数,这里我们指定的容器中使用的系统的时区为上海时间。

  • -p 33022:3306:我们指定容器中的3306端口,映射到我们本地为33022。这样我们在本地访问MySQL服务的时候,就可以通过33022端口来访问。

  • mysql:5.7.31:这个是我们要运行的容器的名称和版本。如果本地没有这个容器名称和版本,则会从docker hub中自动拉取这个镜像名称和版本到本地,然后再启动这个镜像。

容器启动后,我们可以查看启动后的结果如下:

➜  ~ docker ps  
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES  
5207089da9a5 mysql:5.7.31        "docker-entrypoint.s…"   About a minute ago Up About a minute 33060/tcp, 0.0.0.0:
33022->3306/tcp mysql-ha-mmm-slave2  
1c8ff5960272 mysql:5.7.31        "docker-entrypoint.s…"   About a minute ago Up About a minute 33060/tcp, 0.0.0.0:
33021->3306/tcp mysql-ha-mmm-master2  
d8d646ba25f1 mysql:5.7.31        "docker-entrypoint.s…"   About a minute ago Up About a minute 33060/tcp, 0.0.0.0:
33012->3306/tcp mysql-ha-mmm-slave1  
d3d75d9cd930 mysql:5.7.31        "docker-entrypoint.s…"   About a minute ago Up About a minute 33060/tcp, 0.0.0.0:
33011->3306/tcp mysql-ha-mmm-master1  
➜  ~

下面我们查看每一个MySQL数据库容器的host文件中的IP地址:

  • master1的host文件如下:
➜ ~ docker exec -it mysql-ha-mmm-master1 bin/bash  
root@master1:/# cat etc/hosts  
127.0.0.1 localhost  
::1 localhost ip6-localhost ip6-loopback  
fe00::0 ip6-localnet  
ff00::0 ip6-mcastprefix  
ff02::1 ip6-allnodes  
ff02::2 ip6-allrouters  
172.20.0.11 master1.mysql master1  
root@master1:/#
  • master2的host文件如下:
➜  ~ docker exec -it mysql-ha-mmm-master2 bin/bash  
root@master2:/# cat etc/hosts  
127.0.0.1 localhost  
::1 localhost ip6-localhost ip6-loopback  
fe00::0 ip6-localnet  
ff00::0 ip6-mcastprefix  
ff02::1 ip6-allnodes  
ff02::2 ip6-allrouters  
172.20.0.21 master2.mysql master2  
root@master2:/#
  • slave1的host文件如下:
➜  ~ docker exec -it mysql-ha-mmm-slave1 bin/bash  
root@slave1:/# cat etc/hosts  
127.0.0.1 localhost  
::1 localhost ip6-localhost ip6-loopback  
fe00::0 ip6-localnet  
ff00::0 ip6-mcastprefix  
ff02::1 ip6-allnodes  
ff02::2 ip6-allrouters  
172.20.0.12 slave1.mysql slave1  
root@slave1:/#
  • slave2的host文件如下:
➜  ~ docker exec -it mysql-ha-mmm-slave2 bin/bash  
root@slave2:/# cat etc/hosts  
127.0.0.1 localhost  
::1 localhost ip6-localhost ip6-loopback  
fe00::0 ip6-localnet  
ff00::0 ip6-mcastprefix  
ff02::1 ip6-allnodes  
ff02::2 ip6-allrouters  
172.20.0.22 slave2.mysql slave2  
root@slave2:/#

上面我们启动的四个MySQL数据库实例,我们还需要一个监控节点,下面启动一个监控节点,用于安装MMM的监控服务。

为了和其他环境一致,这里我们也使用上面MySQL的镜像。如下是启动一个新的MySQL容器,这个容器,我们不在挂载MySQL的my.cnf配置文件了,因为这个MySQL数据库我们不会使用,我们只是在这个容器中安装MMM的监控服务,我们此时把这个MySQL数据库容器当成一个Debian版本的虚拟机来使用。

启动监控节点

docker run --net=mysql-ha-mmm-network --hostname monitor.mysql --ip 172.20.0.10 --cap-add NET\_ADMIN --name
mysql-ha-mmm-monitor -d -e MYSQL\_ROOT_PASSWORD=root -e TZ="Asia/Shanghai" -p 33010:3306 mysql:5.7.31

查看这个监控节点的host文件如下:

➜  ~ docker exec -it mysql-ha-mmm-monitor bin/bash  
root@monitor:~# cat etc/hosts  
127.0.0.1 localhost  
::1 localhost ip6-localhost ip6-loopback  
fe00::0 ip6-localnet  
ff00::0 ip6-mcastprefix  
ff02::1 ip6-allnodes  
ff02::2 ip6-allrouters  
172.20.0.10 monitor.mysql monitor  
root@monitor:~#

创建主从同步的数据库用户

在组从同步的时候,从需要使用一个指定的用户去连接到主上面同步主上面的binlog日志。所以,我们需要在我们的主上面创建好这样的一个用户。因为在master1宕机之后,MMM组件会将master2提升为新的主库,所以需要在master1和master2上面都创建一个这样的用户,也就是下的命令需要在两个master节点上都执行一下。

create user 'repl_user'@'172.20.0.%' identified by 'repl_user';  
grant replication slave on *.* to 'repl_user'@'172.20.0.%';

历史数据的同步

如果我们并不是基于一个新的集群环境来搭建,而是基于一个已经运行了一段时间的MySQL数据库来做集群,此时我们需要把选定的master节点上面的数据,先使用mysqldump
命令导出为.sql
文件,然后再把这个.sql
文件导入到所有的slave节点上去。然后在可以开始下面的任务。

在master上面执行的导出的命令示例如下:

mysqldump -uroot -proot \  
--master-data=2 \  
--single-transaction \  
--flush-logs \  
--triggers \  
--routines \  
--events \  
-B mydb1 > mydb1.sql

在所有的slave节点上执行的导入数据的命令示例如下:

mysql -uroot -proot < mydb1.sql

但是,我们是基于一个崭新的环境来做的,不涉及到历史数据的问题。所以,这一步我们可以省略。

开启组从同步

在所有的slave上面执行如下命令,此时的binlog文件和日志点的位置,可以在master1上面使用show master status
命令查看,或者查看导出数据的时候,生成的.sql
文件。在master1节点上执行mysqldump
导出命令的时候,我们指定的--master-data=2
,这个参数会在导出的.sql
文件中标记当前master1节点上binlog日志的文件名称和日志偏移量。

change master to master_host='172.20.0.11', master_user='repl_user', master_password='repl_user',
MASTER\_LOG\_FILE='mysql-bin.000003', MASTER\_LOG\_POS=1034;

开启组从同步:

start slave;

查看同步状态:

mysql> show slave status\\G  
*************************** 1. row ***************************  
Slave\_IO\_State: Waiting for master to send event  
Master_Host: 172.20.0.11  
Master\_User: repl\_user  
Master_Port: 3306  
Connect_Retry: 60  
Master\_Log\_File: mysql-bin.000003  
Read\_Master\_Log_Pos: 1034  
Relay\_Log\_File: mysql-relay.000002  
Relay\_Log\_Pos: 320  
Relay\_Master\_Log_File: mysql-bin.000003  
Slave\_IO\_Running: Yes  
Slave\_SQL\_Running: Yes  
Replicate\_Do\_DB:  
Replicate\_Ignore\_DB:  
Replicate\_Do\_Table:  
Replicate\_Ignore\_Table:  
Replicate\_Wild\_Do_Table:  
Replicate\_Wild\_Ignore_Table:  
Last_Errno: 0  
Last_Error:  
Skip_Counter: 0  
Exec\_Master\_Log_Pos: 1034  
Relay\_Log\_Space: 523  
Until_Condition: None  
Until\_Log\_File:  
Until\_Log\_Pos: 0  
Master\_SSL\_Allowed: No  
Master\_SSL\_CA_File:  
Master\_SSL\_CA_Path:  
Master\_SSL\_Cert:  
Master\_SSL\_Cipher:  
Master\_SSL\_Key:  
Seconds\_Behind\_Master: 0  
Master\_SSL\_Verify\_Server\_Cert: No  
Last\_IO\_Errno: 0  
Last\_IO\_Error:  
Last\_SQL\_Errno: 0  
Last\_SQL\_Error:  
Replicate\_Ignore\_Server_Ids:  
Master\_Server\_Id: 11  
Master_UUID: 047bcc07-7424-11eb-96b4-0242ac14000b  
Master\_Info\_File: mysql.slave\_master\_info  
SQL_Delay: 0  
SQL\_Remaining\_Delay: NULL  
Slave\_SQL\_Running_State: Slave has read all relay log; waiting for more updates  
Master\_Retry\_Count: 86400  
Master_Bind:  
Last\_IO\_Error_Timestamp:  
Last\_SQL\_Error_Timestamp:  
Master\_SSL\_Crl:  
Master\_SSL\_Crlpath:  
Retrieved\_Gtid\_Set:  
Executed\_Gtid\_Set:  
Auto_Position: 0  
Replicate\_Rewrite\_DB:  
Channel_Name:  
Master\_TLS\_Version:  
1 row in set (0.00 sec)

mysql>

配置主与主的同步

上面我们配置好了master1->slave1,master1->slave2
的同步。我们还需要在master1和master2直接配置互相同步对方。

现在master2上面配置master1作为它的主库。参考上面slave1和slave2上面的配置。执行如下命令:

change master to master_host='172.20.0.11', MASTER\_LOG\_FILE='mysql-bin.000003', MASTER\_LOG\_POS=1034;

start slave user='repl_user' password='repl_user';

show slave status\\G

然后再配置master2到master1的同步。此时我们需要查看一下master2上面的binlog日志名称和日志偏移量是多少。使用如下命令查看:

mysql> show master status\\G  
*************************** 1. row ***************************  
File: mysql-bin.000003  
Position: 623  
Binlog\_Do\_DB:  
Binlog\_Ignore\_DB:  
Executed\_Gtid\_Set:  
1 row in set (0.00 sec)
mysql>

然后我们登录到master1上面,执行如下命令,配置master2作为master1的主库。

change master to master_host='172.20.0.21', MASTER\_LOG\_FILE='mysql-bin.000003', MASTER\_LOG\_POS=623;

start slave user='repl_user' password='repl_user';

show slave status\\G

验证双主双从同步的效果如下:

alt

安装MMM

修改apt-get源

在下载MMM之前,我们先修改一下apt-get
源,然后更新一下apt-get
源。如下所示,因为此时的容器中,没有vim
命令,所以我们使用echo "xxx" >/etc/apt/sources.list
的方式去更新apt-get
的源。

echo "  
deb http://mirrors.aliyun.com/debian/ buster main non-free contrib  
deb http://mirrors.aliyun.com/debian-security buster/updates main  
deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib  
deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib

deb-src http://mirrors.aliyun.com/debian-security buster/updates main  
deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib  
deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib  
deb-src http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib  
" > etc/apt/sources.list

注意,在更新镜像源的时候,要根据自己的Debian系统的版本,我的Debian系统的版本是buster
版本,所以你要根据自己的系统版本网上找到对应的镜像地址。接着,我们更新一下系统。

root@master1:/etc/apt# apt-get update  
Get:1 http://security.debian.org/debian-security buster/updates InRelease \[65.4 kB\]  
Get:2 http://repo.mysql.com/apt/debian buster InRelease \[21.5 kB\]  
Get:3 http://mirrors.ustc.edu.cn/debian buster InRelease \[122 kB\]  
Get:4 http://security.debian.org/debian-security buster/updates/main amd64 Packages \[267 kB\]  
Get:5 http://mirrors.ustc.edu.cn/debian buster-updates InRelease \[51.9 kB\]  
Get:6 http://mirrors.ustc.edu.cn/debian buster/main amd64 Packages \[7907 kB\]  
Get:7 http://repo.mysql.com/apt/debian buster/mysql-5.7 amd64 Packages \[5693 B\]  
Get:8 http://mirrors.ustc.edu.cn/debian buster-updates/main amd64 Packages \[9504 B\]  
Fetched 8450 kB in 10s (871 kB/s)  
Reading package lists... Done  
root@master1:/etc/apt#

更新完成之后,我们先安装一下我们经常用到的几个命令:

apt-get install net-tools wget vim make cmake inetutils-ping iproute2 iproute2-doc -y

下载MMM

推荐使用源码来安装,这样可以在任何Linux系统版本上面进行安装,例如:Ubuntu、Debian、CentOS、Redhat等等。不用因为系统版本的问题找对应的rpm
包,找对应的deb
包。

通过如下步骤来获取MMM的源码。

登录Debian的官方网站:https://www.debin.org,然后点击跟多关于下载与软件介绍的连接。

alt

此时我们会进入如下页面:https://www.debian.org/intro/index#software,然后点击软件包连接。

alt

接着,我们会进入如下页面:https://www.debian.org/distrib/packages#search_packages,根据选项输入mysql-mmm
,点击搜索按钮。

alt

点击上面的搜索按钮后,进入如下页面:https://packages.debian.org/search?keywords=mysql-mmm&searchon=names&suite=oldstable&section=all,然后我们点击页面中的Debian系统的版本,选择jessie
版本,因为mysql-mmm
是比较老的一种MySQL考可用架构,在最新的Debian系统中,已经没有这样的软件包了,所以我们选择老版本的jessie
版本,这个版本中包含mysql-mmm
的源码。

alt

点击完成jessie
之后,进入如下页面:https://packages.debian.org/search?suite=jessie&searchon=names&keywords=mysql-mmm,此时我们已经搜索到了mysql-mmm
的软件。点击其中任何一个链接,进入详细页面。

alt

进入如下的页面:https://packages.debian.org/jessie/mysql-mmm-tools,我们选择下载源码文件。

或者我们可以右键复制下载地址:http://deb.debian.org/debian/pool/main/m/mysql-mmm/mysql-mmm_2.2.1.orig.tar.gz,使用wget命令下载源码到MySQL服务器上。

wget http://deb.debian.org/debian/pool/main/m/mysql-mmm/mysql-mmm_2.2.1.orig.tar.gz
alt

如果要下载.deb文件,可以点击上面图片中的硬件架构下面的all
连接,进入下面页面后,选择对应的距离我们最近镜像地址,我选择的为ftp.cn.debian.org
这个镜像地址,然后复制下载链接地址,使用wget下载即可。这里贴出如下的下载示例:

wget http://ftp.cn.debian.org/debian/pool/main/m/mysql-mmm/mysql-mmm-tools\_2.2.1-1.1\_all.deb  
wget http://ftp.cn.debian.org/debian/pool/main/m/mysql-mmm/mysql-mmm-monitor\_2.2.1-1.1\_all.deb  
wget http://ftp.cn.debian.org/debian/pool/main/m/mysql-mmm/mysql-mmm-common\_2.2.1-1.1\_all.deb  
wget http://ftp.cn.debian.org/debian/pool/main/m/mysql-mmm/mysql-mmm-agent\_2.2.1-1.1\_all.deb
alt

编译安装MMM

我们是使用的MySQL的容器镜像来启动的MySQL集群,而这个从docker hub上面拉取的MySQL5.7官方版本的镜像是基于Debian系统来制作的,所以我们此次安装MMM软件需要基于Debian系统来安装。

下载好的mysql-mmm
如下所示:

root@test:~# ls -lstr  
total 60  
56 -rw-r--r-- 1 root root 55278 Feb 21 16:22 mysql-mmm_2.2.1.orig.tar.gz  
4 drwxr-xr-x 2 root root 4096 Feb 21 16:24 deb  
root@test:~#

解压并且安装,但是在安装MMM之前,先安装一下它的依赖包,使用如下命令来安装:

apt-get install liblog-log4perl-perl libmailtools-perl liblog-dispatch-perl libclass-singleton-perl libproc-daemon-perl
libalgorithm-diff-perl libdbi-perl libdbd-mysql-perl -y

安装MMM的命令和过程如下:

root@test:~# tar -zxf mysql-mmm_2.2.1.orig.tar.gz  
root@test:~# ls -lstr  
total 64  
4 drwxr-xr-x 6 root root 4096 May 7 2010 mysql-mmm-2.2.1  
56 -rw-r--r-- 1 root root 55278 Feb 21 16:22 mysql-mmm_2.2.1.orig.tar.gz  
4 drwxr-xr-x 2 root root 4096 Feb 21 16:24 deb  
root@test:~# cd mysql-mmm-2.2.1/  
root@test:~/mysql-mmm-2.2.1# make install  
mkdir -p usr/share/perl5/MMM usr/lib/mysql-mmm usr/sbin var/log/mysql-mmm etc etc/mysql-mmm etc/init.d/  
cp -r lib/Common/ usr/share/perl5/MMM  
\[ -f etc/mysql-mmm/mmm_common.conf \] || cp etc/mysql-mmm/mmm_common.conf etc/mysql-mmm/  
mkdir -p usr/lib/mysql-mmm/agent/  
cp -r lib/Agent/ usr/share/perl5/MMM  
cp -r bin/agent/* usr/lib/mysql-mmm/agent/  
cp -r etc/init.d/mysql-mmm-agent etc/init.d/  
cp sbin/mmm_agentd usr/sbin  
\[ -f etc/mysql-mmm/mmm_agent.conf \] || cp etc/mysql-mmm/mmm_agent.conf etc/mysql-mmm/  
mkdir -p usr/lib/mysql-mmm/monitor/  
cp -r lib/Monitor/ usr/share/perl5/MMM  
cp -r bin/monitor/* usr/lib/mysql-mmm/monitor/  
cp -r etc/init.d/mysql-mmm-monitor etc/init.d/  
cp sbin/mmm\_control sbin/mmm\_mond usr/sbin  
\[ -f etc/mysql-mmm/mmm_mon.conf \] || cp etc/mysql-mmm/mmm_mon.conf etc/mysql-mmm/  
mkdir -p usr/lib/mysql-mmm/tools/  
cp -r lib/Tools/ usr/share/perl5/MMM  
cp -r bin/tools/* usr/lib/mysql-mmm/tools/  
cp sbin/mmm\_backup sbin/mmm\_clone sbin/mmm_restore usr/sbin  
\[ -f etc/mysql-mmm/mmm_tools.conf \] || cp etc/mysql-mmm/mmm_tools.conf etc/mysql-mmm/  
root@test:~/mysql-mmm-2.2.1#

如果在安装mmm
的时候,提示没有make
命令,则需要先安装make
命令,安装的时候如果是Debian或Ubuntu系统,使用如下apt-get命令安装:

apt-get install make cmake -y

如果是CentOS或Redhat系统,则使用如下的yum命令来安装:

yum install make cmake -y

以上编译安装MMM需要在每一个节点都执行,包括两个master节点和两个slave节点,还有monitor监控节点也要安装。

安装完MMM之后,我们需要注意一下几个目录,这是我们使用MMM服务的基础。

# MMM各种配置文件所在目录  
/etc/mysql-mmm
# MMM服务日志文件所在目录  
/var/log/mysql-mmm/mmm_mond.log # MMM的monitor服务的日志文件  
/var/log/mysql-mmm/mmm_agentd.log # MMM的agent服务的日志文件
# 各种perl脚本所在目录  
/usr/lib/mysql-mmm/agent # agent客户端各种脚本所在目录  
/usr/lib/mysql-mmm/monitor # monitor监控端各种脚本所在目录  
/usr/lib/mysql-mmm/tools # 工具包脚本所在目录
# 启动和关闭MMM服务的脚本文件  
/etc/init.d/mysql-mmm-agent  
/etc/init.d/mysql-mmm-monitor

创建MMM使用的MySQL用户

监控用和客户端用户,在所有的节点上都要创建这两个用户。如果已经配置组从同步,在master1上创建就OK,其他节点会自动同步这两个创建好的用户到其他节点。

create user 'mmm_monitor'@'172.20.0.%' identified by 'mmm_monitor';  
grant replication client on *.* to 'mmm_monitor'@'172.20.0.%';

create user 'mmm_agent'@'172.20.0.%' identified by 'mmm_agent';  
grant super, replication client, process on *.* to 'mmm_agent'@'172.20.0.%';

需要注意的是这两个用户的权限不同,结合前面我们配置组从同步的哪一个用户,我们来对比一下:

  • monitor:MMM监控使用的用户,拥有replication client权限就可以。

  • agent:MMM客户单使用的用,拥有super、replication client、process权限。

  • replication:组从同步使用的用户,拥有replication slave权限即可。

最后的用户在四个节点上面的结果如下图所示:

alt

修改MMM的配置文件

MMM所有的配置文件都在如下目录中:

root@master1:/etc/mysql-mmm# ls -lstr etc/mysql-mmm/*  
4 -rw-r----- 1 root root 321 Feb 22 21:46 etc/mysql-mmm/mmm_mon.conf  
4 -rw-r----- 1 root root 1293 Feb 22 21:46 etc/mysql-mmm/mmm_tools.conf  
4 -rw-r----- 1 root root 37 Feb 22 22:21 etc/mysql-mmm/mmm_agent.conf  
4 -rw-r----- 1 root root 789 Feb 22 23:20 etc/mysql-mmm/mmm_common.conf  
root@master1:/etc/mysql-mmm#

「mmm_comm.conf配置文件」

所有5个节点中的/etc/mysql-mmm/mmm_common.conf
配置文件都修改为如下所示的内容。

root@master1:/etc/mysql-mmm# cat mmm_common.conf

active\_master\_role writer
<host default>  
# 网卡的名称,各个主机上面网络设备的名称  
 cluster_interface  eth0

 pid\_path   /var/run/mmm\_agentd.pid  
 bin_path   /usr/lib/mysql-mmm/
# 主从复制用户名和密码  
replication\_user repl\_user  
replication\_password repl\_user
# MMM服务使用的anget用户名和密码  
agent\_user mmm\_agent  
agent\_password mmm\_agent
</host>
# master1的配置信息  
<host master1>  
ip 172.20.0.11  
mode master  
peer master2  
</host>

#
 master2的配置信息  
<host master2>  
ip 172.20.0.21  
mode master  
peer master1  
</host>

#
 slave1的配置信息  
<host slave1>  
ip 172.20.0.12  
mode slave  
</host>

#
 slave2的配置信息  
<host slave2>  
ip 172.20.0.22  
mode slave  
</host>

#
 写虚拟IP的配置信息,指定可写的主机名称  
<role writer>  
hosts master1, master2  
ips 172.20.0.100  
mode exclusive  
</role>

#
 读虚拟IP的配置信息,指定可以提供读服务的主机名称。下面的VIP和主键名称不一定是一一对应的,VIP是随机分布到各个可读节点的。  
# 如果提供多个VIP,有可能一个节点被分配多个VIP,这样也是支持的。  
<role reader>  
hosts master1, master2, slave1, slave2  
ips 172.20.0.111, 172.20.0.211, 172.20.0.122, 172.20.0.222  
mode balanced  
</role>
root@master1:/etc/mysql-mmm#

上面的role reader
中配置的可读节点,可以根据自己的需求来配置,这里我把master1, master2, slave1, slave2
都作为可读的节点,当然可以把主节点master1
去掉,只配置master2, slave1, slave2
三个节点。这里的ips
也是我们指定的VIP的值,我们可以配置多个VIP,最好是VIP的个数和上面的host的数目一致,表示每一个提供读的节点分配一个VIP。

「mmm_agent.conf配置文件」

每一个节点上面的/etc/mysql-mmm/mmm_agent.conf
配置文件中,都在第2行中,修改一下主机名称。下面给出master1节点的配置如下:

root@master1:/etc/mysql-mmm# cat mmm_agent.conf  
include mmm_common.conf  
this master1  
root@master1:/etc/mysql-mmm#

其他master2、slave1、slave2各个节点也需要作出对应的修改。只要把master1改为对应的主机名称即可。

「mmm_mon.conf配置文件」

在monitor节点上,修改/etc/mysql-mmm/mmm_mon.conf
配置文件,修改内容如下所示,其他四个节点不需要对这个文件做修改。

root@monitor:/etc/mysql-mmm# cat mmm_mon.conf  
include mmm_common.conf

<monitor>  
 ip     127.0.0.1  
 pid\_path    /var/run/mmm\_mond.pid  
 bin_path    /usr/lib/mysql-mmm/  
 status\_path    /var/lib/misc/mmm\_mond.status  
 ping_ips    172.20.0.1, 172.20.0.11, 172.20.0.21, 172.20.0.12, 172.20.0.22 # 网关IP地址,和各个节点的物理IP地址,用于监控各个节点的状态是否可用  
</monitor>

#
 MMM服务使用MySQL中的monitor用户名称和密码  
<host default>  
monitor\_user mmm\_monitor  
monitor\_password mmm\_monitor  
</host>

#

debug值为0非debug模式,为1的时候表示debug模式,debug模式下,会在/var/log/mysql-mmm/mmm_mond.log日志文件中生成更多日志信息。  
debug 0  
root@monitor:/etc/mysql-mmm#

启动MMM服务

客户端agent服务相关命令如下,客户端agent启动后日志存放在/var/log/mysql-mmm/mmm_agentd.log
文件中。

/etc/init.d/mysql-mmm-agent start  
/etc/init.d/mysql-mmm-agent status  
/etc/init.d/mysql-mmm-agent stop  
/etc/init.d/mysql-mmm-agent restart

监控端monitor服务相关命令如下,监控端monitor启动后日志存放在/var/log/mysql-mmm/mmm_mond.log
文件中。

/etc/init.d/mysql-mmm-monitor start  
/etc/init.d/mysql-mmm-monitor status  
/etc/init.d/mysql-mmm-monitor stop  
/etc/init.d/mysql-mmm-monitor restart

MMM监控状态有一个管理命令mmm_control
,它的使用帮助如下所示:

root@monitor:/# mmm_control --help  
Invalid command '--help'

Valid commands are:  
help \- show this message  
ping \- ping monitor  
show - show status  
checks \[<host>|all \[<check>|all\]\] - show checks status  
set_online <host>                 \- set host <host> online  
set_offline <host>                \- set host <host> offline  
mode - print current mode.  
set_active - switch into active mode.  
set_manual - switch into manual mode.  
set_passive - switch into passive mode.  
move_role \[--force\] <role> <host> \- move exclusive role <role> to host <host>  
(Only use --force if you know what you are doing!)  
set_ip <ip> <host>                \- set role with ip <ip> to host <host>

root@monitor:/#

常用的维护节点状态的命令如下:

mmm_control show  
mmm_control checks all  
mmm\_control set\_online master1  
mmm\_control set\_online master2  
mmm\_control set\_online slave1  
mmm\_control set\_online slave2

「下面分别在四个MySQL节点上执行如下命令启动并查看MMM的客户端服务」

  • master1主节点上,启动和查看MMM的客户端服务如下:
root@master1:/etc/mysql-mmm# etc/init.d/mysql-mmm-agent start  
Daemon bin: '/usr/sbin/mmm_agentd'  
Daemon pid: '/var/run/mmm_agentd.pid'  
Starting MMM Agent daemon... Ok

root@master1:/etc/mysql-mmm# etc/init.d/mysql-mmm-agent status  
Daemon bin: '/usr/sbin/mmm_agentd'  
Daemon pid: '/var/run/mmm_agentd.pid'  
Checking MMM Agent process: running.  
root@master1:/etc/mysql-mmm#
  • master2主节点上,启动和查看MMM的客户端服务如下:
root@master2:/etc/mysql-mmm# etc/init.d/mysql-mmm-agent start  
Daemon bin: '/usr/sbin/mmm_agentd'  
Daemon pid: '/var/run/mmm_agentd.pid'  
Starting MMM Agent daemon... Ok

root@master2:/etc/mysql-mmm# etc/init.d/mysql-mmm-agent status  
Daemon bin: '/usr/sbin/mmm_agentd'  
Daemon pid: '/var/run/mmm_agentd.pid'  
Checking MMM Agent process: running.  
root@master2:/etc/mysql-mmm#
  • slave1主节点上,启动和查看MMM的客户端服务如下:
root@slave1:/etc/mysql-mmm# etc/init.d/mysql-mmm-agent start  
Daemon bin: '/usr/sbin/mmm_agentd'  
Daemon pid: '/var/run/mmm_agentd.pid'  
Starting MMM Agent daemon... Ok

root@slave1:/etc/mysql-mmm# etc/init.d/mysql-mmm-agent status  
Daemon bin: '/usr/sbin/mmm_agentd'  
Daemon pid: '/var/run/mmm_agentd.pid'  
Checking MMM Agent process: running.  
root@slave1:/etc/mysql-mmm#
  • slave2主节点上,启动MMM的客户端服务如下:
root@slave2:/etc/mysql-mmm# etc/init.d/mysql-mmm-agent start  
Daemon bin: '/usr/sbin/mmm_agentd'  
Daemon pid: '/var/run/mmm_agentd.pid'  
Starting MMM Agent daemon... Ok

root@slave2:/etc/mysql-mmm# etc/init.d/mysql-mmm-agent status  
Daemon bin: '/usr/sbin/mmm_agentd'  
Daemon pid: '/var/run/mmm_agentd.pid'  
Checking MMM Agent process: running.  
root@slave2:/etc/mysql-mmm#

「下面在监控节点上执行如下命令启动并查看MMM的监控服务」

  • monitor节点上,启动和查看MMM的监控端服务如下:
root@monitor:/etc/mysql-mmm# etc/init.d/mysql-mmm-monitor start  
Daemon bin: '/usr/sbin/mmm_mond'  
Daemon pid: '/var/run/mmm_mond.pid'  
Starting MMM Monitor daemon: Ok

root@monitor:/etc/mysql-mmm# etc/init.d/mysql-mmm-monitor status  
Daemon bin: '/usr/sbin/mmm_mond'  
Daemon pid: '/var/run/mmm_mond.pid'  
Checking MMM Monitor process: running.  
root@monitor:/etc/mysql-mmm#
  • 在monitor节点,查看监控的状态:
root@monitor:/etc/mysql-mmm# mmm_control show  
master1(172.20.0.11) master/AWAITING_RECOVERY. Roles:  
master2(172.20.0.21) master/AWAITING_RECOVERY. Roles:  
slave1(172.20.0.12) slave/AWAITING_RECOVERY. Roles:  
slave2(172.20.0.22) slave/AWAITING_RECOVERY. Roles:

root@monitor:/etc/mysql-mmm# mmm\_control set\_online master1;  
OK: State of 'master1' changed to ONLINE. Now you can wait some time and check its new roles!  
root@monitor:/etc/mysql-mmm# mmm\_control set\_online master2  
OK: State of 'master2' changed to ONLINE. Now you can wait some time and check its new roles!  
root@monitor:/etc/mysql-mmm# mmm\_control set\_online slave1  
OK: State of 'slave1' changed to ONLINE. Now you can wait some time and check its new roles!  
root@monitor:/etc/mysql-mmm# mmm\_control set\_online slave2  
OK: State of 'slave2' changed to ONLINE. Now you can wait some time and check its new roles!  
root@monitor:/etc/mysql-mmm# mmm_control show  
master1(172.20.0.11) master/ONLINE. Roles: reader(172.20.0.111), writer(172.20.0.100)  
master2(172.20.0.21) master/ONLINE. Roles: reader(172.20.0.211)  
slave1(172.20.0.12) slave/ONLINE. Roles: reader(172.20.0.122)  
slave2(172.20.0.22) slave/ONLINE. Roles: reader(172.20.0.222)

root@monitor:/etc/mysql-mmm#

「问题排查1:monitor服务不能正常启动?」

当在monitor节点启动监控服务后,监控服务一会就异常退出了。原因是在使用docker启动集群节点的时候没有使用--cap-add NET_ADMIN
参数,没有这个参数就没有办法在容器只用使用虚拟VIP的功能。在删除容器后,增加参数重新运行后,才运行起来。

后来,又发现monitor节点启监控服务器仍然失败,查看日志/var/log/mysql-mmm/mmm_mond.log
,如下所示:

root@monitor:/etc/mysql-mmm# tail -f var/log/mysql-mmm/mmm_mond.log  
2021/02/22 23:26:27 INFO Waiting for network connection...  
2021/02/22 23:26:27 INFO Spawning checker 'ping_ip'...  
2021/02/22 23:26:27 INFO Shutting down checker 'ping_ip'...  
2021/02/22 23:26:27 INFO Network connection is available.  
2021/02/22 23:26:27 FATAL Child exited with exitcode 255, restarting after 10 second sleep

修改/etc/mysql-mmm/mmm_mon.conf
配置文件中的debug
的值为1
,表示以debug
的模式运行monitor服务,此时我们再重新启动monitor服务,查看输出的详细错误日志如下:

root@monitor:/etc/mysql-mmm# etc/init.d/mysql-mmm-monitor start  
Daemon bin: '/usr/sbin/mmm_mond'  
Daemon pid: '/var/run/mmm_mond.pid'  
Starting MMM Monitor daemon: 2021/02/22 23:30:17 INFO STARTING...  
2021/02/22 23:30:17 DEBUG Created pid file '/var/run/mmm_mond.pid' with pid 5330  
2021/02/22 23:30:17 INFO Waiting for network connection...  
2021/02/22 23:30:17 INFO Spawning checker 'ping_ip'...  
2021/02/22 23:30:17 DEBUG IP '172.20.0.1' is reachable: OK  
2021/02/22 23:30:17 INFO Shutting down checker 'ping_ip'...  
2021/02/22 23:30:17 INFO Network connection is available.  
Use of uninitialized value $old_state in string ne at usr/share/perl5/MMM/Monitor/Agent.pm line 42.  
2021/02/22 23:30:17 FATAL Child exited with exitcode 255, restarting after 10 second sleep

于是去修改了/usr/share/perl5/MMM/Monitor/Agent.pm
文件,在第41行增加如下内容,保存退出,重新启动monitor服务。

if (! defined($old\_state)) { $old\_state = 'certinally not new_state'; }

然后再次重启monitor服务,启动成功。然后把/etc/mysql-mmm/mmm_mon.conf
配置文件中的debug
的值再次修改为0
,关闭debug
模式再次重启monitor服务。此时查看monitor服务的日志内容如下:

root@monitor:/# tail -f var/log/mysql-mmm/mmm_mond.log  
2021/02/22 23:42:43 INFO Check 'rep_backlog' on 'slave1' is ok!  
2021/02/22 23:42:43 INFO Check 'rep_backlog' on 'master2' is ok!  
2021/02/22 23:42:43 INFO Check 'rep_threads' on 'master1' is ok!  
2021/02/22 23:42:43 INFO Check 'rep_threads' on 'slave2' is ok!  
2021/02/22 23:42:43 INFO Check 'rep_threads' on 'slave1' is ok!  
2021/02/22 23:42:43 INFO Check 'rep_threads' on 'master2' is ok!  
2021/02/22 23:42:43 INFO Check 'ping' on 'master1' is ok!  
2021/02/22 23:42:43 INFO Check 'ping' on 'slave2' is ok!  
2021/02/22 23:42:43 INFO Check 'ping' on 'slave1' is ok!  
2021/02/22 23:42:43 INFO Check 'ping' on 'master2' is ok!

「问题排查2:虚拟IP不能再各个节点生成?」

启动MMM后,发现不能通过VIP访问MySQL数据库,去各个节点使用ifconfig -a
或者ip addr
命令查看发现没有对应的VIP生成。查看了各个节点MMM agent服务的日志文件/var/log/mysql-mmm/mmm_agent.log
,发现如下错误信息:

root@master1:/# tail -f var/log/mysql-mmm/mmm_agentd.log  
2021/02/23 17:16:19 FATAL Couldn't configure IP '172.20.0.111' on interface 'eth0': undef  
2021/02/23 17:16:19 FATAL Couldn't allow writes: undef  
2021/02/23 17:16:22 FATAL Couldn't configure IP '172.20.0.111' on interface 'eth0': undef  
2021/02/23 17:16:22 FATAL Couldn't allow writes: undef

经过排查发现是在设置VIP的时候失败,设置客户端VIP的脚本如下:

/usr/lib/mysql-mmm/agent/configure_ip

执行上面的脚本发现如下错误:

alt

提示我们,需要在perl中安装arp.pm包。安装的时候,为了提高速度,我们修改一下perl安装模块的时候使用的镜像源。

修改perl安装包的时候使用的镜像源,参考如下方式修改:

root@master1:/# perl -MCPAN -e shell  
cpan\[5\]> o conf urllist  
urllist  
0 \[http://www.cpan.org/\] 
Type 'o conf' to view all configuration items

cpan\[6\]> o conf urllist push http://mirrors.aliyun.com/CPAN/  
Please use 'o conf commit' to make the config permanent!

cpan\[7\]> o conf commit  
commit: wrote '/root/.cpan/CPAN/MyConfig.pm'

cpan\[8\]> o conf urllist  
urllist  
0 \[http://www.cpan.org/\] 
1 \[http://mirrors.aliyun.com/CPAN/\] 
Type 'o conf' to view all configuration items

cpan\[9\]> install Net::ARP

cpan\[10\]>

其中各个命令的含义如下:

  • o conf urllist
    :查看的当前的镜像源

  • o conf urllist push http://mirrors.aliyun.com/CPAN/
    :添加阿里的perl镜像源

  • o conf commit
    :提交对镜像源的修改

  • install Net::ARP
    :安装arp.pm包。

经过上面的安装方式,发现安装失败。于是下载源码自己编译安装这个包。参考如下命令顺序来编译安装。

# 下载源码文件  
wget https://cpan.metacpan.org/authors/id/C/CR/CRAZYDJ/Net-ARP-1.0.11.tgz

#
 解压下载后的文件  
tar -zxvf Net-ARP-1.0.11.tgz

#
 进入下载目录  
cd Net-ARP-1.0.11

#
 执行编译  
perl Makefile.PL

#
 执行安装  
make install

上面安装Net-ARP包的操作,需要在除了monitor节点的四个节点上都执行安装一下。

最后所有节点的IP地址和VIP地址如下所示:

alt

验证VIP访问数据库

当我们的MMM客户段服务在四个MySQL数据库实例中启动,并且MMM监控服务在monitor节点启动之后。我们在monitor节点上面尝试使用各个VIP看能否正常连接到MySQL数据库。验证的结果如下:

root@monitor:/etc/mysql-mmm#  
root@monitor:/etc/mysql-mmm# mmm_control show  
master1(172.20.0.11) master/ONLINE. Roles: reader(172.20.0.111), writer(172.20.0.100)  
master2(172.20.0.21) master/ONLINE. Roles: reader(172.20.0.122)  
slave1(172.20.0.12) slave/ONLINE. Roles: reader(172.20.0.211)  
slave2(172.20.0.22) slave/ONLINE. Roles: reader(172.20.0.222)

root@monitor:/etc/mysql-mmm# mysql -uroot -proot -h172.20.0.100 -e 'select @@hostname'  
mysql: \[Warning\] Using a password on the command line interface can be insecure.  
+---------------+  
| @@hostname |  
+---------------+  
| master1.mysql |  
+---------------+  
root@monitor:/etc/mysql-mmm# mysql -uroot -proot -h172.20.0.111 -e 'select @@hostname'  
mysql: \[Warning\] Using a password on the command line interface can be insecure.  
+---------------+  
| @@hostname |  
+---------------+  
| master1.mysql |  
+---------------+  
root@monitor:/etc/mysql-mmm# mysql -uroot -proot -h172.20.0.122 -e 'select @@hostname'  
mysql: \[Warning\] Using a password on the command line interface can be insecure.  
+---------------+  
| @@hostname |  
+---------------+  
| master2.mysql |  
+---------------+  
root@monitor:/etc/mysql-mmm# mysql -uroot -proot -h172.20.0.211 -e 'select @@hostname'  
mysql: \[Warning\] Using a password on the command line interface can be insecure.  
+--------------+  
| @@hostname |  
+--------------+  
| slave1.mysql |  
+--------------+  
root@monitor:/etc/mysql-mmm# mysql -uroot -proot -h172.20.0.222 -e 'select @@hostname'  
mysql: \[Warning\] Using a password on the command line interface can be insecure.  
+--------------+  
| @@hostname |  
+--------------+  
| slave2.mysql |  
+--------------+  
root@monitor:/etc/mysql-mmm#

验证MMM的高可用

我们把master1节点上面的MySQL服务停止掉,来验证一下是否会把主从同步的源头从master1切换为master2上面,并且我们在monitor节点上,仍然可以通过writer vip 去连接到MySQL上。

停止master1节点上面的MySQL服务,在master1节点上,执行如下命令:

root@master1:~/Net-ARP-1.0.11# etc/init.d/mysql stop  
............  
\[info\] MySQL Community Server 5.7.31 is stopped.  
root@master1:~/Net-ARP-1.0.11# %   
➜  ~

接着,我们在monitor节点上,查看MMM监控各个节点服务的状态,发现master1节点以及下线了,并且我们的writer ip,已经从原先的master1节点迁移到master2节点上了。如下所示:

root@monitor:/etc/mysql-mmm# mmm_control show  
# Warning: agent on host master1 is not reachable  
master1(172.20.0.11) master/HARD_OFFLINE. Roles:  
master2(172.20.0.21) master/ONLINE. Roles: reader(172.20.0.122), writer(172.20.0.100)  
slave1(172.20.0.12) slave/ONLINE. Roles: reader(172.20.0.111), reader(172.20.0.211)  
slave2(172.20.0.22) slave/ONLINE. Roles: reader(172.20.0.222)

root@monitor:/etc/mysql-mmm# mmm_control checks all  
slave2 ping \[last change: 2021/02/23 16:19:44\] OK  
slave2 mysql \[last change: 2021/02/23 16:19:44\] OK  
slave2 rep_threads \[last change: 2021/02/23 16:19:44\] OK  
slave2 rep_backlog \[last change: 2021/02/23 16:19:44\] OK: Backlog is null  
master1 ping \[last change: 2021/02/23 18:44:57\] ERROR: Could not ping 172.20.0.11  
master1 mysql \[last change: 2021/02/23 18:44:40\] ERROR: Connect error (host = 172.20.0.11:3306, user = mmm_monitor)!
Can't connect to MySQL server on '172.20.0.11' (115)  
master1 rep_threads \[last change: 2021/02/23 16:19:44\] OK  
master1 rep_backlog \[last change: 2021/02/23 16:19:44\] OK: Backlog is null  
slave1 ping \[last change: 2021/02/23 16:19:44\] OK  
slave1 mysql \[last change: 2021/02/23 16:19:44\] OK  
slave1 rep_threads \[last change: 2021/02/23 16:19:44\] OK  
slave1 rep_backlog \[last change: 2021/02/23 16:19:44\] OK: Backlog is null  
master2 ping \[last change: 2021/02/23 16:19:44\] OK  
master2 mysql \[last change: 2021/02/23 16:19:44\] OK  
master2 rep_threads \[last change: 2021/02/23 16:19:44\] OK  
master2 rep_backlog \[last change: 2021/02/23 16:19:44\] OK: Backlog is null

root@monitor:/etc/mysql-mmm#

此时我们看到master2上面的IP地址信息如下,writer vip 172.20.0.100
已经迁移到了master2主机上了。

root@master2:~/Net-ARP-1.0.11# ip addr  
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000  
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00  
inet 127.0.0.1/8 scope host lo  
valid\_lft forever preferred\_lft forever  
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000  
link/ipip 0.0.0.0 brd 0.0.0.0  
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000  
link/tunnel6 :: brd ::  
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default  
link/ether 02:42:ac:14:00:15 brd ff:ff:ff:ff:ff:ff link-netnsid 0  
inet 172.20.0.21/24 brd 172.20.0.255 scope global eth0  
valid\_lft forever preferred\_lft forever  
inet 172.20.0.122/32 scope global eth0  
valid\_lft forever preferred\_lft forever  
inet 172.20.0.100/32 scope global eth0  
valid\_lft forever preferred\_lft forever  
root@master2:~/Net-ARP-1.0.11#

在monitor节点上,查看MMM的监控服务器的日志信息如下:

root@monitor:/etc/mysql-mmm# tail -20 /var/log/mysql-mmm/mmm_mond.log  
2021/02/23 16:19:49 INFO Check 'mysql' on 'slave2' is ok!  
2021/02/23 16:19:49 INFO Check 'mysql' on 'master1' is ok!  
2021/02/23 16:19:49 INFO Check 'mysql' on 'slave1' is ok!  
2021/02/23 16:19:49 INFO Check 'mysql' on 'master2' is ok!  
2021/02/23 18:44:30 WARN Check 'rep_threads' on 'master1' is in unknown state! Message: UNKNOWN: Connect error (host =
172.20.0.11:3306, user = mmm_monitor)! Can't connect to MySQL server on '172.20.0.11' (115)  
2021/02/23 18:44:30 WARN Check 'rep_backlog' on 'master1' is in unknown state! Message: UNKNOWN: Connect error (host =
172.20.0.11:3306, user = mmm_monitor)! Can't connect to MySQL server on '172.20.0.11' (115)  
2021/02/23 18:44:40 ERROR Check 'mysql' on 'master1' has failed for 10 seconds! Message: ERROR: Connect error (host =
172.20.0.11:3306, user = mmm_monitor)! Can't connect to MySQL server on '172.20.0.11' (115)  
2021/02/23 18:44:41 FATAL State of host 'master1' changed from ONLINE to HARD_OFFLINE (ping: OK, mysql: not OK)  
2021/02/23 18:44:41 INFO Removing all roles from host 'master1':  
2021/02/23 18:44:41 INFO Removed role 'reader(172.20.0.111)' from host 'master1'  
2021/02/23 18:44:41 INFO Removed role 'writer(172.20.0.100)' from host 'master1'  
2021/02/23 18:44:41 FATAL Can't reach agent on host 'master1'  
2021/02/23 18:44:41 ERROR Can't send offline status notification to 'master1' \- killing it!  
2021/02/23 18:44:41 FATAL Could not kill host 'master1' \- there may be some duplicate ips now! (There's no binary
configured for killing hosts.)  
2021/02/23 18:44:41 INFO Orphaned role 'writer(172.20.0.100)' has been assigned to 'master2'  
2021/02/23 18:44:41 INFO Orphaned role 'reader(172.20.0.111)' has been assigned to 'slave1'  
2021/02/23 18:44:57 ERROR Check 'ping' on 'master1' has failed for 11 seconds! Message: ERROR: Could not ping
172.20.0.11  
root@monitor:/etc/mysql-mmm#

我们在monitor节点上,再次尝试连接到writer vip 172.20.0.100
上面,发现已经连接到master2上面了,如下所示:

root@monitor:/etc/mysql-mmm# mysql -uroot -proot -h172.20.0.100 -e 'select @@hostname'  
mysql: \[Warning\] Using a password on the command line interface can be insecure.  
+---------------+  
| @@hostname |  
+---------------+  
| master2.mysql |  
+---------------+  
root@monitor:/etc/mysql-mmm#

下面我们看一下slave1和slave2节点主从同步的配置是否,自动切换到master2节点上。分别登录到slave1和slave2节点上执行如下SQL命令:

select * from mysql.slave\_master\_info\\G

查看结果如下:

alt

通过下面的截图,可以看出在新的主节点上面执行的插入数据,是可以正常的同步到两个slave从节点上。

alt

下面我们把master1节点重新启动,让MySQL数据库服务恢复。

# 启动master1容器  
docker start mysql-ha-mmm-master1

#
 进入master1容器  
docker exec -it mysql-ha-mmm-master1 /bin/bash

#
 启动master1上面的MMM的agent服务  
/etc/init.d/mysql-mmm-agent start

进入monitor节点上,查看各个节点的状态:

# 在master1启动后,在monitor节点查看各个节点状态的时候,发现已经不再有"Warning: agent on host master1 is not reachable"
的警告了。  
root@monitor:/etc/mysql-mmm# mmm_control show  
master1(172.20.0.11) master/AWAITING_RECOVERY. Roles:  
master2(172.20.0.21) master/ONLINE. Roles: reader(172.20.0.122), writer(172.20.0.100)  
slave1(172.20.0.12) slave/ONLINE. Roles: reader(172.20.0.111), reader(172.20.0.211)  
slave2(172.20.0.22) slave/ONLINE. Roles: reader(172.20.0.222)

#
 设置master1节点上线  
root@monitor:/etc/mysql-mmm# mmm\_control set\_online master1  
OK: State of 'master1' changed to ONLINE. Now you can wait some time and check its new roles!

#
 再次查看各个节点的状态,发现master1已经上线了。但是它此时成立备用的主节点了,并且给他分配了一个reader VIP地址。  
root@monitor:/etc/mysql-mmm# mmm_control show  
master1(172.20.0.11) master/ONLINE. Roles: reader(172.20.0.211)  
master2(172.20.0.21) master/ONLINE. Roles: reader(172.20.0.122), writer(172.20.0.100)  
slave1(172.20.0.12) slave/ONLINE. Roles: reader(172.20.0.111)  
slave2(172.20.0.22) slave/ONLINE. Roles: reader(172.20.0.222)

root@monitor:/etc/mysql-mmm#

「MMM高可用验证结果小结:」

  • master1节点宕机之后,master2节点会接管master1的所有任务。

  • writer VIP会自动从master1上面转移到master2上面。

  • 两个从节点slave1和slave2会自动的把主从同步的链路从master1切换到master2上面。

  • 如果在master1上除了提供写的服务,还提供可读的服务,也就是为其分配了reader VIP,那么当master1宕机后,这个reader VIP不会丢失,会被迁移到其他任意一个节点上。

  • 在master1重启后,在monitor节点通过命令mmm_control set_online master1
    设置master1节点上线后,master1节点不会接管现有master2的角色,而是作为一个备用主节点集群中提供服务。此时,只有master2节点宕机后,master1节点才会重新成为主节点的角色。

  • 随着master1和master2节点的宕机和恢复,提供写的VIP会在两个节点上来回切换。

对于这个5个服务器组成的高可用集群,如果我们担心MMM的monitor节点是单节点,不是高可用的monitor服务,我们可以在选择一台服务器,在上面部署另外一个monitor服务,使用keepalive组件,保证两个monitor服务至少有一个可用。这样就更加完美了。

总结

上面就是关于MySQL高可用架构-MMM架构的搭建过程。期间涉及到了MySQL主从同步集群的搭建,我们搭建了一个双主双从的集群,然后基于这个集群,又在每一个节点上面编译安装了MMM插件,在每一个节点上启动了MMM的agent服务。还选择了一台服务器,安装MMM监控服务。

希望对你有所帮助,后续会分享其他高可用架构搭建的方式。

如果您喜欢我的内容,就点击关注吧

扫码长按关注交流群获取最新消息,免费的面试题手册即将在交流群内推出

alt

公众号

alt

个人微信

alt

本文由 mdnice 多平台发布

Guess you like

Origin blog.csdn.net/njpkhuan/article/details/132798680