1.MySQL双主(主主)架构方案思路是:
1.两台mysql都可读写,互为主备,默认只使用一台(masterA)负责数据的写入,另一台(masterB)备用;
2.masterA是masterB的主库,masterB又是masterA的主库,它们互为主从;
3.两台主库之间做高可用,可以采用keepalived等方案(使用VIP对外提供服务);
4.所有提供服务的从服务器与masterB进行主从同步(双主多从);
5.建议采用高可用策略的时候,masterA或masterB均不因宕机恢复后而抢占VIP(非抢占模式);
这样做可以在一定程度上保证主库的高可用,在一台主库down掉之后,可以在极短的时间内切换到另一台主库上(尽可能减少主库宕机对业务造成的影响),减少了主从同步给线上主库带来的压力;
但是也有几个不足的地方:
1.masterB可能会一直处于空闲状态(可以用它当从库,负责部分查询);
2.主库后面提供服务的从库要等masterB先同步完了数据后才能去masterB上去同步数据,这样可能会造成一定程度的同步延时;
2.主主环境(这里只介绍2台主的配置方案):
1.CentOS 64位 2台:masterA(192.168.139.130),masterB(192.168.139.131)
2.官方Mysql5.6版本
3.创建过程
3.1 首先我们两台虚拟机上都要安装好mysql,并启动(具体安装过程可以参考我的第十七课预习任务的方法)
//在masterA上
[root@knightlai01 ~]# ps aux |grep mysql
root 988 0.0 0.1 115432 1704 ? S Oct20 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data/mysql --pid-file=
mysql 1188 0.0 46.3 1302820 462644 ? Sl Oct20 0:57 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/data/myscal/mysql/lib/plugin --user=mysql --log-error=/data/mysql/error.log --pid-file=/data/mysql/mysql.pid --socket=/tmp/mysql.sock
root 4047 0.0 0.0 112708 960 pts/0 S+ 20:27 0:00 grep --color=auto mysql
//在masterB上
[root@knightlai02 shell]# ps aux |grep mysql
root 974 0.0 0.1 115432 1700 ? S Oct20 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data/mysql --pid-file=/data/mysql/mysql.pid
mysql 1193 0.0 46.3 1333488 462280 ? Sl Oct20 1:03 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/data/mysql --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/data/mysql/error.log --pid-file=/data/mysql/mysql.pid --socket=/tmpmysql.sock
root 6134 0.0 0.0 112704 956 pts/0 R+ 21:20 0:00 grep --color=auto mysql
3.2 在MasterA上配置 /etc/my.cnf
[root@knightlai01 shell]# vim /etc/my.cnf
basedir = /usr/local/mysql
datadir = /data/mysql
socket = /tmp/mysql.sock
log-error = /data/mysql/error.log
pid-file = /data/mysql/mysql.pid
server_id=130
log_bin=knightlai #打开二进制功能,MASTER主服务器必须打开此项
binlog_format = mixed
relay-log =relay-bin
relay-log-index =slave-relay-bin.index
auto-increment-increment =1
auto-increment-offset =2
#masterA自增长ID
auto_increment_offset = 1
auto_increment_increment = 2 #奇数ID
在MasterB上配置
basedir = /usr/local/mysql
datadir = /data/mysql
socket = /tmp/mysql.sock
log-error = /data/mysql/error.log
pid-file = /data/mysql/mysql.pid
server_id=131
log_bin=slave
binlog_format= mixed
relay-log=relay-bin
relay-log-index= slave-relay-bin.index
auto-increment-increment= 2
auto-increment-offset=2
注意:mysql1和mysql只有server-id不同和auto-increment-offset不同,其他必须相同。
binlog_format= mixed:指定mysql的binlog日志的格式,mixed是混合模式。
relay-log:开启中继日志功能
relay-log-index:中继日志清单
auto-increment-increment= 2:表示自增长字段每次递增的量,其默认值是1。它的值应设为整个结构中服务器的总数,本案例用到两台服务器,所以值设为2。
auto-increment-offset= 2:用来设定数据库中自动增长的起点(即初始值),因为这两能服务器都设定了一次自动增长值2,所以它们的起点必须得不同,这样才能避免两台服务器数据同步时出现主键冲突。
//如果是克隆的虚拟机需要修改这个uuid
[root@knightlai01 shell]# cat /data/mysql/auto.cnf
[auto]
server-uuid=b14b02c7-b46b-11e8-b604-000c29ecfccf
3.3 创建数据库相关账户并开户主从同步
在MasterA 上配置
//添加主从同步账户
mysql> grant replication slave on *.* to 'repl'@'192.168.139.131' identified by '123456';
Query OK, 0 rows affected (0.19 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.07 sec)
//查看主库状态 记住这个值 “file” “position”
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| knightlai.000007 | 411 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.02 sec)
//配置同步信息
mysql> change master to master_host='192.168.139.131',master_port=3306,master_user='repl',master_password='123456',master_log_file='slave.000001',master_log_pos=120;
Query OK, 0 rows affected, 2 warnings (1.31 sec)
mysql> start slave;
Query OK, 0 rows affected (0.88 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.139.131
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: slave.000001
Read_Master_Log_Pos: 120
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 279
Relay_Master_Log_File: slave.000001
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: 120
Relay_Log_Space: 452
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: 131
Master_UUID: b14b02c7-b46b-44e8-b604-000c29ecfccf
Master_Info_File: /data/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
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
1 row in set (0.02 sec)
在Master B上配置
注意:由于这里是测试环境,可以保证没数据写入,否则需要的步骤是:先masterA锁表-->masterA备份数据-->masterA解锁表 -->masterB导入数据-->masterB设置主从-->查看主从
mysql> grant replication slave on *.* to 'repl'@'192.168.139.130' identified by '123456';
Query OK, 0 rows affected (0.56 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.05 sec)
mysql> show master status;
+--------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+--------------+----------+--------------+------------------+-------------------+
| slave.000001 | 120 | | | |
+--------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
mysql> change master to master_host='192.168.139.130',master_port=3306,master_user='repl',master_password='123456',master_log_file='knightlai.000007',master_log_pos=411;
Query OK, 0 rows affected, 2 warnings (0.08 sec)
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.139.130
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: knightlai.000007
Read_Master_Log_Pos: 411
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 283
Relay_Master_Log_File: knightlai.000007
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: 411
Relay_Log_Space: 450
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: 168
Master_UUID: b14b02c7-b46b-11e8-b604-000c29ecfccf
Master_Info_File: /data/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
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
1 row in set (0.15 sec)
3.4 测试主从同步
在MasterA上创建一个数据库
mysql> create database test1;
Query OK, 1 row affected (0.03 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| test |
| test1 |
| test1012 |
| zrlog |
+--------------------+
8 rows in set (0.18 sec)
在Master B上查看
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| test |
| test1 |
| test1012 |
| zrlog |
+--------------------+
8 rows in set (0.15 sec)
4.配置keepalived 高可用
4.1 安装keepalived
//在Master A上安装keepalived
[root@knightlai02 ~]# ps aux |grep keep
zabbix 1561 0.0 0.2 254844 2448 ? S 22:44 0:00 /usr/sbin/zabbix_server: housekeeper [startup idle for 30 minutes]
root 2132 0.0 0.1 118676 1348 ? Ss 22:47 0:00 /usr/sbin/keepalived -D
root 2133 0.0 0.3 129608 3308 ? S 22:47 0:00 /usr/sbin/keepalived -D
root 2134 0.0 0.2 129548 2812 ? S 22:47 0:00 /usr/sbin/keepalived -D
root 2170 0.0 0.0 112708 960 pts/0 S+ 22:47 0:00 grep --color=auto keep
//在Master B上安装keepalived
[root@knightlai02 ~]# ps aux |grep keep
zabbix 1561 0.0 0.2 254844 2448 ? S 22:44 0:00 /usr/sbin/zabbix_server: housekeeper [startup idle for 30 minutes]
root 2132 0.0 0.1 118676 1348 ? Ss 22:47 0:00 /usr/sbin/keepalived -D
root 2133 0.0 0.3 129608 3308 ? S 22:47 0:00 /usr/sbin/keepalived -D
root 2134 0.0 0.2 129548 2812 ? S 22:47 0:00 /usr/sbin/keepalived -D
root 2170 0.0 0.0 112708 960 pts/0 S+ 22:47 0:00 grep --color=auto keep
4.2 编辑Master A上的配置文件
[root@knightlai02 init.d]# cat /etc/keepalived/keepalived.conf
global_defs {
notification_email {
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_mysql {
script "/usr/local/sbin/check_ng.sh"
interval 3
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass aminglinux>com
}
virtual_ipaddress {
192.168.139.100
}
track_script {
chk_mysql
}
}
4.3 编辑Master B上的配置文件
[root@knightlai01 ~]# cat /etc/keepalived/keepalived.conf
global_defs {
notification_email {
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_mysql {
script "/usr/local/sbin/check_ng.sh"
interval 3
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
nopreempt
advert_int 1
authentication {
auth_type PASS
auth_pass aminglinux>com
}
virtual_ipaddress {
192.168.139.100
}
track_script {
chk_mysql
}
}
4.4 两个配置脚本内容一致,路径一致
//Master A与B上面的脚本一样
[root@knightlai02 init.d]# cat /usr/local/sbin/check_mysql.sh
#时间变量,用于记录日志
d=`date --date today +%Y%m%d_%H:%M:%S`
#计算mysqld进程数量
n=`ps -C mysqld --no-heading|wc -l`
#如果进程为0,则启动mysqld,并且再次检测mysqld进程数量,
#如果还为0,说明mysqld无法启动,此时需要关闭keepalived
if [ $n -eq "0" ]; then
# systemctl start mysqld
sleep 3
n2=`ps -C mysqld --no-heading|wc -l`
if [ $n2 -eq "0" ]; then
echo "$d mysqld down,keepalived will stop" >> /var/log/mysql.log
systemctl stop keepalived
fi
fi
5.模拟测试mysqld高可用
5.1 模拟master A上面mysql keepalived故障
用测试机192.168.139.134去测试mysql
//在Master A上面关闭mysqld服务
[root@knightlai02 init.d]# systemctl stop mysqld
[root@knightlai02 init.d]# ps aux |grep mysqld
root 13947 0.0 0.0 112704 956 pts/0 S+ 04:33 0:00 grep --color=auto mysqld
//在134测试机上面访问mysql 192.168.139.100
MySQL [(none)]> show global variables like 'server%';
+----------------+--------------------------------------+
| Variable_name | Value |
+----------------+--------------------------------------+
| server_id | 131 |
| server_id_bits | 32 |
| server_uuid | b14b02c7-b46b-44e8-b604-000c29ecfccf |
+----------------+--------------------------------------+
3 rows in set (0.00 sec)
//这里的server_id 131,说明我们访问的是第一台Master B
[root@knightlai02 init.d]# cat /etc/my.cnf
[mysqld]
server_id=131
basedir = /usr/local/mysql
datadir = /data/mysql
socket = /tmp/mysql.sock
log-error = /data/mysql/error.log
pid-file = /data/mysql/mysql.pid
5.2 模拟master B上面mysql keepalived故障
//在Master B上面关闭mysqld服务
[root@knightlai02 init.d]# systemctl stop mysqld
[root@knightlai02 init.d]# ps aux |grep mysqld
root 13947 0.0 0.0 112704 956 pts/0 S+ 04:33 0:00 grep --color=auto mysqld
//在134测试机上面访问mysql 192.168.139.100
MySQL [(none)]> show global variables like 'server%';
+----------------+--------------------------------------+
| Variable_name | Value |
+----------------+--------------------------------------+
| server_id | 130 |
| server_id_bits | 32 |
| server_uuid | b14b02c7-b46b-44e8-b604-000c29ecfccf |
+----------------+--------------------------------------+
3 rows in set (0.00 sec)
//这里的server_id 130,说明我们访问的是第一台Master A
[root@knightlai02 init.d]# cat /etc/my.cnf
[mysqld]
server_id=130
basedir = /usr/local/mysql
datadir = /data/mysql
socket = /tmp/mysql.sock
log-error = /data/mysql/error.log
pid-file = /data/mysql/mysql.pid