本文基于MySQL5.7.32版本撰写!!!
所有操作都是在关闭防火墙和SELinux情况下实现的!!!
MySQL数据库自身提供的主从复制功能可以方便的实现数据的多处自动备份,实现数据库的拓展。多个数据备份不仅可以加强数据的安全性,通过实现读写分离还能进一步提升数据库的负载性能。
一、主从复制简介
- 基于二进制日志恢复的;
- 主库的修改操作记录会记录二进制日志;
- 从库会请求新的二进制日志并回放,最终达到主从数据同步;
- 主从复制核心功能:辅助备份,处理物理损坏;
二、搭建主从复制的过程
1)至少两台mysql实例,server_id,server_uuid不同;
2)主库开启二进制日志功能;
3)创建专用的复制用户;
4)保证主从开启之前的某个时间点,从库数据和主库是一致的;
5)告知从库,复制user、password、IP、Port以及复制的起点;
6)从库开启从库模式(start slave);
7)确认线程:主库(dump thread)、从库(ID thread、SQL thread);
三、多个数据库间主从复制与读写分离
在一主多从的数据库体系中,多个从服务器采用异步的方式更新主数据库的变化,业务服务器在执行写或者相关修改数据库的操作是在主服务器上进行的,读操作则是在各从服务器上进行。如果配置了多个从服务器或者多个主服务器又涉及到相应的负载均衡问题,关于负载均衡具体的技术细节还没有研究过,今天就先简单的实现一主一从的主从复制功能。
四、Mysql主从复制的实现原理图
MySQL之间数据复制的基础是二进制日志文件(binary log file)。一台MySQL数据库一旦启用二进制日志后,其作为master,它的数据库中所有操作都会以“事件”的方式记录在二进制日志中,其他数据库作为slave通过一个I/O线程与主服务器保持通信,并监控master的二进制日志文件的变化,如果发现master二进制日志文件发生变化,则会把变化复制到自己的中继日志中,然后slave的一个SQL线程会把相关的“事件”执行到自己的数据库中,以此实现从数据库和主数据库的一致性,也就实现了主从复制
五、主从复制搭建过程
环境:
主机名 | ip |
---|---|
db-master(主) | 192.168.1.20 |
db-slave(从) | 192.168.1.40 |
1.修改MySQL的配置文件
主库:(192.168.1.20)
[root@mysql ~]# hostnamectl set-hostname db-master
[root@mysql ~]# bash
[root@db-master ~]# vim /etc/my.cnf
......
server_id=1 #指定server—_id,注意server_id是唯一的
log_bin=/usr/local/mysql/data/mysql-bin #开启二进制日志功能,并指定日志存放路径及日志名称前缀
[root@db-master ~]# systemctl restart mysqld.service
从库:(192.168.1.40)
[root@mysql ~]# hostnamectl set-hostname db-slave
[root@mysql ~]# bash
[root@db-slave ~]# vim /etc/my.cnf
server_id=2 #切记不可和主库进行冲突
relay_log = /usr/local/mysql/data/relay-bin #开启中继日志
relay_log_index=/usr/local/mysql/data/db-slave-relay-bin.index #指定中继日志位置
[root@db-slave ~]# systemctl restart mysqld.service
查看日志是否开启
主库二进制日志
mysql> show variables like '%log%';
...... |
| log_bin | ON |
| log_bin_basename | /usr/local/mysql/data/mysql-bin |
| log_bin_index | /usr/local/mysql/data/mysql-bin.index |
......
从库中继日志
mysql> show variables like '%log%';
......
| relay_log | /usr/local/mysql/data/relay-bin |
| relay_log_basename | /usr/local/mysql/data/relay-bin |
| relay_log_index | /usr/local/mysql/data/db-slave-relay-bin.index |
......
2.创建主从复制通信的用户账号
主库:(192.168.1.20)
mysql> grant replication slave on *.* to test@'192.168.1.%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.01 sec)
3.备份主库并恢复到从库
主库:(192.168.1.20)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
| test1 |
| test2 |
| test3 |
| test4 |
+--------------------+
9 rows in set (0.00 sec)
mysql> quit
Bye
[root@db-master ~]# mysqldump -uroot -p123456 -A > /tmp/all.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
[root@db-master ~]# scp /tmp/all.sql [email protected]:/root/
......
all.sql 100% 853KB 48.3MB/s 00:00
从库:(192.168.1.40)
[root@db-slave ~]# mysql -uroot -p123456 < /root/all.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
[root@db-slave ~]# mysql -uroot -p123456 -e 'show databases'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
| test1 |
| test2 |
| test3 |
| test4 |
+--------------------+
4.告知从库复制信息并开启专用线程
从库:(192.168.1.40)
[root@db-slave ~]# mysql -uroot -p123456
......
mysql> change master to
-> master_host='192.168.1.20', #主库deIP
-> master_user='test', #专用主从复制的用户名
-> master_password='123456', #专用用户对应的密码
-> master_port=3306, #主库数据库监听的端口
-> master_log_file='mysql-bin.000001', #同步主库的日志文件
-> master_log_pos=1259, #日志中的起点位置
-> master_connect_retry=5; #如果连接失败重试次数
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave; #开启从库专用线程
Query OK, 0 rows affected (0.00 sec)
检查线程状态
mysql> show slave status\G
*************************** 1. row ***************************
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
#确保以上俩行为yes则线程状态正确!!!
......
Master_UUID: da5a57f4-2a70-11eb-8c2a-000c29956e64
Master_Info_File: /usr/local/mysql/data/master.info
......
1 row in set (0.00 sec)
PS:如果Slave_IO_Running:NO解决方法
在主从任意一台服务器上执行PS:显示为nO的原因是因为服务器的uuid相同了!!!!
[root@db-slave data]# pwd
/usr/local/mysql/data
[root@db-slave data]# ll
总用量 123004
-rw-r-----. 1 mysql mysql 56 2月 23 15:35 auto.cnf
[root@db-slave data]# rm -rf auto.cnf #删除一下
[root@db-slave data]# systemctl restart mysqld.service
查看线程列表
主库:(192.168.1.20)
mysql> show processlist;
+----+------+--------------------+------+-------------+------+---------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+--------------------+------+-------------+------+---------------------------------------------------------------+------------------+
| 7 | test | 192.168.1.40:32914 | NULL | Binlog Dump | 1008 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 8 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+------+--------------------+------+-------------+------+---------------------------------------------------------------+------------------+
2 rows in set (0.00 sec)
#每个从库都会有一行dump相关的信息
#如果显示非以上信息,说明主从之间的关系出现了问题
#显示的两行信息,第一行是从库,第二行是主库信息
从库:(192.168.1.40)
5.验证主从复制
主库:(192.168.1.20)
mysql> create database qq;
Query OK, 1 row affected (0.09 sec)
mysql> use qq;
Database changed
mysql> create table t1 (
-> id int,
-> name varchar(20));
Query OK, 0 rows affected (0.11 sec)
mysql> insert into t1 values(1,'wangwu'),(2,'zhangsan');
Query OK, 2 rows affected (0.09 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t1;
+------+----------+
| id | name |
+------+----------+
| 1 | wangwu |
| 2 | zhangsan |
+------+----------+
2 rows in set (0.00 sec)
从库:(192.168.1.40)
mysql> select * from qq.t1;
+------+----------+
| id | name |
+------+----------+
| 1 | wangwu |
| 2 | zhangsan |
+------+----------+
2 rows in set (0.00 sec)
至此之上MySQL主从复制搭建完成!!!!
六、基于SSL的主从复制
主机 | IP |
---|---|
master | 192.168.1.20 |
slave | 192.168.1.40 |
1.创建 SSL/RSA 文件
主(192.168.1.20)
[root@master ~]# cd /usr/local/mysql/bin/
#创建新的SSL文件
[root@master bin]# mysql_ssl_rsa_setup --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
#赋予R权限
[root@master bin]# ls /usr/local/mysql/data/server-key.pem -l
-rw------- 1 mysql mysql 1676 11月 19 22:09 /usr/local/mysql/data/server-key.pem
[root@master bin]# chmod +r /usr/local/mysql/data/server-key.pem
[root@master bin]# ls /usr/local/mysql/data/server-key.pem -l
-rw-r--r-- 1 mysql mysql 1676 11月 19 22:09 /usr/local/mysql/data/server-key.pem
[root@master bin]# systemctl restart mysqld.service
#查看是否支持ssl安全连接
mysql> show variables like '%ssl%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| have_openssl | YES |
| have_ssl | YES |
| ssl_ca | ca.pem |
| ssl_capath | |
| ssl_cert | server-cert.pem |
| ssl_cipher | |
| ssl_crl | |
| ssl_crlpath | |
| ssl_key | server-key.pem |
+---------------+-----------------+
9 rows in set (0.00 sec)
PS:以上操作完成了主服务器支持SSL安全连接!!!
2.创建专用账号
主(192.168.1.20)
mysql> grant replication slave on *.* to test@'192.168.1.%' identified by '123456' require ssl;
Query OK, 0 rows affected, 1 warning (0.00 sec)
3.修改配置文件
主(192.168.1.20)
[root@master bin]# vim /etc/my.cnf
[root@master bin]# tail -2 /etc/my.cnf #添加
server-id = 1
log-bin=mysql-bin
[root@master bin]# systemctl restart mysqld.service
[root@master bin]# mysql -uroot -p123456
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
#以上反馈的 file 和 position 的值要记住,配置从服务器要用到!!!
从(192.168.1.40)
[root@slave ~]# vim /etc/my.cnf
[root@slave ~]# tail -3 /etc/my.cnf
server-id = 2
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
[root@slave ~]# systemctl restart mysqld.service
#查看是否打开中继日志
mysql> show variables like '%log%';
......
| relay_log | relay-log-bin |
| relay_log_basename | /usr/local/mysql/data/relay-log-bin |
| relay_log_index | /usr/local/mysql/data/slave-relay-bin.index |
......
4.从服务器配置证书
#从主服务器吧证书复制到从服务器上!!!
主(192.168.1.20)
[root@master data]# pwd
/usr/local/mysql/data
[root@master data]# scp ca.pem client-key.pem client-cert.pem [email protected]:/usr/local/mysql/data/
The authenticity of host '192.168.1.40 (192.168.1.40)' can't be established.
ECDSA key fingerprint is SHA256:BxEkbMRXK5YMej/alDgQ+Mhlpwj9UlLiSa9clpbXHl8.
ECDSA key fingerprint is MD5:7b:89:c9:54:ea:79:18:bd:c6:4a:d1:0b:1f:6b:d8:f3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.40' (ECDSA) to the list of known hosts.
[email protected]'s password:
ca.pem 100% 1112 1.4MB/s 00:00
client-key.pem 100% 1680 119.1KB/s 00:00
client-cert.pem 100% 1112 79.1KB/s 00:00
从(192.168.1.40)
[root@slave ~]# cd /usr/local/mysql/data/
[root@slave data]# chmod +r client-key.pem
[root@slave data]# ls -l ca.pem client-key.pem client-cert.pem
-rw-r--r--. 1 mysql mysql 1112 2月 26 18:55 ca.pem
-rw-r--r--. 1 mysql mysql 1112 2月 26 18:55 client-cert.pem
-rw-r--r--. 1 mysql mysql 1680 2月 26 18:55 client-key.pem
#添加配置文件
[root@slave data]# vim /etc/my.cnf
[root@slave data]# tail -3 /etc/my.cnf #添加以下三行
ssl-ca = /usr/local/mysql/data/ca.pem
ssl-cert = /usr/local/mysql/data/client-cert.pem
ssl-key = /usr/local/mysql/data/client-key.pem
[root@slave data]# systemctl restart mysqld.service
#查看从服务器是否支持SSL
mysql> show variables like '%ssl%';
+---------------+---------------------------------------+
| Variable_name | Value |
+---------------+---------------------------------------+
| have_openssl | YES |
| have_ssl | YES |
| ssl_ca | /usr/local/mysql/data/ca.pem |
| ssl_capath | |
| ssl_cert | /usr/local/mysql/data/client-cert.pem |
| ssl_cipher | |
| ssl_crl | |
| ssl_crlpath | |
| ssl_key | /usr/local/mysql/data/client-key.pem |
+---------------+---------------------------------------+
9 rows in set (0.00 sec)
5.测试用SSl连接主服务器
从(192.168.1.40)
[root@slave ~]# cd /usr/local/mysql/data/
[root@slave data]# mysql --ssl-ca=ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem -u test -p123456 -h192.168.1.20
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.32-log Source distribution
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
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> \s
--------------
mysql Ver 14.14 Distrib 5.7.32, for linux-glibc2.12 (x86_64) using EditLine wrapper
Connection id: 4
Current database:
Current user: [email protected]
SSL: Cipher in use is DHE-RSA-AES128-GCM-SHA256
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.7.32-log Source distribution
Protocol version: 10
Connection: 192.168.1.20 via TCP/IP #此IP可以看出连接的是主服务器
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
Uptime: 15 min 2 sec
Threads: 2 Questions: 9 Slow queries: 0 Opens: 108 Flush tables: 1 Open tables: 101 Queries per second avg: 0.009
--------------
PS:SSL 测试连接成功,并且登入的 SSL 协议是: Cipher in use is DHE-RSA-AES128-GCM-SHA256
6.配置主从Replicate
从(192.168.1.40)
mysql> change master to
-> master_host='192.168.1.20',
-> master_user='test',
-> master_password='123456',
-> master_log_file='mysql-bin.000001',
-> master_log_pos=154,
-> master_ssl=1,
-> master_ssl_ca='/usr/local/mysql/data/ca.pem',
-> master_ssl_cert='/usr/local/mysql/data/client-cert.pem',
-> master_ssl_key='/usr/local/mysql/data/client-key.pem';
Query OK, 0 rows affected, 2 warnings (0.09 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G
*************************** 1. row ***************************
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
7.测试同步
主(192.168.1.20)
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> use test;
Database changed
mysql> create table t1 (t int,name varchar(20));
Query OK, 0 rows affected (0.16 sec)
mysql> insert into t1 values(1,'zhangsan'),(2,'wangwu');
Query OK, 2 rows affected (0.09 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t1;
+------+----------+
| t | name |
+------+----------+
| 1 | zhangsan |
| 2 | wangwu |
+------+----------+
2 rows in set (0.00 sec)
从(192.168.1.40)
mysql> select * from test.t1;
+------+----------+
| t | name |
+------+----------+
| 1 | zhangsan |
| 2 | wangwu |
+------+----------+
2 rows in set (0.00 sec)
以上为同步成功。
总结:
SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。复制默认是明文进行传输的,通过SSL 加密可以大大提高数据的安全性。
七、基于GTID的主从复制
GTID知识:https://www.hi-linux.com/posts/47176.html
主机 | IP |
---|---|
master | 192.168.1.20 |
slave | 192.168.1.40 |
1.修改配置文件
主(192.168.1.20)
[root@master ~]# vim /etc/my.cnf
[root@master ~]# tail -4 /etc/my.cnf
server-id = 1
log-bin = mysql-bin
gtid-mode = ON
enforce-gtid-consistency = True
[root@master ~]# systemctl restart mysqld.service
从(192.168.1.40)
[root@slave ~]# vim /etc/my.cnf
[root@slave ~]# tail -5 /etc/my.cnf
server-id = 2
relay-log = relay-log-bin
relay-log-index = slave-relay-bin.index
gtid-mode = ON
enforce-gtid-consistency = True
[root@slave ~]# systemctl restart mysqld.service
2.创建专用账户
mysql> grant replication slave on *.* to test@'192.168.1.%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)
3.配置主从
从(192.168.1.40)
mysql> change master to
-> master_host='192.168.1.20',
-> master_user='test',
-> master_password='123456',
-> master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
4.查看主从服务器的状态
主(192.168.1.20)
mysql> show master status;
+------------------+----------+--------------+------------------+----------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+----------------------------------------+
| mysql-bin.000001 | 447 | | | da5a57f4-2a70-11eb-8c2a-000c29956e64:1 |
+------------------+----------+--------------+------------------+----------------------------------------+
1 row in set (0.00 sec)
从(192.168.1.40)
mysql> show slave status\G
*************************** 1. row ***************************
......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
Retrieved_Gtid_Set: da5a57f4-2a70-11eb-8c2a-000c29956e64:1
Executed_Gtid_Set: da5a57f4-2a70-11eb-8c2a-000c29956e64:1
Auto_Position: 1
......
#从库上的GTID号与主库上的GTID号保持一致,表示同步没有问题
5.测试同步
主(192.168.1.20)
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> use test;
Database changed
mysql> create table t1 (t int,name varchar(20));
Query OK, 0 rows affected (0.10 sec)
mysql> insert into t1 values(1,'zhangsan'),(2,'wangwu');
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t1;
+------+----------+
| t | name |
+------+----------+
| 1 | zhangsan |
| 2 | wangwu |
+------+----------+
2 rows in set (0.00 sec)
从(192.168.1.40)
mysql> select * from test.t1;
+------+----------+
| t | name |
+------+----------+
| 1 | zhangsan |
| 2 | wangwu |
+------+----------+
2 rows in set (0.00 sec)
GTID主从搭建完成!!!
6.GTID 复制和普通复制的区别
#配置区别
#普通复制配置
CHANGE MASTER TO
MASTER_HOST='192.168.1.1',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_PORT=3307,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=444,
MASTER_CONNECT_RETRY=10;
#GTID配置
change master to
master_host='192.168.1.1',
master_user='repl',
master_password='123' ,
MASTER_AUTO_POSITION=1;
1)在主从复制环境中,主库发生过的事务,在全局都是由唯一GTID记录的,更方便Failover
2)额外功能参数(3个)
3)change master to 的时候不再需要binlog 文件名和position号,MASTER_AUTO_POSITION=1;
4)在复制过程中,从库不再依赖master.info文件,而是直接读取最后一个relaylog的 GTID号
5) mysqldump备份时,默认会将备份中包含的事务操作,以以下方式SET @@GLOBAL.GTID_PURGED='8c49d7ec-7e78-11e8-9638-000c29ca725d:1';告诉从库,我的备份中已经有以上事务,你就不用运行了,直接从下一个GTID开始请求binlog就行。
HOST=‘192.168.1.1’,
MASTER_USER=‘repl’,
MASTER_PASSWORD=‘123’,
MASTER_PORT=3307,
MASTER_LOG_FILE=‘mysql-bin.000001’,
MASTER_LOG_POS=444,
MASTER_CONNECT_RETRY=10;
#GTID配置
change master to
master_host=‘192.168.1.1’,
master_user=‘repl’,
master_password=‘123’ ,
MASTER_AUTO_POSITION=1;
1)在主从复制环境中,主库发生过的事务,在全局都是由唯一GTID记录的,更方便Failover
2)额外功能参数(3个)
3)change master to 的时候不再需要binlog 文件名和position号,MASTER_AUTO_POSITION=1;
4)在复制过程中,从库不再依赖master.info文件,而是直接读取最后一个relaylog的 GTID号
5) mysqldump备份时,默认会将备份中包含的事务操作,以以下方式SET @@GLOBAL.GTID_PURGED=‘8c49d7ec-7e78-11e8-9638-000c29ca725d:1’;告诉从库,我的备份中已经有以上事务,你就不用运行了,直接从下一个GTID开始请求binlog就行。