一 测试架构设计和目标:
1)Master(192.168.31.230)为正常运行环境下的主库,为两个Slave(192.168.31.231和192.168.31.232)提供“主-从”复制功能;
2)Master_Backup(192.168.31.233)是Master的备份库,只要Master是正常的,它不对外提供服务。它与Master之间属于"主-主"复制关系,即自己既是主机,又是对方的从机;
3)同理,192.168.31.234和192.168.31.235为Slave_Backup,分别为192.168.31.231和 192.168.31.232的备份库,只要Slave是正常的,对应的备份机不对外提供服务;
4)Slave在此架构中的目的是为了实现读写分离,对应用程序来说,Master只负责写,两个Slave只负责读。Slave的数据来源于Master的复制操作;
5)如果Master由于某种原因(例如:宕机和断电等)导致不能正常运行,则此时需要让Master_Backup自动切换为新主机,而Slave和Slave_Backup也能自动切换数据源到Master_Backup;
6)同理,如果Slave由于某种原因(例如:宕机和断电等)导致不能正常运行,则此时需要让对应的Slave_Backup自动切换为新从机;
7)无论是Master还是切换后的Master_Backup,它们向客户端提供的连接地址应保持一致,如上图提供的VIP+Port,即192.168.31.201:3306,Slave和Slave_Backup也应如此,对外提供的连接地址始终是192.168.31.202:3306和192.168.31.203:3306。
二 实现部署测试
首先完成双主部署
1 在masterA上新建一个账户,用户masterB同步数据
masterA操作
> GRANT REPLICATION SLAVE ON *.* TO 'master'@'192.168.31..%' IDENTIFIED BY '123456';
> FLUSH PRIVILEGES;
> FLUSH TABLES WITH READ LOCK;
mysqldump -uroot -p123456 --databases test >/tmp/testA.sql
scp /tmp/testA.sql 192.168.31.233:/tmp
> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)
2 masterB:上同样的建立复制到账户,并导入数据
mysql> GRANT REPLICATION SLAVE ON *.* TO 'master'@'192.168.31.%' IDENTIFIED BY '123456';mysql> FLUSH TABLES WITH READ LOCK;
mysqldump -uroot -p123456 --databases test >/tmp/testB.sql
scp /tmp/testB.sql 192.168.31.230:/tmp/
# 分别在master1 和 master2上分别导入对方的数据.但是存在一个问题: 因为存在主键冲突的情况,导出数据的时候,不要把主键给导出来了;如果是一方没有数据,那就直接导入数据就好了,不过也要跳过主键;
mysql -uroot -p123456 </tmp/testA.sql
mysql -uroot -p123456 </tmp/testB.sql
3 修改master1和master2 的配置文件 ,只是server-id 不同
master1:的配置文件
vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
#datadir=/mysqldata
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
#### Master ####
server-id = 1
log-bin = mysql-bin
log-bin-index = mysql-bin.index
relay-log = mysql-relay
relay-log-index = mysql-relay.index
expire-logs-days = 10
max-binlog-size = 100M
log-slave-updates = 1
binlog-do-db = test
replicate-do-db = test
binlog-ignore-db = mysql
replicate-ignore-db = mysql
sync-binlog = 1
auto-increment-increment = 2
auto-increment-offset = 1
# master2:的配置文件
vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
### Master ####
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
server-id = 2
log-bin = mysql-bin
log-bin-index = mysql-bin.index
relay-log = mysql-relay
relay-log-index = mysql-relay.index
expire-logs-days = 10
max-binlog-size = 100M
log-slave-updates
skip-slave-start
slave-skip-errors = all
binlog-do-db = test
replicate-do-db = test
binlog-ignore-db = mysql
replicate-ignore-db = mysql
sync-binlog = 1
auto-increment-increment = 2
auto-increment-offset = 2
4 分别在master1和master2上获取File和Position位置
master1:
>flush tables with read lock;
>show matser status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB |Binlog_Ignore_DB
+------------------+----------+--------------+------------------+
| mysql-bin.000002| 106 | test | mysql
+------------------+----------+--------------+------------------+
>unlock tables;
master2:
>flush tables with read lock;
>show matser status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB |Binlog_Ignore_DB
+------------------+----------+--------------+------------------+
| mysql-bin.000003| 106 | test | mysql
+------------------+----------+--------------+------------------+
>unlock tables;
5 配置主从,分别在master1和 master2上配置对方的从
master1上:
> CHANGE MASTER TO
-> MASTER_HOST='192.168.31.233',
-> MASTER_USER='master',
-> MASTER_PASSWORD='123456',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql-bin.000003',
-> MASTER_LOG_POS=106,
-> MASTER_CONNECT_RETRY=10;
Query OK, 0 rows affected (0.02 sec)
mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)
master2上:
> CHANGE MASTER TO
-> MASTER_HOST='192.168.31230',
-> MASTER_USER='master',
-> MASTER_PASSWORD='123456',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql-bin.000002',
-> MASTER_LOG_POS=106,
-> MASTER_CONNECT_RETRY=10;
Query OK, 0 rows affected (0.02 sec)
mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)
用>show processlist查看进程状态
接着为双主机器各部署两个从机并测试是否主从正常(主从部署略,其步骤与双主大致相同,注意修改部分参数即可,这里不在详细写出可参考 )
6 测试结果
1)当Master和Master_Backup都正常运行时,在任意一端更新数据后都会同步到两个Slave上
2)当Master处于正常时,无论Master_Backup是否正常,在此端更新数据后都会同步到两个Slave上
3)当Master处于不可运行时,Master_Backup通过Monitor(Keepalived)成为接管者,在Master_Backup更新数据后不会同步到所有Slave上,即使后来在Slave上将MASTER_HOST指定为Keepalived提供的VIP(192.168.31.201)也无用。
究其原因,Master_Server_Id指向的是已经处于不可运行的Master,而预期结果是希望它能自动的更新定位到Master_Backup(233)上达到自动切换目的,然而测试结果并能不满足快速响应容灾切换的目的。
三 修改架构及部署
选择mysql-mmm结合半同步机制来实现容灾自动切换
1 在master(230和233)上安装semisync master并设置
mysql代码:
>INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
>INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
>SET GLOBAL rpl_semi_sync_master_enabled = 1;
>SET GLOBAL rpl_semi_sync_slave_enabled = 1;
vim /ect/my.cnf后加入如下配置:
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_slave_enabled = 1
2 在slave(231、232、234和235)上安装slave插件并设置
mysql代码:
>INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
>SET GLOBAL rpl_semi_sync_slave_enabled = 1;
vim /ect/my.cnf后加入如下配置:
rpl_semi_sync_slave_enabled = 1
3 所有mysql实例停止slave并开启slave,使半同步机制生效
mysql代码 :
>stop slave;
>start slave;
4 查看semisync状态
mysql代码:
>show status like '%emi%';
重点关注:
1)Rpl_semi_sync_master_clients:与当前master建立半同步连接的客户端数
2)Rpl_semi_sync_master_status:作为半同步master端的就绪状态(ON:就绪,OFF:未就绪)
3)Rpl_semi_sync_slave_status:作为半同步slave端的就绪状态(ON:就绪,OFF:未就绪)
5 安装mysql-mmm
5.1新增一台专门用于监控mysql的服务器(mysql_monitor),IP为192.168.31.250
5.2在mysql_monitor、master、master_backup、slave和slave_backup上安装epel网络源
yum install http://mirrors.hustunique.com/epel//6/x86_64/epel-release-6-8.noarch.rpm
5.3在mysql_monitor上安装mysql-mmm-monitor
yum -y install mysql-mmm-monitor
5.4 编辑mysql_monitor上的配置文件mmm_mon.conf
vi /etc/mysql-mmm/mmm_mon.conf
include mmm_common.conf
<monitor>
# 本机IP
ip 192.168.31.250
port 9988
pid_path /var/run/mysql-mmm/mmm_mond.pid
bin_path /usr/libexec/mysql-mmm
status_path /var/lib/mysql-mmm/mmm_mond.status
ping_ips 192.168.31.230, 192.168.31.231, 192.168.31.232, 192.168.31.233, 192.168.31.234, 192.168.31.235 # 所有MySQL服务器的IP
auto_set_online 0
</monitor>
<host default>
# GRANT REPLICATION CLIENT ON语句创建的账号和密码
monitor_user mmm_monitor
monitor_password monitor
</host>
<check mysql>
check_period 5 # 每5秒检查一次
trap_period 10
timeout 2 # 检查超时秒数
restart_after 10000
max_backlog 60
</check>
<code># 设置为1,开启调试模式,打印日志到前台,ctrl+c将结束进程,对于调试有帮助</code>
debug 0
6 在master、master_backup、slave和slave_backup上安装和配置
1)安装mysql-mmm-agent
yum -y install mysql-mmm-agent
2)授权monitor访问
mysql代码 :
>GRANT REPLICATION CLIENT ON *.* TO 'mmm_monitor'@'192.168.31.%' IDENTIFIED BY 'monitor';
>GRANT SUPER,REPLICATION CLIENT, PROCESS ON *.* TO 'mmm_agent'@'192.168.31.%' IDENTIFIED BY'agent';
3)编辑mmm_agent.conf配置文件
vim /etc/mysql-mmm/mmm_agent.conf
include mmm_common.conf # 包含公用配置文件
<span style="color: #000000;">mmm_common.conf中定义的某个host名称</span></span></code> # 对应<code><span style="color: #008000;">
this db1 # 设置成1时,将打印日志到前台,按ctrl+c将结束进程
debug 0
max_kill_retries 1
4)编辑mmm_common.conf配置文件
vim /etc/mysql-mmm/mmm_common.conf
active_master_role writer
<host default>
# 对应当前主机的网络接口名
cluster_interface eth2
pid_path /var/run/mysql-mmm/mmm_agentd.pid
bin_path /usr/libexec/mysql-mmm/
mysql_port 3306
agent_port 9989
# 对应GRANT REPLICATION SLAVE ON语句创建的账号和密码
replication_user slave
replication_password slave123
# GRANT SUPER,REPLICATION CLIENT, PROCESS ON语句创建的账号和密码
agent_user mmm_agent
agent_password agent
</host>
# master的配置
# 其中host后面的值定义的是某台数据库服务的别名,一般就用服务器的主机名即可
<host db1>
ip 192.168.31.230
mode master
# db1的master对等点
peer db2
</host>
# master_backup的配置
<host db2>
ip 192.168.31.233
mode master
# db2的master对等点
peer db1
</host>
# slave的配置
<host db3>
ip 192.168.31.231
mode slave
</host>
# slave的配置
<host db4>
ip 192.168.31.232
mode slave
</host>
# slave_backup的配置
<host db5>
ip 192.168.31.234
mode slave
</host>
# slave_backup的配置
<host db6>
ip 192.168.31.235
mode slave
</host>
# 定义writer角色,即架构中的master和master_backup
# ips为writer对外提供的vip
<role writer>
hosts db1, db2
ips 192.168.31.201
mode exclusive
</role>
# 定义reader角色,即架构中的两个slave和两个slave_backup
# ips为reader对外提供的vip
<role reader>
hosts db3, db4, db5, db6
ips 192.168.31.202, 192.168.31.203
mode balanced
</role>
注意,也需要将此配置文件复制到mysql_monitor的同名目录下
5) 在master、master_backup、slave和slave_backup上启动mmm agent服务,并设置为开机服务
/etc/init.d/mysql-mmm-agent start
vim /etc/rc.d/rc.local后,将上述命令行添加到mysql启动命令的下面
7 在上mysql_monitor开启mmm monitor监控,并设置为开机服务
/etc/init.d/mysql-mmm-monitor start
vi /etc/rc.d/rc.local后,将上述命令行添加
8 然后重启所有服务器系统后测试
1)在mysql_monitor上执行如下命令,查看各监控机的运行状态
执行mmm_control show 查看
2)测试结果
1)当Master和Master_Backup都正常运行时,在任意一端更新数据后都会同步到两个Slave上
2)当Master处于正常时,无论Master_Backup是否正常,在此端更新数据后都会同步到两个Slave上
3)当Master处于不可运行时,Master_Backup通过Monitor(Keepalived)成为接管者,在Master_Backup更新数据后会同步到所有Slave上,符合预期
四 问题处理总结
1 架构图中看出,Mmm_Mnitor存在单点问题,当Mmm_Mnitor处于不可运行时,整个主从结构将不能正常运行。可以部署多个监控,结合Keepalived来扩展。
2 读写分离会带来数据延迟达到的问题。假设有一个业务,当数据插入到数据库后要立即又从数据库中将此数据查询出来,因此当数据插入到Master库后,由于网络的延迟,Slave库中不会立即得到这条最新的数据,此时应用程序查询Slave库将得不到预期结果。
解决问题:将此类业务控制在一个数据库事务中进行,读写都在master中进行。因此,在mmm_common.conf配置文件中,还需要将db1和db2同时配置在reader组:
<role writer>
hosts db1, db4
ips 192.168.31.201
mode exclusive
</role>
<role reader>
hosts db1, db4, db2, db3, db5, db6
ips 192.168.31.202, 192.168.31.203
mode balanced
</role>
3 主从复制差距的问题。有时候因为主服务器的更新过于频繁,造成了从服务器更新速度较慢,当然问题是多种多样,有可能是网络搭建的结构不好或者硬件的性能较差,从而使得主从服务器之间的差距越来越大,最终对某些应用产生了影响。
解决问题:定期进行主从服务器的数据同步,具体步骤如下在主服务器上
mysql> FLUSH TABLES WITH READ LOCK;Query OK, 0 rows affected (0.03 sec)mysql> show master status\G;*************************** 1. row ***************************File: mysql-bin.000004Position: 102Binlog_Do_DB:Binlog_Ignore_DB:1 row in set (0.00 sec)
记录出日志的名字和偏移量,这些是从服务器复制的目的目标;在从服务器上,使用MASTER_POS_WAIT()函数得到复制坐标值
mysql> select master_pos_wait('mysql-bin.000004','102');+-------------------------------------------+| master_pos_wait('mysql-bin.000004','102') |+-------------------------------------------+| 0 |+-------------------------------------------+1 row in set (0.00 sec)
这个select 语句会阻塞直到从服务器达到指定日志文件和偏移量后,返回0,如果是-1,则表示超时退出,查询是0时,表示从服务器与主服务器已经同步