文章目录
5.Mycat2实现读写分离
读写分离原理:读写分离就是让主库处理事务性操作,从库处理select查询。数据库复制被用来把事务性查询导致的数据变更同步到从库,同时主库也可以select查询。
实现读写分离是基于MySQL的主从复制架构的,通过一主多从的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。 所以这里我们先要搭建一下MySQL的主从复制集群。
5.1 Docker搭建MySQL主从复制集群
5.1.1 MySQL主从同步原理
MySQL通过binlog完成主备同步,实现最终一致性。
- Mysql 中有一种日志叫做 binlog(二进制日志)。这个日志会记录下所有修改了数据库的SQL 语句(insert,update,delete,create/alter/drop table, grant 等等)
- 主从复制的原理其实就是把主服务器上的 binlog 复制到从服务器上执行一遍,这样从服务器上的数据就和主服务器上的数据相同了。
与主从复制相关的线程有三个
- 主库上的dump_thread
- 备库上的io_thread、sql_thread
与主从复制相关的日志有binlog、relaylog
- binlog: 记录数据库的写入操作,以二进制的形式保存在日志文件;
- relaylog: Slave 接收 Master 的同步日志,会先放到中继日志 relay log 里, slave 的读操作也会基于 relay log。
- master将数据改变记录到
二进制日志(binary log)
中。 - 当slave上执行
start slave
命令之后,slave会创建一个IO 线程
用来连接master,请求master中的binlog。 - 当slave连接master时,master会创建一个 **
binlog dump 线程
,用于发送 binlog 的内容。在读取 binlog 的内容的操作中,会对主节点上的 binlog 加锁,当读取完成并发送给从服务器后解锁。 - IO 线程接收主节点 binlog dump 进程发来的更新之后,保存到
中继日志(relay log)
中。 - slave的
SQL线程
,读取relay log日志,并解析成具体操作,从而实现主从操作一致,最终数据一致。
主从部署必要条件
- 主库开启binlog日志(设置log-bin参数)
- 主从server-id不同
- 从库服务器能连通主库
服务器创建方式
- 使用
docker
方式创建MySQL服务器,主从服务器IP一致,使用端口号区分。
5.1.2 主服务器搭建
- 在docker中创建并启动MySQL主服务器:
端口3306
docker run -d \
-p 3306:3306 \
-v /msb/mysql/master/conf:/etc/mysql/conf.d \
-v /msb/mysql/master/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name msb-mysql-master \
mysql:8.0.29
- 创建MySQL主服务器配置文件
默认情况下MySQL的binlog日志是自动开启的,可以通过如下配置定义一些可选配置
vim /msb/mysql/master/conf/my.cnf
[mysqld]
# 服务器唯一id,默认值1
server-id=1
# 设置日志格式,默认值ROW
binlog_format=STATEMENT
# 二进制日志名,默认binlog
# log-bin=binlog
# 设置需要复制的数据库,默认复制全部数据库
#binlog-do-db=mytestdb
# 设置不需要复制的数据库
#binlog-ignore-db=mysql
#binlog-ignore-db=infomation_schema
重启MySQL容器
docker ps
docker restart msb-mysql-master
binlog格式说明:
- binlog_format=STATEMENT:日志记录的是主机数据库的
写指令
,性能高,但是now()之类的函数以及获取系统参数的操作会出现主从数据不同步的问题。 - binlog_format=ROW(默认):日志记录的是主机数据库的
写后的数据
,批量操作时性能较差,解决now()或者 user()或者 @@hostname 等操作在主从机器上不一致的问题。 - binlog_format=MIXED:是以上两种level的混合使用,有函数用ROW,没函数用STATEMENT,但是无法识别系统变量
-
登录MySQL主服务器
ALTER USER ‘root’@‘%’ IDENTIFIED WITH mysql_native_password BY ‘123456’;
#启动容器,在容器内访问MySQL env LANG=C.UTF-8 避免容器中显示中文乱码
[root@localhost ~]# docker exec -it msb-mysql-master env LANG=C.UTF-8 /bin/bash
bash-4.4# mysql -uroot -p
Enter password: 输入密码
#修改默认密码校验方式
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-
在主数据库上, 创建一个允许从数据库来访问的用户账号
用户:
msb_slave
密码:
123456
主从复制使用
REPLICATION SLAVE
赋予权限
-- 创建slave用户
CREATE USER 'msb_slave'@'%';
-- 设置密码
ALTER USER 'msb_slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'msb_slave'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
- 主机中查询master状态
执行完此步骤后,不要再操作主服务器,防止主服务器状态值变化,可以选择锁住主服务器
-- 执行以下命令锁定数据库以防止写入数据。
FLUSH TABLES WITH READ LOCK;
到主服务器上查看主机状态, 记录File和Position对应的值
-- 在主机查看mater状态
SHOW MASTER STATUS;
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000003 | 1092 | | | |
+---------------+----------+--------------+------------------+-------------------+
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000003 | 1345 | | | |
+---------------+----------+--------------+------------------+-------------------+
5.1.3 从服务器搭建
我们可以选择配置多台从服务器,配置方式都是一样的。
- 在docker中创建并启动MySQL从服务器:名称
msb-mysql-slave1
, 端口3307
docker run -d \
-p 3307:3306 \
-v /msb/mysql/slave1/conf:/etc/mysql/conf.d \
-v /msb/mysql/slave1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name msb-mysql-slave1 \
mysql:8.0.29
docker run -d \
-p 3308:3306 \
-v /msb/mysql/slave2/conf:/etc/mysql/conf.d \
-v /msb/mysql/slave2/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name msb-mysql-slave2 \
mysql:8.0.29
- 创建slave1的配置文件
vim /msb/mysql/slave1/conf/my.cnf
vim /msb/mysql/slave2/conf/my.cnf
配置下面的内容
[mysqld]
# 服务器唯一id,每台服务器的id必须不同,如果配置其他从机,注意修改id
server-id=2
[mysqld]
server-id=3
重启从服务器
docker restart msb-mysql-slave1
docker restart msb-mysql-slave2
登录MySQL主服务器
[root@localhost ~]# docker exec -it msb-mysql-slave1 env LANG=C.UTF-8 /bin/bash
bash-4.4# mysql -uroot -p
Enter password: 输入密码
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
[root@localhost ~]# docker exec -it msb-mysql-slave2 env LANG=C.UTF-8 /bin/bash
bash-4.4# mysql -uroot -p
Enter password: 输入密码
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
- 在从机上配置主从关系
CHANGE MASTER TO MASTER_HOST='192.168.58.100',
MASTER_USER='msb_slave',MASTER_PASSWORD='123456', MASTER_PORT=3306,
MASTER_LOG_FILE='binlog.000003',MASTER_LOG_POS=1345;
- 启动从服务器,查看状态
START SLAVE;
-- 查看状态(不需要分号)
SHOW SLAVE STATUS\G
5.1.4 主从同步测试
在主库创建数据库、表,插入数据,测试从库是否同步数据
-- 创建数据库
CREATE DATABASE user_db CHARACTER SET utf8;
-- 创建表
CREATE TABLE users (
id INT(11) PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20) DEFAULT NULL,
age INT(11) DEFAULT NULL
);
-- 插入数据
INSERT INTO users VALUES(NULL,'user1',20);
INSERT INTO users VALUES(NULL,'user2',21);
INSERT INTO users VALUES(NULL,'user3',22);
5.1.5 停止和重置
需要的时候,可以使用如下SQL语句
-- 在从机上执行。功能说明:停止I/O 线程和SQL线程的操作。
stop slave;
-- 在从机上执行。功能说明:用于删除SLAVE数据库的relaylog日志文件,并重新启用新的relaylog文件。
reset slave;
-- 在主机上执行。功能说明:删除所有的binglog日志文件,并将日志索引文件清空,重新开始所有新的日志文件。
-- 用于第一次进行搭建主从库时,进行主库binlog初始化工作;
reset master;
5.1.6 常见问题解决
启动主从同步后,常见错误是 Slave_IO_Running: No 或者 Connecting
的情况
解决方案1:
- 首先停掉Slave服务
-- 在从机停止slave
stop slave;
- 到主服务器上查看主机状态, 记录File和Position对应的值
-- 在主机查看mater状态
SHOW MASTER STATUS;
- 然后到slave服务器上执行手动同步:
-- MASTER_LOG_FILE和MASTER_LOG_POS与主库保持一致
CHANGE MASTER TO MASTER_HOST='192.168.58.100',
MASTER_USER='slave',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000015',
MASTER_LOG_POS=442,
MASTER_CONNECT_RETRY=10;
解决方案2
- 程序可能在slave上进行了写操作
- 也可能是slave机器重起后,事务回滚造成的.
- 一般是事务回滚造成的,解决办法
mysql> slave stop;
mysql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
mysql> slave start;