MMM(Master-Master replication manager for MySQL,MySQL 主主复制管理器)是一套支持双主故障切换和双主日常管理的脚本程序。MMM 使用 Perl 语言开发,主要从来监控和管理 MySQL Master-Master(双主)复制,虽然叫做双主复制,但是业务上同一时刻只允许一个主进行写入,另一台备选主上提供部分读服务,以加速在主主切换时备选主的预热,可以说 MMM 这套脚本程序一方面实现了故障切换的功能,另一方面其内部附加的工具也可以实现多个 Slave 的 read 负载均衡。
MMM 提供了自动和手动两种方式移除一组服务器中复制延迟较高的服务器的虚拟 ip,同时它还可以备份数据,实现两节点之间的数据同步等。由于 MMM 无法完全保证数据的一致性,所以 MMM 适用于对数据的一致性要求不是很高的,但是又想最大程度地保证业务可用性的场景。对于那些对数据的一致性要求很高的业务,非常不建议采用 MMM 这种高可用架构。
在整个监管过程中,需要在 MySQL 中添加相关授权 yoghurt,以便让 MySQL 可以支持监理机的维护。授权的用户包括一个 mmm_monitor 用户和一个 mmm_agent 用户,如果想使用 MMM 的备份工具则还需要添加一个 mmm_tools 用户。
服务器 | 主机名 | 操作系统 | IP地址 | 主要软件 |
---|---|---|---|---|
Master1服务器 | master1 | CentOS 7.6 | 192.168.10.20 | MySQL 5.7、MySQL-MMM |
Master2服务器 | master2 | CentOS 7.6 | 192.168.10.30 | MySQL 5.7、MySQL-MMM |
Slave1服务器 | slave1 | CentOS 7.6 | 192.168.10.40 | MySQL 5.7、MySQL-MMM |
Slave2服务器 | slave2 | CentOS 7.6 | 192.168.10.50 | MySQL 5.7、MySQL-MMM |
Monitor服务器 | monitor | CentOS 7.6 | 192.168.10.90 | MySQL-MMM |
systemctl stop firewalld && systemctl disable firewalld
setenforce 0
Master1 服务器
hostnamectl set-hostname master1
su
Master2 服务器
hostnamectl set-hostname master2
su
Slave1 服务器
hostnamectl set-hostname slave1
su
Slave2 服务器
hostnamectl set-hostname slave2
su
Monitor 服务器
hostnamectl set-hostname monitor
su
#!/bin/bash
#一键安装 mysql-5.7.17
#联网下载两个源码包,包在我的云主机上
#安装包下载在 /data 目录
#编译安装需较长时间,请耐心等待
mkdir /data
wget http://101.34.22.188/mysql-5.7.17/boost_1_59_0.tar.gz -P /data
wget http://101.34.22.188/mysql-5.7.17/mysql-5.7.17.tar.gz -P /data
systemctl stop firewalld && systemctl disable firewalld
setenforce 0
ntpdate ntp1.aliyun.com
tar zxvf /data/mysql-5.7.17.tar.gz -C /opt
tar zxvf /data/boost_1_59_0.tar.gz -C /usr/local
mv /usr/local/boost_1_59_0 /usr/local/boost
yum -y install gcc gcc-c++ ncurses ncurses-devel bison cmake make git perl expat-devel pcre-devel pcre
useradd -s /sbin/nologin mysql
cd /opt/mysql-5.7.17/
cmake \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock \
-DSYSCONFDIR=/etc \
-DSYSTEMD_PID_DIR=/usr/local/mysql \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_EXTRA_CHARSETS=all \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_ARCHIVE_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_PERFSCHEMA_STORAGE_ENGINE=1 \
-DMYSQL_DATADIR=/usr/local/mysql/data \
-DWITH_BOOST=/usr/local/boost \
-DWITH_SYSTEMD=1
cd /opt/mysql-5.7.17/
make -j 4 && make install
echo > /etc/my.cnf
cat > /etc/my.cnf<<EOF
[client]
port = 3306
default-character-set=utf8
socket=/usr/local/mysql/mysql.sock
[mysql]
port = 3306
default-character-set=utf8
socket=/usr/local/mysql/mysql.sock
auto-rehash
[mysqld]
user = mysql
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port = 3306
character-set-server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket=/usr/local/mysql/mysql.sock
bind-address = 0.0.0.0
skip-name-resolve
max_connections=2048
default-storage-engine=INNODB
max_allowed_packet=16M
server-id = 1
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
EOF
chown -R mysql.mysql /usr/local/mysql/
chown mysql.mysql /etc/my.cnf
echo "PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile
source /etc/profile
cd /usr/local/mysql/bin/
./mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
cp /usr/local/mysql/usr/lib/systemd/system/mysqld.service /usr/lib/systemd/system/
systemctl daemon-reload && systemctl start mysqld && systemctl enable mysqld
ln -s /usr/local/mysql/bin/mysql /usr/local/sbin/
pgrep "mysqld" &> /dev/null
if [ $? -eq 0 ];then
echo -e "\033[32mmysqld服务运行正常\033[0m"
else
echo -e "\033[31mmysqld服务运行异常,请检查\033[0m"
fi
sleep 2
echo ' '
echo -e "\033[32mMySQL 没有设置密码,执行 mysql 命令登录\033[0m"
cat /etc/my.cnf
[client]
port = 3306
default-character-set=utf8
socket=/usr/local/mysql/mysql.sock
[mysql]
port = 3306
default-character-set=utf8
socket=/usr/local/mysql/mysql.sock
auto-rehash
[mysqld]
user = mysql
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port = 3306
character-set-server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket=/usr/local/mysql/mysql.sock
server-id = 1
log-error=/usr/local/mysql/data/mysql_error.log
general_log=ON
general_log_file=/usr/local/mysql/data/mysql_general.log
slow_query_log=ON
slow_query_log_file=mysql_slow_query.log
long_query_time=5
binlog-ignore-db=mysql,information_schema
log_bin=mysql_bin
log_slave_updates=true
sync_binlog=1
innodb_flush_log_at_trx_commit=1
auto_increment_increment=2
auto_increment_offset=1
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
重启 mysqld
systemctl restart mysqld
参数解释
......
server-id = 1
#每台 Mysql 主机的 server-id 不能相同
log-error=/usr/local/mysql/data/mysql_error.log
#错误日志
general_log=ON
#通用查询日志
general_log_file=/usr/local/mysql/data/mysql_general.log
slow_query_log=ON
#慢查询日志
slow_query_log_file=mysql_slow_query.log
long_query_time=5
binlog-ignore-db=mysql,information_schema
#不需要同步的库名
log_bin=mysql_bin
#开启二进制日志用于主从数据复制
log_slave_updates=true
#允许slave从master复制数据时可以写入到自己的二进制日志
sync_binlog=1
#"双1设置",MySQL 在每写一次二进制日志时都会同步到磁盘中去
innodb_flush_log_at_trx_commit=1
#"双1设置",每次事务提交时MySQL都会把缓存的数据写入日志文件,并且刷到磁盘中去
auto_increment_increment=2
#自增字段一次递增多少
auto_increment_offset=1
#自增字段的起始值
把配置文件复制到其他 3 台数据库服务器并重启 mysql 服务器
注意:配置文件中的 server-id 不可相同,需要修改。
server-id = 1
server-id = 2
server-id = 3
server-id = 4
master1 服务器(192.168.10.20)
mysql> grant replication slave on *.* to 'replication'@'192.168.10.%' identified by '123456';
mysql> flush privileges;
mysql> show master status;
+------------------+----------+--------------+--------------------------+-----------------
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Se
+------------------+----------+--------------+--------------------------+-----------------
| mysql_bin.000001 | 1023 | | mysql,information_schema |
+------------------+----------+--------------+--------------------------+-----------------
1 row in set (0.00 sec)
master2 服务器(192.168.10.30)
mysql> grant replication slave on *.* to 'replication'@'192.168.10.%' identified by '123456';
mysql> flush privileges;
mysql> show master status;
+------------------+----------+--------------+--------------------------+-----------------
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Se
+------------------+----------+--------------+--------------------------+-----------------
| mysql_bin.000001 | 1023 | | mysql,information_schema |
+------------------+----------+--------------+--------------------------+-----------------
1 row in set (0.00 sec)
192.168.10.20
change master to master_host='192.168.10.30',master_user='replication',master_password='123456',master_log_file='mysql_bin.000001',master_log_pos=1023;
start slave;
show slave status\G;
#查看 IO 和 SQL 线程是不是 YES,位置偏移量对不对
192.168.10.30
change master to master_host='192.168.10.20',master_user='replication',master_password='123456',master_log_file='mysql_bin.000001',master_log_pos=1023;
start slave;
show slave status\G;
#查看 IO 和 SQL 线程是不是 YES,位置偏移量对不对
192.168.10.40
change master to master_host='192.168.10.20',master_user='replication',master_password='123456',master_log_file='mysql_bin.000001',master_log_pos=1023;
start slave;
show slave status\G;
192.168.10.50
change master to master_host='192.168.10.20',master_user='replication',master_password='123456',master_log_file='mysql_bin.000001',master_log_pos=1023;
start slave;
show slave status\G;
master1 服务器
create database test;
show databases;
master2 服务器
show databases;
slave1 服务器
show databases;
slave2 服务器
show databases;
yum -y install epel-release && yum -y install mysql-mmm*
注:若本地仓库中无以上软件,需先为各服务器配置在线源仓库。
阿里云源仓库配置方法
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
yum clean all && yum makecache
192.168.10.20
[root@master1 ~]# cd /etc/mysql-mmm/
[root@master1 mysql-mmm]# cp mmm_common.conf mmm_common.conf.bak
#修改配置文件前,先备份
[root@master1 mysql-mmm]# vim mmm_common.conf
active_master_role writer
<host default>
cluster_interface ens33
pid_path /run/mysql-mmm-agent.pid
bin_path /usr/libexec/mysql-mmm/
replication_user replication
##指定主主、主从复制用户,要与前面一致
replication_password 123456
agent_user mmm_agent
##指定monitor代理进程的用户名
agent_password 123456
</host>
<host db1>
ip 192.168.10.20
mode master
peer db2
##peer设置同级数据库
</host>
<host db2>
ip 192.168.10.30
mode master
peer db1
</host>
<host db3>
ip 192.168.10.40
mode slave
</host>
<host db4>
ip 192.168.10.50
mode slave
</host>
<role writer>
hosts db1, db2
ips 192.168.10.200
##设定写VIP
mode exclusive
#只有一个 host 可以进行写操作模式
</role>
<role reader>
hosts db3, db4
ips 192.168.10.201, 192.168.10.202
##设定读VIP
mode balanced
##多个 slave 主机可以进行读操作模式
</role>
无文字版
active_master_role writer
<host default>
cluster_interface ens33
pid_path /run/mysql-mmm-agent.pid
bin_path /usr/libexec/mysql-mmm/
replication_user replication
replication_password 123456
agent_user mmm_agent
agent_password 123456
</host>
<host db1>
ip 192.168.10.20
mode master
peer db2
</host>
<host db2>
ip 192.168.10.30
mode master
peer db1
</host>
<host db3>
ip 192.168.10.40
mode slave
</host>
<host db4>
ip 192.168.10.50
mode slave
</host>
<role writer>
hosts db1, db2
ips 192.168.10.200
mode exclusive
</role>
<role reader>
hosts db3, db4
ips 192.168.10.201, 192.168.10.202
mode balanced
</role>
所有主机该配置文件内容都是相同的
scp mmm_common.conf [email protected]:/etc/mysql-mmm/
scp mmm_common.conf [email protected]:/etc/mysql-mmm/
scp mmm_common.conf [email protected]:/etc/mysql-mmm/
scp mmm_common.conf [email protected]:/etc/mysql-mmm/
master1
[root@master1 ~]# vim /etc/mysql-mmm/mmm_agent.conf
include mmm_common.conf
this db1
##根据不同的主机分别修改为db1/db2/db3/db4,默认配置为db1,因此master1无需修改
master2
[root@master2 ~]# vim /etc/mysql-mmm/mmm_agent.conf
include mmm_common.conf
this db2
slave1
[root@slave ~]# vim /etc/mysql-mmm/mmm_agent.conf
include mmm_common.conf
this db3
slave2
[root@slave2 ~]# vim /etc/mysql-mmm/mmm_agent.conf
include mmm_common.conf
this db4
monitor 服务器(192.168.10.90)
[root@monitor ~]# vim /etc/mysql-mmm/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.20,192.168.10.30,192.168.10.40,192.168.10.50
##指定所有数据库服务器的IP
auto_set_online 10
##指定自动上线时间
# 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
##指定mmm_monitor的用户名
monitor_password 123456
##指定mmm_monitor的密码
</host>
debug 0
所有数据库执行下列语句
grant super,replication client,process on *.* to 'mmm_agent'@'192.168.10.%' identified by '123456';
flush privileges;
PS
权限 | 功能 |
---|---|
process | 显示或杀死属于其他用户的服务线程 |
super | 允许用户终止任何查询;修改全局变量的SET语句;使用 CHANGE MASTER,PURGE MASTER LOGS |
replication client | 查询主服务器、从服务器状态 |
grant replication client on *.* to 'mmm_monitor'@'192.168.10.%' identified by '123456';
flush privileges;
systemctl start mysql-mmm-agent.service && systemctl enable mysql-mmm-agent.service
systemctl start mysql-mmm-monitor.service && systemctl enable mysql-mmm-monitor.service
[root@monitor ~]#mmm_control show
db1(192.168.10.20) master/ONLINE. Roles: writer(192.168.10.200)
db2(192.168.10.30) master/ONLINE. Roles:
db3(192.168.10.40) slave/ONLINE. Roles: reader(192.168.10.202)
db4(192.168.10.50) slave/ONLINE. Roles: reader(192.168.10.201)
[root@monitor ~]#mmm_control checks all
db4 ping [last change: 2021/11/04 16:13:20] OK
db4 mysql [last change: 2021/11/04 16:13:20] OK
db4 rep_threads [last change: 2021/11/04 16:13:20] OK
db4 rep_backlog [last change: 2021/11/04 16:13:20] OK: Backlog is null
db2 ping [last change: 2021/11/04 16:13:20] OK
db2 mysql [last change: 2021/11/04 16:13:20] OK
db2 rep_threads [last change: 2021/11/04 16:13:20] OK
db2 rep_backlog [last change: 2021/11/04 16:13:20] OK: Backlog is null
db3 ping [last change: 2021/11/04 16:13:20] OK
db3 mysql [last change: 2021/11/04 16:13:20] OK
db3 rep_threads [last change: 2021/11/04 16:13:20] OK
db3 rep_backlog [last change: 2021/11/04 16:13:20] OK: Backlog is null
db1 ping [last change: 2021/11/04 16:13:20] OK
db1 mysql [last change: 2021/11/04 16:13:20] OK
db1 rep_threads [last change: 2021/11/04 16:13:20] OK
db1 rep_backlog [last change: 2021/11/04 16:13:20] OK: Backlog is null
[root@monitor ~]#mmm_control move_role writer db2
OK: Role 'writer' has been moved from 'db1' to 'db2'. Now you can wait some time and check new roles info!
[root@monitor ~]#mmm_control show
db1(192.168.10.20) master/ONLINE. Roles:
db2(192.168.10.30) master/ONLINE. Roles: writer(192.168.10.200)
db3(192.168.10.40) slave/ONLINE. Roles: reader(192.168.10.202)
db4(192.168.10.50) slave/ONLINE. Roles: reader(192.168.10.201)
[root@monitor ~]#mmm_control move_role writer db1
OK: Role 'writer' has been moved from 'db2' to 'db1'. Now you can wait some time and check new roles info!
[root@monitor ~]#mmm_control show
db1(192.168.10.20) master/ONLINE. Roles: writer(192.168.10.200)
db2(192.168.10.30) master/ONLINE. Roles:
db3(192.168.10.40) slave/ONLINE. Roles: reader(192.168.10.202)
db4(192.168.10.50) slave/ONLINE. Roles: reader(192.168.10.201)
master1
systemctl stop mysqld
monitor
[root@monitor ~]#mmm_control show
db1(192.168.10.20) master/HARD_OFFLINE. Roles:
db2(192.168.10.30) master/ONLINE. Roles: writer(192.168.10.200)
db3(192.168.10.40) slave/ONLINE. Roles: reader(192.168.10.202)
db4(192.168.10.50) slave/ONLINE. Roles: reader(192.168.10.201)
VIP 成功漂移至 master2,且 master1 显示 HARD_OFFLINE
master1
systemctl start mysqld
master1 恢复后 VIP 仍在 master2 上,并未转移到 master1
slave1
systemctl stop mysqld
monitor
[root@monitor ~]#mmm_control show
db1(192.168.10.20) master/ONLINE. Roles:
db2(192.168.10.30) master/ONLINE. Roles: writer(192.168.10.200)
db3(192.168.10.40) slave/HARD_OFFLINE. Roles:
db4(192.168.10.50) slave/ONLINE. Roles: reader(192.168.10.201), reader(192.168.10.202)
slave1 所对应的的 VIP 被 slave2 接管
slave1
systemctl start mysqld
monitor
[root@monitor ~]#mmm_control show
db1(192.168.10.20) master/ONLINE. Roles:
db2(192.168.10.30) master/ONLINE. Roles: writer(192.168.10.200)
db3(192.168.10.40) slave/AWAITING_RECOVERY. Roles:
db4(192.168.10.50) slave/ONLINE. Roles: reader(192.168.10.201), reader(192.168.10.202)
[root@monitor ~]#mmm_control show
db1(192.168.10.20) master/ONLINE. Roles:
db2(192.168.10.30) master/ONLINE. Roles: writer(192.168.10.200)
db3(192.168.10.40) slave/ONLINE. Roles:
db4(192.168.10.50) slave/ONLINE. Roles: reader(192.168.10.201), reader(192.168.10.202)
[root@monitor ~]#mmm_control show
db1(192.168.10.20) master/ONLINE. Roles:
db2(192.168.10.30) master/ONLINE. Roles: writer(192.168.10.200)
db3(192.168.10.40) slave/ONLINE. Roles: reader(192.168.10.202)
db4(192.168.10.50) slave/ONLINE. Roles: reader(192.168.10.201)
在一段时间的交接后,slave1 重新获取到 VIP,继续工作
grant all on *.* to 'test'@'192.168.10.90' identified by '123456';
flush privileges;
yum -y install mariadb-server mariadb
systemctl start mariadb.service && systemctl enable mariadb.service
mysql -utest -p123456 -h 192.168.10.200 #能登录则成功
monitor
MySQL [(none)]> create database client_test;
Query OK, 1 row affected (0.00 sec)
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| client_test |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
6 rows in set (0.01 sec)
master1
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| client_test |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
6 rows in set (0.00 sec)
master2
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| client_test |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
6 rows in set (0.00 sec)
slave1
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| client_test |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
6 rows in set (0.00 sec)
slave2
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| client_test |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
6 rows in set (0.00 sec)