github学习笔记
mysql 中的主从复制
1. 主从复制的介绍
/*
主从复制至少需要两台服务器,一台作为主库,一台作为从库.
主库: Master
从库: Slave
1) MySQL 的主从复制又叫 Replication、AB 复制。至少需要两个 MySQL 服务(可以是同一台机器,也可以是不同机器之间进行)。
比如A服务器做主服务器,B服务器做从服务器,在A服务器上进行数据的更新,通过 binlog 日志记录同步到B服务器上,并重新执行(也叫重做)同步过来的 binlog 数据,从而达到两台服务器数据一致。
2) MySQL 数据库的主从复制方案,与使用 scp/rsync 等命令进行的文件级别复制类似,都是数据的远程传输。
只不过 MySQL 的主从复制是其自带的功能,无需借助第三方工具,而且MySQL的主从复制并不是数据库磁盘上的文件直接拷贝,而是通过逻辑的 binlog 日志复制到要同步的服务器本地,然后由本地的线程读取日志里面的 SQL 语句,重新应用到 MySQL 数据库中。
3) mysql 支持一台主库同时向多态从库复制,从库也可以同时作为其他从服务器的主库,形成一个链式结构.
作用:
1. 可以实时灾备,用于故障切换(主库出现问题,可以快速切换到从库提供服务)
2. 读写分离,提供查询服务,实现负载均衡(降低主库的访问压力)
3. 数据热备,避免影响业务(在从库中执行数据备份,不影响主库提供服务)
*/
2. 主从复制的原理
/*
主从复制主要有三步,其中和前边所讲的bin log 有关:
1) Master 主库在事务提交时,会将数据变更记录到binlog中;
2) Slave 从库会有一个IOThread的线程定时读取Master的binlog,写入到Slave从库的中继日Relay log中;
3) Slave 会有一个SQLThread的线程对中继日志(Relay log)进行重做,从而改变自己的数据,使主从数据一致;
*/
主从复制原理图
3. 主从复制的搭建流程
/*
1) 服务器的准备,关闭防火墙或者开放指定端口,保证服务器mysql正常运行(可以使用 'systemctl status msyqld' 查看)
准备好服务器,至少需要两台,开放服务器端口
A) firewall-cmd --zone=public --add-port=3306/tcp -premanent
B) firewall-cmd reload
or
A) systemctl stop firewalld
B) systemctl disable firewalld
2) 修改服务器的配置文件
/etc/my.con
[mysqld]
server-id = 1
# 1 代表只读,0代表读写
read-only=0
#要生成二进制日志文件 主服务器一定要开启
log-bin = mysql-bin
3) 创建访问用户
*/
# 1 创建用户
mysql> create user '$username'@'%' identified by '$password';
# 2 设置用户权限
mysql> grant replication slave,replication client on *.* to '$username'@'%';
# 3 刷新权限
mysql> flush privileges;
# 4 查看用户权限
mysql> show grants for '$username'@'%';
/*
4) 开启主从同步
*/
# 从库关联主库
mysql> change master to master_host='$master_host',master_user='$master_user',master_password='$master_password',master_log_file='$bin_log_file',master_log_pos=$bin_log_index;
# 启动主从复制
mysql> start slave;
# 查看从库状态
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.0.2
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 769
Relay_Log_File: f2229f66966b-relay-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000001
-- 这两个参数正常表示主从服务正常
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.....
下面使用docker创建主从服务
- Master
# Master
# 创建Master容器配置
# 创建宿主机挂载配置目录
[root@iZ2ze58f53sxjm9z7mgn5xZ ~]# mkdir mysql_test
[root@iZ2ze58f53sxjm9z7mgn5xZ ~]# cd mysql_test/
[root@iZ2ze58f53sxjm9z7mgn5xZ mysql_test]# mkdir -p master/conf master/data master/logs
# 指定镜像版本启动docker容器
[root@iZ2ze58f53sxjm9z7mgn5xZ mysql_test]# docker run --name mysql-master -p 3310:3306 -v /root/mysql_test/master/conf:/etc/mysql/conf.d -v /root/mysql_test/master/data:/var/lib/mysql -v /root/mysql_test/master/logs:/var/log/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
# 查看docker容器是否可以进入mysql
[root@iZ2ze58f53sxjm9z7mgn5xZ mysql_test]# docker exec -it mysql-master bash
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
bash-4.2# mysql -uroot -p123456
# --------配置/etc/mysql/conf.d/my.cnf,没有创建一个--------------
[mysqld]
server-id = 1
# 1 代表只读,0代表读写
read-only=0
#要生成二进制日志文件 主服务器一定要开启
log-bin = mysql-bin
# 指定同步的数据库,不指定则全部同步
# binlog-do-db=$db_name
# 如果从数据库有写入操作,也需要更新binlog
# log-slave-updates
# 配置文件修改完成重新启动mysql
[root@iZ2ze58f53sxjm9z7mgn5xZ mysql_test]# docker restart mysql-master
# ------------创建主服务器复制用户及相关权限-------------------
# 1 创建用户
mysql> create user 'slave'@'%' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
# 2 设置用户权限
mysql> grant replication slave,replication client on *.* to 'slave'@'%';
Query OK, 0 rows affected (0.00 sec)
# 3 刷新权限
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
# 4 查看用户权限
mysql> show grants for 'slave'@'%';
+-------------------------------------------------------------------+
| Grants for slave@% |
+-------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%' |
+-------------------------------------------------------------------+
1 row in set (0.00 sec)
#--------------------查看master对应的ip,slave会用到------------------------------------
[root@iZ2ze58f53sxjm9z7mgn5xZ ~]# docker inspect mysql-master
....
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "898ecd79eef9bfbc6fbe347f72da2784ccdfff92998af06a464601391d75bec2",
"EndpointID": "8ce221372a3c9e697c42cdecbbb4fe50c24b067b45c17204af6756c3204058ee",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",# 地址
....
- Slave
# Slave
# 创建挂载目录
[root@iZ2ze58f53sxjm9z7mgn5xZ ~]# cd mysql_test/
[root@iZ2ze58f53sxjm9z7mgn5xZ mysql_test]# mkdir -p slave/data slave/conf slave/logs
# 创建slave从库容器
[root@iZ2ze58f53sxjm9z7mgn5xZ mysql_test]# docker run --name mysql-slave -p 3333:3306 -v /root/mysql_test/slave/conf:/etc/mysql/conf.d -v /root/mysql_test/slave/data:/var/lib/mysql -v /root/mysql_test/slave/logs:/var/log/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
# 查看是否可以正常进入容器,如果启动失败,可以查看使用docker logs -f $container_name日志原因
[root@iZ2ze58f53sxjm9z7mgn5xZ mysql_test]# docker exec -it mysql-slave bash
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
bash-4.2# mysql -uroot -p123456
# --------配置/etc/mysql/conf.d/my.cnf,没有创建一个--------------
[mysqld]
server-id = 2
#要生成二进制日志文件 主服务器一定要开启
log-bin = mysql-bin
[root@iZ2ze58f53sxjm9z7mgn5xZ mysql_test]# docker restart mysql-slave bash
# 关联主从库
mysql> change master to master_host='172.17.0.2',master_user='slave',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=769;
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_State: Waiting for master to send event
Master_Host: 172.17.0.2
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 769
Relay_Log_File: f2229f66966b-relay-bin.000002
Relay_Log_Pos: 320
.....
4. 主从复制测试
Master
-- 查询原有的数据
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)
-- 创建一个数据库
mysql> create database my_test;
Query OK, 1 row affected (0.00 sec)
-- 创建成功
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| my_test |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
Slave
-- 查看从库的原本数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)
-- master创建成功之后查看,成功同步过来
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| my_test |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
5. 切换主从
/*
1) SHOW PROCESSLIST; 检查slave是否已经应用完从Master读取过来的在relay log中的操作,如果未应用完不能stop slave,否则会造成数据会有丢失
*/
mysql> SHOW PROCESSLIST;
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| 5 | root | localhost | NULL | Query | 0 | starting | SHOW PROCESSLIST |
| 6 | system user | | NULL | Connect | 152 | Waiting for master to send event | NULL |
| 7 | system user | | NULL | Connect | 152 | Slave has read all relay log; waiting for more updates | NULL |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
3 rows in set (0.00 sec)
-- 停止slave
mysql> stop slave;
-- 重新reset slave 为master
mysql> reset master;
-- 将其他slave的master设置为当前服务结点
-- 停止其他的slave
mysql> stop slave;
-- 更改关联
mysq> change master to ...
6. 主从集群中的错误
/*
1) Error 'Character set '#255' is not a compiled character set and is not specified in the '/usr/share/mysql/charsets/Index.xml' file' on query. Default database: 'my_test'. Query: 'DROP TABLE `t` /* generated by server *\/'
该错误可能是从库的数据库版本比主库,导致复制过来的binlog解析不成功
*/
/*
2) Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction 'ANONYMOUS' at master log mysql-bin.000001, end_log_pos 1269. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any.
复制过来的binlog在主库中找不到记录,也就是最后关联设置的master_log_pos太靠前了,然后执行删除或者什么其他操作,导致找不到对应需要同步的数据
*/