一个应用系统是否高可用,整个系统的效率是否满足预期,往往受到多方面的制约因素,例如:运行环境,网络环境以及数据的吞吐量等;作为一般的大型应用系统来说,我们想要提升整个系统的效率,我们大多数情况下会从我们的后端数据库做优化,从而提高我们整个系统的数据吞吐量,如果我们后端采用的是关系型数据,我们可能会想到两种解决方案,一种是更换非关系型数据库,这种方案代价比较昂贵,它会涉及到数据的迁移,以及程序代码的修改;另一种是通过数据库集群的方式,来横向和纵向扩展我们的数据库,这种方案容易实现并且程序代码修改量比较小;
根据MySQL的官方文档介绍,MySQL支持读写分离的集群配置,并且MySQL提供两种类型的读写分离数据复制类型;一种是二进制日志文件方式的数据复制,另一种是Global Transaction Identifiers (GTIDs)。
下面我们通过一个小实验来看看MySQL数据基于二进制日志数据复制方式的主从集群是如何实现的。
OS环境:CentOS7
软件环境:Docker(最新版),MySQL:latest镜像
我们通过Docker容器快速的构建两个MySQL数据库服务器
docker pull mysql
[root@dev01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest 62a9f311b99c 4 weeks ago 445MB
- 1.
- 2.
- 3.
- 4.
可以看到我们已经拉取到最新的MySQL Docker容器,为了在本地环境中启动两个不同的MySQL Docker容器,我们需要通过修改容器的配置文件的方式来改变MySQL的配置;
首先,我们修改MySQL Master(主数据库)的容器配置文件:
一,创建Master数据库的配置文件
vi master.cnf
[mysqld]
# master server id
server-id = 1
# bin log
log_bin = mysql-master-bin
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- server-id,在MySQL集群数据库中,这个参数必须唯一
- log_bin,MySQL采用二进制日志文件复制的文件名
二,将该配置文件拷贝到MySQL Docker容器中
docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql
docker cp master.cnf fdb98bbd52b6:/etc/mysql/conf.d
- 1.
- 2.
三,提交修改后的Docker容器
docker commit -m "add master configure file" fdb98bbd52b6 mysql:master
[root@dev01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql master 345465966cb5 3 hours ago 445MB
- 1.
- 2.
- 3.
- 4.
- commit -m是修改容器后提交的信息,类似Git提交;
- fdb98bbd52b6是刚才修改的容器;
- mysql:master是我们为修改后的容器打上tag标签master
接下来我们修改MySQL Slave(从数据库)的容器配置文件
一,创建Slave数据库的配置文件
vi slave.cnf
[mysqld]
# slave server id
server-id = 2
# bin log
log_bin = mysql-slave-bin
relay_log = mysql-relay-bin
log_slave_updates = 1
read_only = 1
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- server-id为从数据库的ID,该参数在MySQL集群中必须保持唯一性;
- log_bin如果slave为其它slave的master,必须设置bin_log,在这里我们暂时开启;
- relay_log配置中继日志
- log_slave_updates表示slave将复制事件写进自己的二进制日志(后面会看到它的用处);
- read_only尽量使用read_only,它防止改变数据(除了特殊的线程);
二,将配置文件拷贝到容器中
docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql
docker cp slave.cnf 8ee82abb2e91:/etc/mysql/conf.d
- 1.
- 2.
三,提交修改后的Docker容器
docker commit -m "add slave configure file" 8ee82abb2e91 mysql:slave
[root@dev01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql slave 3a53cd39ee45 4 hours ago 445MB
- 1.
- 2.
- 3.
- 4.
到此,所需要的两个MySQL容器已经修改完毕,并且保存在我们本地的容器仓库中,接下来我们开始启动刚才修改的两个容器进行后续的配置
一,启动Master数据库
docker run --name master -e MYSQL_ROOT_PASSWORD=root -d mysql:master
- 1.
- --name master是我们为启动的容器名;
- mysql:master是我们刚才修改后并且提交到本地的Docker镜像
- 默认数据库root的密码设置为root
二,启动Slave数据库
docker run --link master:master --name slave -e MYSQL_ROOT_PASSWORD=root -d mysql:slave
- 1.
- 为了master容器与slave容器的网络互通,我们添加了--line选项来连接到我们刚才启动的名为master容器;
- --name slave是我们为启动的容器名;
- mysql:slave是我们刚才修改后并且提交到本地的Docker镜像;
- 默认数据库root的密码设置为root
三,进入master容器中通过mysql命令进入数据库
docker exec -it master /bin/bash
mysql -u root -proot
- 1.
- 2.
四,在master数据库中创建用于复制数据的账号,并且给该账号相应的权限
create user 'repl'@'%' identified by 'repl-pwd';
grant replication slave on *.* to 'repl'@'%';
flush privileges;
- 1.
- 2.
- 3.
五,查看master数据库的状态
mysql> show master status;
+-------------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------------+----------+--------------+------------------+-------------------+
| mysql-master-bin.000003 | 2743 | | | |
+-------------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
六,进入slave容器中通过mysql命令进入数据库
docker exec -it slave /bin/bash
mysql -u root -proot
- 1.
- 2.
七,配置slave,将master数据库指向刚才配置好的master数据库节点,并且启动slave
change master to master_host='master', master_user='repl', master_password='repl-pwd', master_log_file='mysql-master-bin.000003', master_log_pos=0;
start slave;
- 1.
- 2.
八,查看slave数据库状态
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: master
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-master-bin.000003
Read_Master_Log_Pos: 4
Relay_Log_File: mysql-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mysql-master-bin.000003
Slave_IO_Running: No
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 4
Relay_Log_Space: 155
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 2061
Last_IO_Error: error connecting to master 'repl@master:3306' - retry-time: 60 retries: 1 message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 0
Master_UUID:
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State:
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp: 190912 06:06:14
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
由于最新版的MySQL为了提升安全性更改了密码校验插件,在这里我们还是采用之前的密码校验插件,我们在master数据库上用如下的命令来修改刚才在master数据库创建的用户
alter user 'repl'@'%' identified by 'repl-pwd' password expire never;
alter user 'repl'@'%' identified with mysql_native_password by 'repl-pwd';
flush privileges;
- 1.
- 2.
- 3.
九,再次查看slave状态
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: master
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-master-bin.000003
Read_Master_Log_Pos: 2743
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 2971
Relay_Master_Log_File: mysql-master-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 2743
Relay_Log_Space: 3179
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: f6e8062e-d521-11e9-9009-0242ac110008
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
我们主要查看Slave_IO_Running和Slave_SQL_Running,表示我们的slave数据库节点已经成功的连接到了我们的master数据库节点。
十,验证,我们在master数据库节点上创建一个空的数据库
mysql> create database data;
Query OK, 1 row affected (0.10 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| data |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
十一,验证slave,查看刚才在master数据库节点上创建的数据库是否同步到slave数据节点
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| data |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
可以看到,我们刚才在master数据库节点上创建的数据库已经同步到我们的slave数据库节点,master和slave的数据库数据已经保持一致。
以上实验我们选取了两个数据库(一主一从)的方式,在实际的应用中我们会根据我们的应用场景,slave数据库节点也有可能被选择作为主数据库,这个时候slave数据库节点就有可能是1到N个。
参考:
https://dev.mysql.com/doc/refman/5.7/en/replication.html