1. 基于binlog搭建主从复制
1)、主从复制原理
- 用户写入数据到master数据库中
- master数据库数据写入binlog文件中,通知到slave数据库
- slave数据库的I/O线程从master数据库binlog读取数据到slave数据库的relay log中
- slave数据库的SQL线程重放relaylog,也就是将数据还原到库中
2)、binlog三种模式:通过命令show variables like 'binlog_format';或select @@binlog_format;可查看binlog日志模式;也可通过命令set binlog_format=STATEMENT或ROW或MIXED设置binlog模式;命令只是临时的,重启MySQL就会失效,永久设置需要在my.cnf的[msqld]下添加binlog_format=STATEMENT或ROW或MIXED
- statement level模式:每一条修改数据的SQL记录到master的binlog中,这样会减少binlog数据量,slave只需根据SQL命令就可以同步数据,但是这只限于简单的SQL操作,如果有依赖宿主环境和复杂函数的SQL就不能正确同步数据了,如记录宿主机机器名等;
- row level模式:master的binlog记录每一行数据被修改的形式,slave会做同样的修改,这样可以避免statement level的缺点,但会带来数据量大的问题,如一个简单的update SQL操作,statement level就是一条SQL记录,而row level要记录下所有影响行的数据;
- mixed模式:会结合statement level和row level优点区分对待记录日志形式。其实新版本的MySQL已经对row level模式做了一定优化,比如对表定义的修改就以statement level形式记录。
3)、主从复制环境搭建:(如果有防火墙限制,可以先关闭防火墙)MySQL客户端可以是docker内登录或者其他连接MySQL的客户端
a. 主服务器配置如下:
- 开启binlog,MySQL8.0默认开启,可通过命令show variables like 'log_bin%';查看到log_bin为ON;如果默认为OFF,即关闭,需要在my.cnf的[msqld]下添加log_bin=mybinlog,mybinlog可以自定义修改,为binlog的basename;
- 设置server_id,在my.cnf的[msqld]下添加server_id=3316,保证集群中唯一;我本地用docker环境,配置的server_id为对外暴露的端口号;
- 在配置文件修改完log_bin和server_id后,启动镜像容器,成功后,可在数据文件下看到mybinlog.index文件,里面记录的是mybinlog文件位置,可直接使用cat命令查看,而查看binlog文件需要使用mysql工具命令:docker exec -it mysqlmaster mysqlbinlog --no-defaults --base64-output=decode-rows /var/lib/mysql/mybinlog.000001,--no-defaults参数是解决mysqlbinlog: [ERROR] unknown variable 'default-character-set=utf8mb4';
docker run --name mysqlmaster -p 3316:3306 --privileged=true -v /root/mysqlmaster/conf:/etc/mysql/conf.d -v /root/mysqlmaster/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0
- 在mysql客户端创建一个用户,用于slave中配置连接master,同步数据,同时授予该用户备份数据权限;如果不想创建新用户可直接用root,赋予备份数据权限即可;
create user 'rep'@'%' identified by '@Rep123'; grant replication slave on *.* to 'rep'@'%';
- 在mysql客户端执行刷新权限命令:flush privileges;
- 在mysql客户端查看master状态,命令:show master status; ,记录file和position,要用到slave配置中;如file为mybinlog.000003,position为896
b. 从服务器配置如下:
- 设置server_id,在my.cnf的[msqld]下添加server_id=3326,保证集群中唯一;我本地用docker环境,配置的server_id为对外暴露的端口号;
- 配置完后启动镜像容器
docker run --name mysqlslave -p 3326:3306 --privileged=true -v /root/mysqlslave/conf:/etc/mysql/conf.d -v /root/mysqlslave/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0
- 将master中现有数据手动迁移到slave,如果是全新的库,可忽略此步
- 在mysql客户端执行如下命令,指定slave的master信息
change master to master_host='10.0.79.61', master_port=3316, master_user='rep', master_password='@Rep123', master_log_file='mybinlog.000004', master_log_pos=156, MASTER_AUTO_POSITION=0;
- 在mysql客户端启动从服务器复制功能:start slave;
- 在mysql客户端执行命令:show slave status;查看从库是否正常,可观察Slave_IO_Running和Slave_SQL_Running值都为Yes即可
c. 测试(本地测试通过):
- 在主库中执行创建数据库:create database dbtest;use dbtest;
- 创建表
CREATE TABLE `test` ( `id` bigint NOT NULL AUTO_INCREMENT, `a` bigint DEFAULT NULL, `b` bigint DEFAULT NULL, `c` bigint DEFAULT NULL, `d` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_a_b_c` (`a`,`b`,`c`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
- 插入数据,查看从库,同步成功。
d. 清理binlog方式:
- 手动清理:按照时间清理命令purge master logs before '2022-01-01 17:20:00';或按照文件索引清理purge master logs to'mybinlog.000022';
- 自动清理,设置binlog过期时间:expire_logs_days=7,单位天
2. 基于主从复制的高可用方案,可设计如下,准备两个双主节点的数据库,也就是互相做主从复制,通过keepalive工具实现高可用
3. 基于MySQL-Proxy搭建读写分离
MySQL官方不推荐用于生产,所以做赘述
4. MySQL Router搭建MySQL集群
实际工作中用的并不多,生产上用的都是MySQL中间件,如当当的sharding-jdbc,蘑菇街的TSharding,奇虎360的Atlas,阿里的Cobar,阿里基于Cobar的MyCAT,58同城的Oceanus,谷歌的Vitess
5. 生产用的分库分表后期通过ShardingSphere进行讲解和实现