docker部署mysql主主备份(keepalived)跨主机自动切换
docker部署mysql主主备份 haproxy代理(swarm)
? 主主复制即在两台MySQL主机内都可以变更数据,而且另外一台主机也会做出相应的变更。聪明的你也许已经想到该怎么实现了。对,就是将两个主从复制有机合并起来就好了。只不过在配置的时候我们需要注意一些问题,例如,主键重复,server-id不能重复等等。
? 两台MySQL之间互为彼此的从库,同时又是主库。这种方案,既做到了访问量的压力分流,同时也解决了“单点故障”问题。任何一台故障,都还有另外一套可供使用的服务。
主主复制----->互为主从
搭建一个两主的Mysql环境
实现一个数据库挂掉自动切换数据库
从属关系 | 容器名称 | 服务器 | 端口 | vip |
---|---|---|---|---|
主 | mysql-master1 | 192.168.56.100 | 3306 | 192.168.56.120 |
主 | mysql-master2 | 192.168.56.101 | 3306 |
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.56.101" accept"
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.56.100" accept"
firewall-cmd --reload
firewall-cmd --list-all
mkdir -p /home/scsdm/services/mysql && cd /home/scsdm/services/mysql
cat > docker-compose.yml << EOF
version: '3'
services:
node1:
image: mysql:5.7.23
hostname: mysql-master1
container_name: mysql-master1
restart: always
ports:
- "3306:3306"
network_mode: host
environment:
- MYSQL_ROOT_PASSWORD=hancloud1234!
- TZ=Asia/Shanghai
volumes:
- $PWD/mysql_master1/slowSql:/data/mysql
- $PWD/mysql_master1/data:/var/lib/mysql
- $PWD/mysql_master1/logs:/var/log/mysql
- $PWD/mysql_master1/conf/my.cnf:/etc/mysql/my.cnf
privileged: true
command: ['mysqld','--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci','--default-time-zone=+08:00']
entrypoint: bash -c "chown -R mysql:mysql /var/log/mysql && exec /entrypoint.sh mysqld"
EOF
mkdir -p /home/scsdm/services/mysql/mysql_master1/conf
cd /home/scsdm/services/mysql/mysql_master1/conf
cat > my.cnf << EOF
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time-zone=+08:00
max_connections=1000
# 开启binlog
log-bin=mysql-bin
log-bin-index=mysql-bin.index
# 服务器唯一id,默认值1
server-id=1
max_binlog_size=1G
max_binlog_cache_size=1G
# 设置日志格式,默认值ROW
binlog_format=mixed
expire_logs_days=7
# 开启慢查询
slow_query_log=1
long_query_time=2
slow_query_log_file=/data/mysql/slow.log
# 错误日志
log_error=/var/log/mysql/error.log
# 设置需要复制的数据库,默认复制全部数据库
#binlog-do-db=mcp_manager
# 设置不需要复制的数据库
binlog-ignore-db=mysql
binlog-ignore-db=infomation_schema
EOF
cd /home/scsdm/services/mysql
# my.cnf 权限不能是777,会被忽略
chmod 644 /home/scsdm/services/mysql/mysql_master1/conf/my.cnf
docker-compose up -d
#进入容器:env LANG=C.UTF-8 避免容器中显示中文乱码
docker exec -it mysql-master1 env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
-- 创建slave用户
CREATE USER 'slave'@'%';
-- 设置密码
ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY 'hancloud@1234';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
查看创建的用户信息
select host,user from mysql.user;
执行完此步骤后不要再操作主服务器MYSQL
,防止主服务器状态值变化
SHOW MASTER STATUS;
记下File
和Position
的值。
执行完此步骤后不要再操作主服务器MYSQL,防止主服务器状态值变化。
mkdir -p /home/scsdm/services/mysql && cd /home/scsdm/services/mysql
cat > docker-compose.yml << EOF
version: '3'
services:
node1:
image: mysql:5.7.23
hostname: mysql-master2
container_name: mysql-master2
restart: always
ports:
- "3306:3306"
network_mode: host
environment:
- MYSQL_ROOT_PASSWORD=hancloud1234!
- TZ=Asia/Shanghai
volumes:
- $PWD/mysql_master2/slowSql:/data/mysql
- $PWD/mysql_master2/data:/var/lib/mysql
- $PWD/mysql_master2/logs:/var/log/mysql
- $PWD/mysql_master2/conf/my.cnf:/etc/mysql/my.cnf
privileged: true
command: ['mysqld','--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci','--default-time-zone=+08:00']
entrypoint: bash -c "chown -R mysql:mysql /var/log/mysql && exec /entrypoint.sh mysqld"
EOF
mkdir -p /home/scsdm/services/mysql/mysql_master2/conf
cd /home/scsdm/services/mysql/mysql_master2/conf
cat > my.cnf << EOF
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time-zone=+08:00
max_connections=1000
# 开启binlog
log-bin=mysql-bin
log-bin-index=mysql-bin.index
# 服务器唯一id,默认值1
server-id=2
max_binlog_size=1G
max_binlog_cache_size=1G
# 设置日志格式,默认值ROW
binlog_format=mixed
expire_logs_days=7
# 开启慢查询
slow_query_log=1
long_query_time=2
slow_query_log_file=/data/mysql/slow.log
# 错误日志
log_error=/var/log/mysql/error.log
# 设置需要复制的数据库,默认复制全部数据库
#binlog-do-db=mcp_manager
# 设置不需要复制的数据库
binlog-ignore-db=mysql
binlog-ignore-db=infomation_schema
EOF
cd /home/scsdm/services/mysql
# my.cnf 权限不能是777,会被忽略
chmod 644 /home/scsdm/services/mysql/mysql_master2/conf/my.cnf
docker-compose up -d
#进入容器:env LANG=C.UTF-8 避免容器中显示中文乱码
docker exec -it mysql-master2 env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
-- 创建slave用户
CREATE USER 'slave'@'%';
-- 设置密码
ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY 'hancloud@1234';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
执行完此步骤后不要再操作主服务器MYSQL
,防止主服务器状态值变化
SHOW MASTER STATUS;
记下File
和Position
的值。
# 配置主Mysql地址
CHANGE MASTER TO MASTER_HOST='192.168.56.100',
# 配置主Mssql创建的用于备份的用户名和密码和端口
MASTER_USER='slave',MASTER_PASSWORD='hancloud@1234', MASTER_PORT=3306,
# 配置主Mssql的binlog日志名称和当前所在位置(上面记录的位置)
MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=959;
START SLAVE;
-- 查看状态(不需要分号)
SHOW SLAVE STATUS\G
# 配置主Mysql地址
CHANGE MASTER TO MASTER_HOST='192.168.56.101',
# 配置主Mssql创建的用于备份的用户名和密码和端口
MASTER_USER='slave',MASTER_PASSWORD='hancloud@1234', MASTER_PORT=3306,
# 配置主Mssql的binlog日志名称和当前所在位置(上面记录的位置)
MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=959;
START SLAVE;
-- 查看状态(不需要分号)
SHOW SLAVE STATUS\G
-- 在从机上执行。功能说明:停止I/O 线程和SQL线程的操作。
stop slave;
-- 在从机上执行。功能说明:用于删除SLAVE数据库的relaylog日志文件,并重新启用新的relaylog文件。
reset slave;
-- 在主机上执行。功能说明:删除所有的binglog日志文件,并将日志索引文件清空,重新开始所有新的日志文件。
-- 用于第一次进行搭建主从库时,进行主库binlog初始化工作;
reset master;
mkdir -p /home/scsdm/services/keepalived/checksh && cd /home/scsdm/services/keepalived
cat > /home/scsdm/services/keepalived/checksh/check-mysql.sh << EOF
#!/bin/bash
count=`netstat -apn | grep 3306 | wc -l`
if [ $count -gt 0 ]; then
exit 0
else
sleep 2
count=`netstat -apn | grep 3306 | wc -l`
if [ $count -gt 0 ]; then
pkill keepalived
fi
exit 1
fi
EOF
# 虚拟ip
IP="192.168.56.120"
# 需要的网卡
ETH="enp0s3"
cat > /home/scsdm/services/keepalived/keepalived.conf << EOF
global_defs {
router_id LVS_2
script_user root # 脚本执行用户
enable_script_security # 开启脚本安全权限
}
vrrp_script checkMsql
{
script "/checksh/check-mysql.sh" # 这个地址写的事容器内脚本路径
interval 2
weight -30
}
vrrp_instance VI_1 {
state BACKUP
# 注意网卡
interface ETH
virtual_router_id 51
priority 100
advert_int 1
nopreempt
virtual_ipaddress {
# 需要修改成对应的虚拟ip
IP
}
authentication {
auth_type PASS
auth_pass password
}
track_script {
checkMsql
}
}
EOF
cat > /home/scsdm/services/keepalived/docker-compose.yml << EOF
version: '3'
services:
keepalived:
image: osixia/keepalived:stable
hostname: keepalived
volumes:
- "${PWD}/checksh:/checksh"
- "${PWD}/keepalived.conf:/container/service/keepalived/assets/keepalived.conf"
- "/etc/localtime:/etc/localtime:ro"
restart: always
privileged: true
network_mode: host
command: --loglevel debug --copy-service
EOF
docker-compose up -d
即可使用该虚拟ip访问
CREATE DATABASE mcp_manager;
USE mcp_manager;
CREATE TABLE t_user (
id BIGINT AUTO_INCREMENT,
uname VARCHAR(30),
PRIMARY KEY (id)
);
INSERT INTO t_user(uname) VALUES('xiaohong');
INSERT INTO t_user(uname) VALUES('xiaoming');
INSERT INTO t_user(uname) VALUES('xiaohong2');
INSERT INTO t_user(uname) VALUES('xiaoming2');
当从库IO线程接受到主库传递来的二进制日志(Binlog)并将之保存为从库的中继日志(relay log),然后从库SQL线程将中继日志(relay log)的事件重做到从库上,实现主从数据同步。
如果SQL线程发现该事件的server_id与当前从库的server_id相同,则会丢弃该事件,因此如果两台MySQL如何互为主从,不会导致相同的事件被重复执行。
在一套MySQL复制群集中,通过双主或多主架构,解决一主多从架构的单点故障,减少主从切换的故障处理时间,增加MySQL群集的高可用性。
1、主备模式,两台MySQL互为主从,其中一台作为主节点对外提供服务,另外一台作为备机节点(standby),当提供服务的主节点发生故障后,将服务请求快速切换到备用节点,原主节点故障恢复后转换为备用节点(standby)。
2、主主模式,两台MySQL互为主从,且两台MySQL均作为主节点对外提供服务,当其中一台MySQL发生故障后,将指向该故障节点的请求快速切换到另外一台MySQL,原来指向非故障节点的请求不受影响。
在主主模式下,两个主库都提供读写服务,如果应用通过两个主库操作相同数据,则会发生冲突导致数据覆盖(使用语句模式复制)或复制异常(使用行模式复制),因此需要对读写服务进行控制:
1、基于自主主键控制,通过设置自增属性auto_increment_offset和auto_increment_increment来控制每个主节点生产不同的自增值,并根据不同自增值访问不同主节点。
2、基于库级别或表级别控制,如应用APP1访问节点node1上的DB1库,而应用APP2访问节点node2上的DB2库,两个主节点间不会操作相同表的数据,因此不会存在事务冲突。
为保证应用程序使用相同数据库连接配置而不受故障切换影响,常用方案有:
1、VIP,通过vrrpd或keepalived将VIP动态绑定到新主节点
2、域名,通过切换域名将域名指向新主节点
3、代理,通过更新代理中存放的路由信息来指向新主节点。
1、主主模式能将读写请求分摊到两个主节点,有效提升服务器使用率。
2、主节点发生故障后,能快速进行主从切换。
3、当故障节点恢复后,故障节点能通过复制进行数据恢复(应用其他节点数据)和数据同步(将未同步数据发生给其他节点)。
1、当主节点上MySQL实例发生故障后,可能会存在部分数据(Binlog)未同步到另外的主节点,导致数据丢失(直到故障节点恢复)。
2、主主模式下,很容易因数据访问控制不当导致数据冲突。
3、为提高系统高可用性,双主架构会被扩展成双主多从结构,同样存在主节点发生故障后多个从库选主和恢复复制的问题。
在双主架构下,MySQL本身并没有自动故障切换能力,Google开源项目MySQL-MMM(Master-Master Replication Manager for MySQL)能够用来监控MySQL主主复制并实现自动故障转移。
在使用after_sync的半同步复制的双主架构下,能有效确保两个主库的BINLOG同步,再配合MMM工具实现自动故障转移,确保群集高可用。