文章转载自:http://www.mydlq.club/article/106/
系统环境:
谈起为什么在大多数情况下部署 Mysql 常常使用 Mysql 主从模式进行部署这个问题,本来也去网上搜寻了一些答案,其中原因主要有以下几点:
MySQL 主从复制默认是异步的模式。MySQL增删改操作会全部记录在 Binlog 中,当 slave 节点连接 master 时,会主动从 master 处获取最新的 Binlog 文件。并把 Binlog 存储到本地的 relay log 中,然后去执行 relay log 的更新内容。
在传统的复制里面,当发生故障,需要主从切换,需要找到 Binlog 和 位点信息,恢复完成数据之后将主节点指向新的主节点。在 MySQL 5.6 里面,提供了新的数据恢复思路,只需要知道主节点的 IP、端口以及账号密码就行,因为复制是自动的,MySQL 会通过内部机制 GTID 自动找点同步。
接下来我们要部署的主从是基于GTID 复制模式。
GTID 是什么
GTID 指的是全局事务 ID,全程是 Global Transaction Identifier,在整个事务流程中每一个事务 ID 是全局唯一的,且在整个主从复制架构中该 ID 都不会相同。
GTID 主从复制方式
基于 GTID 的主从复制方式的出现,主要是用于替换传统的 日志点 复制方式。通过 GTID 可以保证每个主库提交的事务在集群中都有 唯一 的一个事务 ID。强化了数据库主从的一致性和故障恢复数据的容错能力,在 主库 宕机发生 主从切换 的情况下,GTID 方式可以让其他从库自动找到新主库复制的位置。而且 GTID 可以忽略已经执行过的事务,减少了数据发生错误的概率。
GTID 的组成
GTID 由 server_uuid + tid 组成,其中:
其组成样式如下:
fb90fba5-60cf-11eb-b5fa-000c295fbc5f:21
GTID 复制工作原理
假设从库开启了 binlog,那么执行流程如下:
GTID 使用中的限制条件
GTID 复制是针对事务来说的,一个事务只对应一个 GTID,好多的限制就在于此。其中主要限制如下:
如何开启 GTID 模式
需要在 Mysql 配置文件中添加下面几条配置:
## 开启 gtid 模式 gtid_mode=on ## 配置不允许任何事务违反 GTID 一致性,用于保证数据一致性 enforce_gtid_consistency=on ## 开启 Binlog 并指定名称(可选) log_bin=binlog ## 从节点从主节点接收到更新且执行,是否将记录存到从节点的 binlog 日志中(可选) log-slave-updates=1 ## 当从数据库启动的时候,从节点不会启动复制(可选) skip-slave-start=1
服务器IP | 角色 | 配置文件目录 | 数据存储目录 |
---|---|---|---|
192.168.2.11 | 主节点 | /apps/mysql | /apps/mysql/data |
192.168.2.12 | 从节点 | /apps/mysql | /apps/mysql/data |
创建 Mysql 的 Docker 镜像的外挂数据存储目录:
这个目录是本人创建的数据存储目录,实际部署需要修改为需要部署应用的服务器的存储目录。
$ mkdir -p /apps/mysql/data
在目录 /apps/mysql 中创建 Mysql 主节点的配置文件 my.cnf,内容如下:
[mysqld] port = 3306 max_connections = 2000 default-time_zone='+8:00' sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION #gtid: server_id = 1 #服务器id gtid_mode = on #开启gtid模式 enforce_gtid_consistency = on #强制gtid一致性,开启后对于特定create table不被支持 #binlog log_bin = mysql-binlog log_slave_updates = on binlog_format = row #强烈建议,其他格式可能造成数据不一致 #relay log skip_slave_start = 1 default_authentication_plugin = 'mysql_native_password' #更改加密方式
MySQL8.0 之前 mysql 密码加密方式为 mysql_native_password,而 MySQL8.0 版本默认新添加的用户密码默认使用的 caching_sha2_password,因此进行使用主从复制时可能会遇到错误,需要将加密方式改成 mysql_native_password。
部署 Mysql 的主节点,执行的 Docker 命令如下:
$ docker run --name mysql-a -d \ --restart=always \ --network=host \ -v /apps/mysql/my.cnf:/etc/mysql/conf.d/my.cnf \ -v /apps/mysql/data:/var/lib/mysql \ -v /etc/localtime:/etc/localtime \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0.23
进入 MySQL 的 Master 容器中,使用客户端工具连接 MySQL Server:
$ docker exec -it mysql-a mysql -uroot -p123456
输入下面命令创建鉴权用户并赋与权限:
## 创建用户 repl 密码为 123456 $ create user 'repl'@'%' identified by '123456'; ## 赋予用户 repl 权限 $ grant replication slave,replication client on *.* to 'repl'@'%'; ## 刷新权限 $ flush privileges;
$ mkdir -p /apps/mysql/data
在目录 /apps/mysql 中创建 Mysql 从节点的配置文件,内容如下:
[mysqld] port = 3306 max_connections = 2000 default-time_zone = '+8:00' sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION #GTID: server_id = 2 #服务器id gtid_mode = on #开启gtid模式 enforce_gtid_consistency = on #强制gtid一致性,开启后对于特定create table不被支持 #binlog log_bin = mysql-binlog log_slave_updates = on binlog_format = row #强烈建议,其他格式可能造成数据不一致 #relay log skip_slave_start = 1 default_authentication_plugin = 'mysql_native_password' #更改加密方式 read_only = on #设置只读
执行下面 Docker 命令,部署 Mysql 从节点:
$ docker run --name mysql-b -d \ --restart=always \ --network=host \ -e MYSQL_ROOT_PASSWORD=123456 \ -v /apps/mysql/my.cnf:/etc/mysql/conf.d/my.cnf \ -v /apps/mysql/data:/var/lib/mysql \ -v /etc/localtime:/etc/localtime \ mysql:8.0.23
进入 Mysql Slave 镜像内部,使用客户端工具连接该 Msyql Server:
$ docker exec -it mysql-b mysql -uroot -p123456
配置从库连接主库:
$ CHANGE MASTER TO master_host='192.168.2.11', master_port=3306, master_user='repl', master_password='123456', master_auto_position=1;
注:master_host 需要改为你的主节点 IP 地址,用户名密码要和上面创建的用户密码一致。
启动从库:
$ start slave;
查看连接状态:
$ show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.2.11 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-binlog.000003 Read_Master_Log_Pos: 886 Relay_Log_File: node-02-relay-bin.000003 Relay_Log_Pos: 1107 Relay_Master_Log_File: mysql-binlog.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: 886 Relay_Log_Space: 3129553 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: f5c69d56-694c-11eb-800e-000c29e6fc4e 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: f5c69d56-694c-11eb-800e-000c29e6fc4e:1-8 Executed_Gtid_Set: 13f0092c-694d-11eb-aba6-000c29262359:1-5, f5c69d56-694c-11eb-800e-000c29e6fc4e:1-8 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: Master_public_key_path: Get_master_public_key: 0 Network_Namespace:
在主节点服务器上执行下面命令,进入 mysql 客户端:
$ docker exec -it mysql-master mysql -uroot -p123456
然后执行下面命令创建测试库、表并插入测试数据:
##创建名为 test 的数据库 $ CREATE DATABASE test; ##使用 test 数据库 $ USE test; ##创建 user 表 $ CREATE TABLE `user` ( `id` int(0) NOT NULL, `name` varchar(20) NULL DEFAULT NULL ); ##插入测试数据 $ INSERT INTO `user` VALUES (1, 'mydlq');
在从节点服务器上执行下面命令,进入 mysql 客户端:
$ docker exec -it mysql-slave mysql -uroot -p123456
然后执行下面命令
##查看全部数据库 $ SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | +--------------------+ ##使用 test 数据库 $ USE test; ##查看全部表 $ SHOW TABLES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | +--------------------+ ## 查看 user 表中数据 $ SELECT * FROM `user`; +----+-------+ | id | name | +----+-------+ | 1 | mydlq | +----+-------+
如果从库中能正常执行上面命令且存在测试数据,则证明主从配置没有问题。