一、MySQL高可用之多源复制
摘要:在 MySQL 8.0 版本中,提供了多源复制,多源复制的出现对于分库分表的业务提供了极大的便利,本文做了详细的说明
- 在 MySQL 8.0 版本中,提供了多源复制,多源复制的出现对于分库分表的业务提供了极大的便利,
- 目前我们已经部署了多套多源复制供统计使用。
- MySQL 5.7 之前只能实现一主一从、一主多从或者多主多从的复制。
- 如果想实现多主一从的复制,只能使用 MariaDB,但是 MariaDB 又与官方的MySQL 版本不兼容。
- MySQL 5.7 开始支持了多主一从的复制方式,也就是多源复制。
- MySQL 8.0 版本相比之前的版本,无论在功能还是性能、安全等方面都已经有不少的提升。
- 拓展:MySQL之父Widenius先生离开了Sun之后,觉得依靠Sun/Oracle来发展MySQL,
- 实在很不靠谱,于是决定另开分支,这个分支的名字叫做MariaDB。
多源复制的好处
- 可以集中备份,在从库上备份,不会影响线上的数据正常运行
- 节约购买从库服务器的成本,只需要一个从库服务器即可
- 数据汇总在一起,方便后期做数据统计
- 减轻DBA维护工作量。
Backing up multiple servers to a single server.
Merging table shards.
Consolidating data from multiple servers to a single server.
- 如上图,多源复制采用多通道的模式,和普通的复制相比,就是使用 FOR CHANNEL进行了分离。
- CHANGE MASTERTO....FORCHANNEL'm1';
- CHANGE MASTERTO....FORCHANNEL'm2';
- 要开启多源复制功能必须需要在从库上设置 master-info-repository 和 relay-log-info-repository 这两个参数。
- 这两个参数是用来存储同步信息的,可以设置的值为 FILE 和 TABLE,5.7默认值是 FILE。
- 比如 master-info 就保存在 master.info 文件中,
- relay-log-info 保存在 relay-log.info 文件中,
- 如果服务器意外关闭,正确的 relay-log-info 没有来得及更新到 relay-log.info 文件,这样会造成数据丢失。
- 为了数据更加安全,通常设为 TABLE。这些表都是 innodb 类型的,支持事务。
- 相对文件存储安全得多。在 MySQL 库下可以看见这两个表信息,分别是 mysql.slave_master_info 和 mysql.slave_relay_log_info。
- 这两个参数也是可以动态调整的。
- SET GLOBAL master_info_repository='TABLE';
- SET GLOBAL relay_log_info_repository='TABLE';
搭建过程支持GTID复制模式和binlog+position方式复制。
docker pull mysql:8.0.27
--docker network create --subnet=172.72.0.0/24 mysql-network docker rm -f mysql8027M33265 mysql8027M33266 mysql8027M33267 mysql8027M33268
mkdir -p /mysqlmultiple/master1/conf.d
mkdir -p /mysqlmultiple/master1/data mkdir -p /mysqlmultiple/master2/conf.d mkdir -p /mysqlmultiple/master2/data mkdir -p /mysqlmultiple/master3/conf.d mkdir -p /mysqlmultiple/master3/data mkdir -p /mysqlmultiple/slave/conf.d mkdir -p /mysqlmultiple/slave/data
- docker run -d --name mysql8027M33265 \
- -h master1 -p 33265:3306 --net=mysql-network --ip 172.72.0.10 \
- -v /mysqlmultiple/master1/conf.d:/etc/mysql/conf.d -v /mysqlmultiple/master1/data:/var/lib/mysql/ \
- -e MYSQL_ROOT_PASSWORD=jem \
- mysql:8.0.27
- docker run -d --name mysql8027M33266 \
- -h master2 -p 33266:3306 --net=mysql-network --ip 172.72.0.11 \
- -v /mysqlmultiple/master2/conf.d:/etc/mysql/conf.d -v /mysqlmultiple/master2/data:/var/lib/mysql/ \
- -e MYSQL_ROOT_PASSWORD=jem \
- mysql:8.0.27
- docker run -d --name mysql8027M33267 \
- -h master3 -p 33267:3306 --net=mysql-network --ip 172.72.0.12 \
- -v /mysqlmultiple/master3/conf.d:/etc/mysql/conf.d -v /mysqlmultiple/master3/data:/var/lib/mysql/ \
- -e MYSQL_ROOT_PASSWORD=jem \
- mysql:8.0.27
- docker run -d --name mysql8027S33268 \
- -h slave1 -p 33268:3306 --net=mysql-network --ip 172.72.0.13 \
- -v /mysqlmultiple/slave/conf.d:/etc/mysql/conf.d -v /mysqlmultiple/slave/data:/var/lib/mysql/ \
- -e MYSQL_ROOT_PASSWORD=jem \
- mysql:8.0.27
- cat > /mysqlmultiple/master1/conf.d/my.cnf << "EOF"
- [mysqld]
- user=mysql
- port=3306
- character_set_server=utf8mb4
- secure_file_priv=
- server-id = 802733265
- log-bin =
- binlog_format=row
- expire_logs_days = 30
- max_binlog_size = 100M
- binlog-ignore-db = mysql
- binlog-ignore-db = information_schema
- binlog-ignore-db = performance_schema
- binlog-ignore-db = sys
- replicate_ignore_db=information_schema
- replicate_ignore_db=performance_schema
- replicate_ignore_db=mysql
- replicate_ignore_db=sys
- gtid-mode=ON
- enforce-gtid-consistency=on
- skip_name_resolve
- report_host=172.72.0.10
- EOF
- cat > /mysqlmultiple/master2/conf.d/my.cnf << "EOF"
- [mysqld]
- user=mysql
- port=3306
- character_set_server=utf8mb4
- secure_file_priv=
- server-id = 802733266
- log-bin =
- binlog_format=row
- expire_logs_days = 30
- max_binlog_size = 100M
- binlog-ignore-db = mysql
- binlog-ignore-db = information_schema
- binlog-ignore-db = performance_schema
- binlog-ignore-db = sys
- replicate_ignore_db=information_schema
- replicate_ignore_db=performance_schema
- replicate_ignore_db=mysql
- replicate_ignore_db=sys
- gtid-mode=ON
- enforce-gtid-consistency=ON
- skip_name_resolve
- report_host=172.72.0.11
- EOF
- cat > /mysqlmultiple/master3/conf.d/my.cnf << "EOF"
- [mysqld]
- user=mysql
- port=3306
- character_set_server=utf8mb4
- secure_file_priv=
- server-id = 802733267
- log-bin =
- binlog_format=row
- expire_logs_days = 30
- max_binlog_size = 100M
- binlog-ignore-db = mysql
- binlog-ignore-db = information_schema
- binlog-ignore-db = performance_schema
- binlog-ignore-db = sys
- replicate_ignore_db=information_schema
- replicate_ignore_db=performance_schema
- replicate_ignore_db=mysql
- replicate_ignore_db=sys
- gtid-mode=ON
- enforce-gtid-consistency=ON
- skip_name_resolve
- report_host=172.72.0.12
- EOF
- cat > /mysqlmultiple/slave/conf.d/my.cnf << "EOF"
- [mysqld]
- user=mysql
- port=3306
- character_set_server=utf8mb4
- secure_file_priv=''
- server-id = 802733268
- log-bin =
- binlog_format=row
- expire_logs_days = 30
- max_binlog_size = 100M
- binlog-ignore-db = mysql
- binlog-ignore-db = information_schema
- binlog-ignore-db = performance_schema
- binlog-ignore-db = sys
- replicate_ignore_db=information_schema
- replicate_ignore_db=performance_schema
- replicate_ignore_db=mysql
- replicate_ignore_db=sys
- gtid-mode=ON
- enforce-gtid-consistency=ON
- skip_name_resolve
- report_host=172.72.0.13
- master-info-repository = table
- relay-log-info-repository = table
- EOF
- docker restart mysql8027M33265
- docker restart mysql8027M33266
- docker restart mysql8027M33267
- docker restart mysql8027S33268
- docker ps
登陆容器,确认数据 docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"
- docker exec -it mysql8027M33265 mysql -uroot -pjem
- mysql -uroot -pjem -h192.168.1.54 -P33265 -e "select @@hostname,@@server_id,@@server_uuid"
- mysql -uroot -pjem -h192.168.1.54 -P33266 -e "select @@hostname,@@server_id,@@server_uuid"
- mysql -uroot -pjem -h192.168.1.54 -P33267 -e "select @@hostname,@@server_id,@@server_uuid"
- mysql -uroot -pjem -h192.168.1.54 -P33268 -e "select @@hostname,@@server_id,@@server_uuid"
- 远程登陆需要修改密码
- docker exec -it mysql8027M33266 mysql -uroot -pjem
- mysql> alter user root@'%' identified with mysql_native_password by 'root'; --更改密码
- mysql> flush privileges;
- docker exec -it mysql8027S33268 mysql -uroot -pjem
- --在 3 台主库
- mysql -uroot -proot -h192.168.1.54 -P33265
- mysql -uroot -proot -h192.168.1.54 -P33266
- mysql -uroot -proot -h192.168.1.54 -P33267
- mysql> create user repl@'%' identified with mysql_native_password by 'root';
- mysql> grant all on *.* to repl@'%' with grant option;
- mysql> flush privileges;
- select user,host,grant_priv,password_last_changed,authentication_string from mysql.user;
- show master status \G;
- show slave hosts;
- select @@hostname,@@server_id,@@server_uuid;
- mysql -uroot -proot -h192.168.1.54 -P33268
- change master to
- master_host='172.72.0.10',
- master_port=3306,master_user='repl',
- master_password='root',
- master_auto_position=1 FOR CHANNEL 'Master1';
- show slave status \G;
- -- 启动所有 SLAVE
- mysql> START SLAVE;
- --主库创建数据测试
- mysql -uroot -proot -h192.168.1.54 -P33265
- mysql> create database test;
- --主库2和3
- change master to
- master_host='172.72.0.11',
- master_port=3306,
- master_user='repl',
- master_password='root',
- master_auto_position=1 FOR CHANNEL 'Master2';
- change master to
- master_host='172.72.0.12',
- master_port=3306,
- master_user='repl',
- master_password='root',
- master_auto_position=1 FOR CHANNEL 'Master3';
- -- 也可以单独启动需要同步的通道
- START SLAVE FOR CHANNEL 'master2';
- START SLAVE FOR CHANNEL 'master3';
- select a.master_log_pos,a.host,a.user_name,a.user_password,a.port,a.uuid,a.channel_name
- from mysql.slave_master_info a;
- -- mysql -uroot -proot -h192.168.1.54 -P33265
- create database master1;
- use master1;
- CREATE TABLE `test1` (`id` int(11) DEFAULT NULL,`count` int(11) DEFAULT NULL);
- insert into test1 values(1,1);
- -- mysql -uroot -proot -h192.168.1.54 -P33266
- create database master2;
- use master2;
- CREATE TABLE `test2` (`id` int(11) DEFAULT NULL,`count` int(11) DEFAULT NULL);
- insert into test2 values(2,2);
- -- mysql -uroot -proot -h192.168.1.54 -P33267
- create database master3;
- use master3;
- CREATE TABLE `test3` (`id` int(11) DEFAULT NULL,`count` int(11) DEFAULT NULL);
- insert into test3 values(3,3);
- --从库查询
- -- mysql -uroot -proot -h192.168.1.54 -P33268
- show databases;
- SELECT * FROM master1.test1;
- SELECT * FROM master2.test2;
- SELECT * FROM master3.test3;
1、初次配置耗时较长,需要将各个 master 的数据 dump 下来,再 source 到 slave 上。
2、需要考虑各 master 数据增长频率,slave 的数据增长频率是这些数据的总和。如果太高,会导致大量的磁盘 IO,造成数据更新延迟,最严重的是会影响正常的查询。
3、如果多个主数据库实例中存在同名的库,则同名库的表都会放到一个库中;
4、如果同名库中的表名相同且结构相同,则数据会合并到一起;如果结构不同,则先建的有效。