一、主从复制
-
https://dev.mysql.com/doc/refman/5.7/en/replication-howto.html
-
slave向master认证
-
master向slave发送二进制日志
-
slave端IO线程将master发送来的日志写入本地,slave端SQL线程用于变更本地数据库
-
影响IO线程正常工作的原因:
-
- master端防火墙
-
- 执行CHANGE MASTER时的信息在master端是否可用?
-
影响SQL线程正常工作的原因:
-
- 原本的主从数据不一致
-
slave端SQL线程单线程写入,相比IO线程较慢,怎么解决?
-
slave端IO线程是异步处理的,怎么解决同步问题?
1.打开GTID功能
- https://dev.mysql.com/doc/refman/5.7/en/replication-gtids.html
- 这样每次重启机器后,slave不需要再知道具体的master的日志id
- gtid会自动增加,slave端根据gtid来进行同步
- slave自动找拥有最近gtid的主机作为master
# master端
[mysqld]
basedir=/usr/local/mysql
datadir=/data/mysql
socket=/data/mysql/mysql.sock
log-bin=mysql-bin
server-id=1
gtid_mode=ON
enforce-gtid-consistency=ON
# slave端
[mysqld]
basedir=/usr/local/mysql
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=2
gtid_mode=ON
enforce-gtid-consistency=ON
# 重启mysql,先起master
2.半同步模式
- https://dev.mysql.com/doc/refman/5.7/en/replication-semisync.html
- 无损模式
# master端
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
# slave端
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
# 查看激活状态
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
-> FROM INFORMATION_SCHEMA.PLUGINS
-> WHERE PLUGIN_NAME LIKE '%semi%';
+---------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+---------------------+---------------+
| rpl_semi_sync_slave | ACTIVE |
+---------------------+---------------+
1 row in set (0.00 sec)
# 打开半同步功能(热激活)
## master端
SET GLOBAL rpl_semi_sync_master_enabled = 1;
## slave端
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
# 查看半同步变量
mysql> show variables like 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.01 sec)
# 查看半同步状态
mysql> show status like 'rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
# 重启slave端的IO线程
mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
mysql> START SLAVE IO_THREAD;
Query OK, 0 rows affected (0.01 sec)
mysql> show status like 'rpl_semi_sync%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.01 sec)
# 如果slave端的IO线程挂掉,master端会等待一个超时时间后,切换成异步工作状态
3.延迟复制
mysql> stop slave SQL_THREAD;
Query OK, 0 rows affected (0.00 sec)
mysql> change master to master_delay=10;
Query OK, 0 rows affected (0.00 sec)
mysql> start slave SQL_THREAD;
4.慢查询
mysql> set global slow_query_log=ON;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "long%";
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)
mysql> set long_query_time=5;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "long%";
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 5.000000 |
+-----------------+----------+
1 row in set (0.00 sec)
5.并行SQL写入
- 加速slave端的SQL线程写入
# slave端修改配置文件
[mysqld]
basedir=/usr/local/mysql
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=2
gtid_mode=ON
enforce-gtid-consistency=ON
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON
# 查看slave端的线程
mysql> show processlist;
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| 1 | system user | | NULL | Connect | 53 | Slave has read all relay log; waiting for more updates | NULL |
| 3 | system user | | NULL | Connect | 53 | Waiting for master to send event | NULL |
| 4 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 5 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 6 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 7 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 8 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 9 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 10 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 11 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 12 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 13 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 14 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 15 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 16 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 17 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 18 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 19 | system user | | NULL | Connect | 53 | Waiting for an event from Coordinator | NULL |
| 20 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
19 rows in set (0.00 sec)
二、组复制
- https://dev.mysql.com/doc/refman/5.7/en/group-replication.html
- 仅支持innodb
- 最多支持9个节点为一组
- 每个节点既是主又是从
- 所有节点之间同步,如果一个节点出现故障,则全部回滚
- 组复制需要保证节点之间的原始数据完全相同
第一个节点配置
# 关闭mysqld,清除原data
[root@localhost ~]# /etc/init.d/mysqld stop
[root@localhost ~]# rm -rf /data/mysql/*
[root@localhost ~]# ll /data/mysql/
total 0
# 修改my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/data/mysql
socket=/data/mysql/mysql.sock
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
plugin_load_add='group_replication.so'
transaction_write_set_extraction=XXHASH64
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address= "server1:33061"
group_replication_group_seeds= "server1:33061,server2:33061,server3:33061"
group_replication_bootstrap_group=off
group_replication_single_primary_mode=OFF
group_replication_enforce_update_everywhere_checks=ON
group_replication_ip_whitelist="192.168.147.0/24,127.0.0.1/8"
group_replication_allow_local_disjoint_gtids_join=1
# 重新初始化mysql
[root@localhost ~]# mysqld --initialize --user=mysql
# 进入mysql修改root密码
[root@localhost ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/server1.err'.
SUCCESS!
[root@localhost ~]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.36-log
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> alter user root@localhost identified by 'passwd';
Query OK, 0 rows affected (0.00 sec)
# 创建用于组复制的用户,在此期间关闭二进制日志记录
mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)
# 激活组复制,在初始节点激活组复制时需要开启bootstrap,其他节点不用
mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='password' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.03 sec)
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)
mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected, 1 warning (2.09 sec)
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 1ddadb97-93f0-11ed-9d79-000c299c98e4 | server1 | 3306 | ONLINE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
1 row in set (0.00 sec)
其他节点配置
- 只需要注意修改my.cnf中的部分内容
- 在创建rpl_user需要暂时关闭二进制日志写入(防止数据不一致)
- 开启组复制功能时,不需要再开启bootstrap功能
mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)
mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='password' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected, 1 warning (3.28 sec)
实验效果
# 可以看到各环节都是online状态
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 1ddadb97-93f0-11ed-9d79-000c299c98e4 | server1 | 3306 | ONLINE |
| group_replication_applier | 52d2a816-93f2-11ed-ad4b-000c29ad4e3c | server3 | 3306 | ONLINE |
| group_replication_applier | de36bbfc-93f0-11ed-905c-000c29f090f3 | server2 | 3306 | ONLINE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.00 sec)
# 此时在任意一个节点插入数据,都会被同步到其他节点
三、读写分离
- 使用包mysql-router
- 下载地址:https://cdn.mysql.com/archives/mysql-router/mysql-router-community-8.0.21-1.el7.x86_64.rpm
- 配置文件:/etc/mysqlrouter
[routing:ro] # 配置读路由策略
bind_address=0.0.0.0
bind_port=7001
destinations=192.168.147.138:3306,192.168.147.139:3306,192.168.147.140:3306
routing_strategy=round-robin # 轮询
[routing:rw] # 配置写路由策略
bind_address=0.0.0.0
bind_port=7002
destinations=192.168.147.138:3306,192.168.147.139:3306,192.168.147.140:3306
routing_strategy=round-first-available # 首位可用