Mysql架构体系全系列文章主目录(进不去说明还没写完)https://blog.csdn.net/grd_java/article/details/123033016 |
---|
本文只是整个系列笔记的第四章:MySQL集群架构,只解释MySQL集群架构相关概念。如果不懂第一章MySQL架构原理,是看不懂这章的。
1. 集群架构设计理念
1. 大家必须清楚的一点:InnoDB提交分为两个阶段,prepare(准备,准备好)阶段,commit(提交)阶段。
2. 可以大致理解为,先写日志再写数据,prepare阶段是写日志(并且执行了SQL语句),commit阶段是真正的提交事务,对数据进行修改,清理Undo 日志等。
3. 整个提交阶段做了很多事,有很多书籍对两阶段的定义都不同,包含的操作也不同。本文就统一将写日志操作当做第一阶段,真正提交事务,持久化修改当做第二阶段。
集群架构设计时,主要遵从3个维度:可用性、扩展性、一致性
1. 可用性设计:一台服务器瘫痪,不至于整个服务不可用,数据不至于丢失。保证高可用的方式就是冗余(说白了就是备份)。
- 站点高可用,冗余站点
- 服务高可用,冗余服务
- 数据高可用,冗余数据
- 主流的实现高可用的架构模式
1. 主从模式:简单灵活,比较主流,可以满足大部分需求,适用于读多写少的,但是写操作的高可用需要自行处理(因为从库负责读,可以扩展很多台,但是主库负责写,只有一台)
2. 双主模式:特殊的主从架构,互为主从,有双主双写、双主单写两种方式,建议双主单写,因为双主双写容易发生数据不一致,数据冲突等问题。2. 扩展性设计:如果当前集群承担不了压力,可以方便的扩展集群和服务。主要围绕读操作扩展和写操作扩展展开
- 提高读性能的扩展
1. 加从库:简单易操作,方案成熟但是上限低。从库过多会引发主库性能损耗(需要频繁数据同步,发送binlog日志等),需要用良好的设计避免持续加从库来缓解读性能问题。
2. 分库分表:需要大量的实践经验才能胜任分库分表的工作(其实通过自己用虚拟机搭集群测试,就可以积攒大部分经验,剩下的去公司真实环境再碰碰壁就好了),业界还没有一套比较完美的通用解决方案。分为水平拆分和垂直拆分,垂直拆分可以缓解部分压力,水平拆分理论上可以无限扩展。
- 提高写性能的扩展
分库分表
3. 一致性设计:主从架构中,主从各库数据需要同步,集群有若干服务器,保证这些服务器数据一致,主要考虑集群中各数据库同步和同步延迟问题,可用方案如下
- 不使用从库:就是不用主从架构,使用分库分表,那么只需要关心用户请求如何路由到对应的库和表。
- 增加访问路由层:进行一些逻辑控制,避免发生主从不同步问题,比如计算出主从同步需要的最长时间,在接下来这段时间,让所有请求都去主库,等主从同步完成,再让请求可以前往从库。
2. 主从模式理论
MySQL主从模式,指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。
- MySQL默认采用异步复制方式,节点不用一直访问主服务器来更新自己数据。
- 从节点,可以复制主节点中所有数据库,或者特定数据库,或者特定的表。
mysql主从复制的用途
- 实时备灾,用于故障切换,提高站点的高可用
- 读写分离,提供查询服务的高可用
- 数据备份,提高业务数据的高可用,避免一个库宕机,整个业务不能用
主从部署的必要条件
- 从库服务器能连通主库
- 主库开启binlog日志(设置log-bin参数)
- 主从server-id不同
主从复制原理
- Master主库必须开启Binary log日志功能,Data changes发生数据改变,bin log日志会详细记录发生修改的操作细节(具体多详细和你的参数设置有关)
- Slave从库,此时会Read读主库的Binary log日志到本地,然后写到自己的Relay log(中继日志)中
- 然后MySQL的线程SQL Thread,就会读取Relay log日志,replay重现主库做过的修改,以达到数据同步
- 注意,日志中记录的是修改的细节,不是具体数据。涉及了Master的BinlogDump Thread线程和Slave的I/O Thread 和 SQL Thread线程。
- BinlogDump Thread:Master将修改操作记录到Binlog中后,从库会进行同步,发送Read请求给Master。BinlogDump Thread线程接到从库的请求后,读取Binlog信息推送给Slave的I/O Thread。
- Slave的I/O Thread将读取到的Binlog信息写入到本地Relay Log中。
- Slave的SQL Thread检测到Relay Log的变更请求,解析relay log内容在从库上执行,完成数据同步。
完全异步复制的时序
- Master execute(执行)修改操作后,到commit提交的细节如下
- 判断数据页是否在内存,不在就磁盘读取到内存,返回数据行,在的话,直接返回
- 对返回的数据行进行数据更新操作,然后将数据写入内容,同时redolog、binlog写入内存(redo log buffer和binlog buffer)
- 执行commit命令,只是SQL命令操作,不是数据(事务)是commit状态
- 执行完commit命令之后,才会进行真正的两阶段提交操作,具体细节如下:
- 写入内存中的redo log到磁盘,此时redo log处于prepare状态
- 写入binlog到磁盘,
这个点就是异步的点
。- 提交事务,此时事务处于commit状态。
- Slave进行异步同步
- 当主库事务提交后,从库才可以读取到主库修改后的binlog日志,因为commit是进行两段提交(先提交日志,再提交数据修改)
- 当日志被提交后,从库就可以异步的开始同步,读取主库binlog到relay log,然后重现主库事务。同样的,第一段提交记录到自己的binlog,第二段提交让事务处于commit。
- 而当从库同步binlog时,不会影响主库进行第二段提交或者主库接下来的操作。
mysql完全异步的主从复制的问题
- 主库宕机后,数据可能丢失,比如进行第一段提交前或第一段提交时宕机了,从库将无法同步binlog
- 从库只有一个SQL Thread,主库写压力大,复制可能会延时,高并发时,就会出现数据不同步
解决方法
- 半同步复制—解决数据丢失问题
- 并行复制------解决从库复制延迟问题
2.1半同步复制
如果是全同步的话,那么主库必须等待从库同步完,才能执行最后的一段commit,怎么做事务安全性是最高的,但是事务执行周期就太长了。
半同步复制:让Master在某一时间点等待Slave结点的ACK(Acknowledge character)消息,接到ACK消息后才进行事务最终的提交,MySQL5.5版本开始引入半同步复制机制来降低数据丢失的概率。
- 某个时间点,大多数情况是relay log同步成功后,就会返回ACK。
我们先复习一些主库事务写入的4个步骤(来自官方文档):
- InnoDB Redo File Write(Prepare Write):写Redo日志,标记为prepare状态
- Binlog File Flush & Sync to Binlog File:binlog刷盘,并异步同步Binlog文件
- InnoDB Redo File Commit(Commit Write):Redo 日志提交,这里是引擎真正的提交了事务,事务状态为commit
- Send Binlog to Slave(sync):异步发送Binlog文件到Slave
再复习一下主从复制的方案
- 传统主从复制:Master不需要关注Slave是否接受到Binlog Event
- 半同步复制(MySQL 5.5引入):Master需要在第三步真正提交事务之后,不会立即返回事务提交成功给客户端,而是等待Slave返回ACK,即为after-commit,从库都同步完,才能继续执行,返回事务提交成功。
- 增强半同步(MySQL 5.7引入):当Master需要在第二步Binlog刷盘完成之后,等待Slave返回ACK,即为after-sync,才能继续执行。
- 记住一点,主库的binlog只有提交到磁盘,从库才能获取到,所以无论怎样,都是在第二步binlog刷盘完成之后,才能开始异步复制。
所以半同步复制和增强半同步复制的时序图一样,都是等从库返回ACK,只不过,增强半同步,会在binlog刷盘后,就等待从库返回ACK
相应的,这种方案,也会有问题
- binlog刷盘后,发送给从库失败。此时主库是知道失败的,可以通过redo log重做。
- binlog刷盘后,成功发送给从库,但是从库没有返回ACK。此时从库无论同步是否成功,主库的结果都是失败,需要重做。
- 但是半同步复制,是事务已经提交完成,这时候退回去会比较麻烦,但是增强半同步复制,它在binlog刷盘后停住了,事务没有提交,所以出现意外,它的后路会多一些。
2.2 并行复制(MTS)
如果MySQL5.7要使用MTS功能,必须使用最新版本(最低5.7.19版本),修复了很多bug
MySQL主从复制的延迟,一直广受开发者关注,MySQL5.6开始追加了并行复制功能,目的就是为了改善复制延迟问题,并行复制称为enhanced multi-threaded salve(简称MTS)
从库中有两个线程(I/O Thread和SQL Thread),都是单线程模式工作,因此有延迟问题,那么采用多线程机制来加强,就可以减少从库复制的延迟
- 没有加强I/O Thread,因为就算它加强了,主库传输也还是那个速度,从库的接收线程增多,也只能闲着。
- 加强SQL Thread,当日志拷贝完成,多个工作线程同时进行数据库同步操作,就可以加快同步速度。
- MySQL5.6、5.7、8.0版本上,都是基于SQL Thread多线程思想,不断优化,减少复制延迟。
MySQL
5.6
并行复制原理:5.6版本支持了所谓的并行复制,但其并行只是基于库的
,如果用户MySQL数据库中是多个库,对于从库复制的速度,的确可以有较大帮助
- 每个线程(事务)负责不同库的同步工作,事务之间没有冲突
- Coordinator(调度者,就是原来的SQL Thread)先读取Relay Log,然后将针对不同库的操作,建立一个队列Jobs放上对应操作,然后分配给不同线程(Worker xxxx),从队列中取操作,然后执行。
- 这种工作模式,只是针对多库的场景下有明显效率提升,如果是单库多表的场景下,可能反而需要更多的时间来完成工作。而且事务之间的并行执行顺序也需要考虑。
MySQL
5.7
并行复制原理:5.7之后才能真正称为并行复制,基于组提交的并行复制,Slave服务器的回放与Master服务器是一致的(Master服务器上怎么并行执行,Slave上就怎么进行并行回放),不会再有库的并行复制限制。
MySQL5.7中基于"组提交"的并行复制
- 对事务进行分组,当事务提交时,将在单个操作中写入到二进制日志中。如果多个事务同时提交成功,那么它们并不会有冲突,会在主库上的二进制日志中添加以组为单位的提交信息,因此可以在Slave上并行执行。
- MySQL5.7的并行复制有一个规则,所有已经处于prepare阶段的事务,都保证可以并行提交。这样就可以放心在从库中并行提交,因为处理这个阶段的事务没有冲突。
在一个组中提交的事务,一定不会修改同一行
。这是新的并行复制思路,摆脱了原来防止冲突的分发算法,等待策略等复杂、效率低下的工作。- 引入了新的变量(参数)
slave-parallel-type
,以兼容MySQL 5.6基于库的并行复制。其参数值可以是Database(默认值,基于库的并行复制)、Logical_clock(基于组的提交方式)
事务分组、分组后的binlog日志
- 5.7版本设计方式是将"组提交"的信息放在GTID中,为了避免用户没有开启GTID功能(gtid_mode=OFF),5.7版又引入了Anonymous_Gtid二进制日志event类型-----ANONYMOUS_GTID_LOG_EVENT
- 通过mysqlbinlog工具分析binlog日志,可以发现组提交的内部信息,下面是一共三组的日志信息,last_committed = 0的、=6的、=12的,各自一组。
- 多了last_committed和sequence_number两个字段
- sequence_number表示事务编号
- last_committed表示事务提交时,上次事务提交的编号,如果事务具有相同last_committed,表示这些事务都在同一组,可以进行并行回放。
MySQL
8.0
并行复制原理:基于write-set的并行复制,MySQL会有一个集合变量
,存储事务修改过的记录
信息(主键哈希值),所有已经提交的事务,这个事务所修改的主键值经过hash
后,都会与那个变量的集合进行对比,来判断该行是否与其冲突(集合中已经存在)
。以此来确定依赖关系,没有冲突即可并行
。这样的粒度,就到row(行)级别了,此时并行的粒度更加精细,并行速度会更快。
8.0 并行复制的配置和调优,下面给出个参数的介绍,最后给出配置文件指定的形式,推荐使用配置文件统一配置。
# 控制集合变量的大小
set [global] binlog_transaction_dependency_history_size = xxx;
# 控制binlog文件中事务之间依赖关系,就是last_committed值(上一个执行的事务的id)
# COMMIT_ORDERE:基于“组提交”机制
# WRITESET:基于写集合机制
# WRITESET_SESSION:基于写集合,比writeset多了一个约束,同一个session中的事务last_committed按先后顺序递增。
set [global] binlog_transaction_dependency_tracking = xxx;
# 用于控制事务的检测算法,参数值为OFF、XXHASH64、MURMUR32
set [global] transaction_write_set_extraction = xxx;
# 开启MTS(并行复制)功能后,可以将此参数设置为TABLE,这样性能可以有50%~80%的提升,因为并行复制开启后
# 对元master.info这个文件的更新将会大幅提升,资源竞争也会变大。
set [global] master_info_repository = xxx;
# 同理,也需要对relay_log的info设置为table,可以有效提升性能
set [global] relay_log_info_repository= xxx;
# 线程工作模式
# 0:退化到单线程的复制
# 正数,比如1:SQL线程功能转化为coordinator线程,但只有一个worker线程回放,单线程复制
set [global] slave_parallel_workers = xxx;
# 保证事务按照relay log中记录的顺序来回放。MySQL5.7之后,MTS可以实现更小粒度的并行复制
# 需要将slave_parallel_type设置为LOGICAL_CLOCK(基于组提交),但仅仅设置LOGICAL_CLOCK不够,此时在slave上应用事务的顺序是无序的。
# 和relay log中记录的事务顺序不一样,这样的数据一致性无法保证,为了保证事务按relay log中记录的顺序来回放
# 需要开启参数slave_preserve_commit_order
set [global] slave_preserve_commit_order = xxx;
# 开启slave_preserve_commit_order后,就必须开启log_slave_updates参数
set [global] log_slave_updates = xxx;
配置文件统一指定
# 基于组提交
slave-parallel_type= LOGICAL_CLOCK
# 工作线程为8个并行
slave_parallel_workers= 8
# slave待处理任务的最大量
slave_pending_jobs_size_max= 2147483648
# 开启slave保证提交顺序功能。保证事务按照relay log中记录的顺序来回放
slave_preserve_commit_order= 1
# 开启slave日志更新。开启slave_preserve_commit_order= 1,就必须开启log_slave_updates
log_slave_updates= 1
# master info 元信息存储到table,效率提升50%~80%
master_info_repository= table
# relay log 日志元信息存储到table(表),默认是file文件中
relay_log_info_repository= table
# relay log 恢复功能开启。
relay_log_recovery= 1
并行复制的监控 |
---|
使用MTS(并行复制)后,复制的监控,还是可以用show slave status \G;命令查看的,但是5.7版本开始,performance_schema库提供多个元数据表,可以更详细的监控并行复制过程
- 通过replication_applier_status_by_worker可以看到worker进程的工作情况
3. Linux虚拟机集群环境准备
由于篇幅原因放在这篇文章了:https://blog.csdn.net/grd_java/article/details/124127540 |
---|
上面的文章演示了一个主机的配置过程,你可以根据需要,通过上面的步骤,定制多台主机,组成集群。具体几台,看后面我的案例中的要求。
4. 主从模式实战
需要拥有两个主机Master1和Slave1两台,具体如果创建,参考上面Linux虚拟机集群环境准备
保证两个主机都可以进入mysql>,并且两个主机都关闭了防火墙。
另外,推荐大家所有mysql配置都配置到配置文件中,不要图方便使用set命令,set命令无法修改只读参数,也不能保证配置一直有效。
4.1 配置主库
4.1.1 修改配置文件
修改Master1上的配置文件/etc/my.cnf,配置到[mysqld]下;我们要将这台主机作为master主机(主从架构的“主”),需要开启binlog日志,做相关master配置。
# log_bin
log_bin=mysql-bin # 开启binlog功能,名字指定为mysql-bin
server-id = 1 # 服务id号,保证唯一
sync-binlog = 1 # 同步模式,=1表示每次写入,都进行磁盘同步(刷盘)
# 以下系统库,不进行同步
binlog-ignore-db=performance_schema
binlog-ignore-db=information_schema
binlog-ignore-db=sys
# 指定以下库,需要进行同步,我们这里举个实例,不指定这个参数
# binlog-do-db=需要指定同步的库
#
重启mysql 服务
[hadoop100@master1 module]$ sudo systemctl restart mysqld
4.1.2 配置主库授权
1. 主库可以选择性的给特定从库授权(进入到mysql>命令行进行授权),得到授权的从库才能进行同步,另外我们也需要给特定用户和账号授予相关操作权限
2. 你需要通过show master status;查看主库状态,并获取你的binlog日志文件信息,我这里文件为mysql-bin.000003
- 里面有个很重要的属性Position,是文件中指针的位置,从库进行同步时,不可能每次都把整个文件同步一遍吧。
- 从库同步时,就需要知道这个Position,从指定位置进行同步,而不是每次都从头同步。
# 主从复制的授权语法-----这个是给从库授权,让指定从库可以进行主从复制
grant replication slave on 允许授权的范围 to 授权的用户@授权的操作 identified by 授权的账号
# 权限,授权语法-----这个是授权一些操作,否则就是建立主从连接,也没办法操作
grant all privileges on 允许授权的范围 to 授权的用户@授权的操作 identified by 授权的账号
# 授权主从复制权限给所有slave的root用户的远程连接操作给root账号
grant replication slave on *.* to 'root'@'%' identified by 'root';
# 授权其它所有权限
grant all privileges on *.* to 'root'@'%' identified by 'root'
# 刷新权限----授权完成后,需要进行刷新才能生效
flush privileges;
4.2 配置从库
4.2.1 修改配置文件
和配置主库的步骤一样,配置内容不一样
- 先配置从库的/etc/my.cnf配置文件
# log_bin
# 从库无需开启binlog日志,只需要relay_log,默认是开启的
server-id=2 # id一定要保证唯一
relay_log=mysql-relay-bin # 指定relay_log的名字,不指定就是用默认的
read_only = 1 # 是否只读,1表示开启只读限制,也就是这个从库只能进行读操作
- 重启服务
- 进入mysql> 命令行,然后执行show slave status;正常情况下应该是Empty set,表明你还没有进行过主从复制,否则后面你的日志和我对不上,会产生冲突。
4.2.2 配置从库同步设置
和主库一样,主库需要授权给指定从库,允许它同步,从库也需要指定,和谁进行同步。
# 语法如下,其中master的binlog文件名和Position编号,都需要master上执行show master status;命令查看
change master to master_host = 'master的ip地址',master_port=master的mysql端口号,master_user='master配置授权时指定的账号',master_password='master账号的密码',master_log_file='master的binlog文件名',master_log_pos=master的binlog文件的Positon编号;
# 示例
change master to master_host='192.168.10.100',master_port=3306,master_user='root',master_password='root',master_log_file='mysql-bin.000003',master_log_pos=154;
4.2.3 开启从库复制
- 命令start slave;将开启从库,进行主从复制。
- 此时再通过show slave status \G;(\G是竖版显示,方便查看)就可以看到同步信息了。而不是Empty set了
4.2.4 在master建个库,看看效果
Master上建立一个school库,库里面创建一个student表
# 创建school库
mysql> create database school;
# 进入school
mysql> use school;
# 创建student表
mysql> create table student(
-> id char(20) primary key,
-> username varchar(20)
-> )engine=innodb
-> charset=utf8;
# 查看是否创建成功
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| school |
| sys |
+--------------------+
现在直接去slave上,show databases;就可以看到,成功同步过去了。
Master上执行insert看效果
4.2.5 使用mysqldump工具,加速同步
考虑:配置从库不可能每次都从我们一开始配置的Position位置同步,一个月后产生好多数据量后,还从那个地方同步吗?如果需要扩展从库个数,相同的配置要每台机器都做一遍吗?(其实我们5.7和之后的版本,使用并行复制基于组提交(GTID),基于GTID的复制中,从库会告知主库已经执行的事务的GTID的值,然后主库会将所有未执行的事务的GTID的列表返回给从库,并且可以保证同一个事务只在指定的从库执行一次,自然就解决了这些问题。)
- 可以通过mysqldump工具,将主库中的数据文件拷贝,然后分发(通过工具)给从库,从库自己去执行,增加同步速度,而且非常简单
步骤如下:
- Master库执行命令,拷贝数据文件
# > 这个符号在Linux表示输出
mysqldump 操作的目标 > 要输出到那个文件 -u用户名 -p密码
# 下面操作就是将所有的库文件,输出到mysql_backup_all.sql文件
mysqldump --all-databases > mysql_backup_all.sql -uroot -proot;
- 将生成的文件分发到从库,进行数据同步,然后配置同步位置Position。
- 如何分发,这是Linux的基础知识,有多种工具可以选择。
- 配置同步位置,不需要去每一台机器中配置,而是通过集群分发脚本,统一执行脚本。也是Linux基础知识。
4.3 半同步复制
mysql使用半同步复制时,需要额外的模块做支撑,安装是比较简单的。
先通过show plugins;命令查看是否有rpl_semi_sync_XXXXXX半同步插件,主和从是不一样的
- Master上,是rpl_semi_sync_master插件
- Slaves上,是rpl_semi_sync_Slave插件
主库和从库都得安装,安装步骤一样,下面演示主库,从库大家自己按步骤自己走一遍(
注意:从库安装的是rpl_semi_sync_Slave,主库安装的是rpl_semi_sync_master
)。
- 首先先要查看主库的mysql是否支持动态插件安装,通过命令select @@have_dynamic_loading;如果是NO,不支持的话,请升级你的MySQL版本,太老了。
- 安装rpl_semi_sync_master模块,其实在MariaDB(Mysql分支产品)中是默认安装了这个的,并起名为semisync_master.so,所以我们也给它起这个别名
# 安装rpl_semi_sync_master插件,起别名为'semisync_master.so'
install plugin rpl_semi_sync_master soname 'semisync_master.so';
# 从库安装rpl_semi_sync_slave插件,起别名为'semisync_slave.so'
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
# 可以通过show plugins;查看是否安装成功
show plugins;
- 安装完成之后,我们可以查看相关参数
- Master
- Slave
show variables like '%semi%';
- 启用并设置,可见上面没有开启semi_sync(半同步),timeout为10秒太长了。我们可以配置文件指定,或者通过set global XXXX命令来直接配置。
- 方法1:通过set global 命令进行全局配置
- 方法2:修改配置文件
[hadoop100@master1 ~]$ sudo vim /etc/my.cnf
# Master库的配置
rpl_semi_sync_master_enabled = 1 # 开启半同步复制功能
rpl_semi_sync_master_timeout = 1000 # 超时时间为1秒
# Slave的配置
rpl_semi_sync_slave_enabled = 1 # 开启半同步复制功能
#记住修改后,一定要重启mysql服务
[hadoop100@master1 ~]$ sudo systemctl restart mysqld
- 查看是否修改成功
配置成功之后,就可以启用半同步复制了,需要先停止当前slave,然后重新启动它
mysql> stop slave;
mysql> start slave;
接下来就看看半同步的效果了,我们随便在Master插入一条数据,然后看Master上的日志,看看它是不是半同步(日志中显示semi_sync)
4.4 并行复制(并行功能开启)
并行复制不需要安装额外模块,5.7版本添加了基于组提交的新特性。
注意
,并行复制是一种复制方式,采用多线程,无论是全同步,半同步,都可以使用单线程或多线程。不要混淆概念。
Master主要配置binlog的并行处理,也就是让binlog基于"组"提交事务
Slave主要配置Slave开启并行,还有relay_log相关的配置
因为我们都知道,主库就是负责将修改记录到binlog。而Slave就是读binlog到relay_log中进行同步
首先配置Master,通过show variables like ‘%binlog_group%’;命令查看相关参数。
配置文件中配置如下参数,然后重启mysqld服务
# 组提交延迟
binlog_group_commit_sync_delay = 1000
# 每组最多包含的事务数量
binlog_group_commit_sync_no_delay_count = 100
然后配置Slave,前面我们讲过,5.7为了兼容以前的基于库的并行复制,添加了一个新参数slave_parallel_type,默认值就是DATABASE,基于库。我们需要修改,让其基于组(Logical_clock),同时也要对relayLog做相应配置。
- 通过命令show variables like '%slave%'即可看到slave相关参数
- 通过命令show variables like '%relay_log%'即可看到relay_log相关参数
- 通过配置文件修改参数(有些参数只读,用set命令改不了。如果你想使用set global命令直接修改,需要先stop slave停止slave服务。设置完成后,再start slave;但是只读的参数只能在配置文件改),这些参数,在前面讲解8.0版本并行复制的理论时,都介绍过。5.7高版本和8.0配置几乎差不多。
记住配置完重启mysqld服务
配置成功效果
# 基于组提交
slave-parallel_type= LOGICAL_CLOCK
# 工作线程为8个并行,如果是0表示单线程,默认是0
slave_parallel_workers= 8
# slave待处理任务的最大量
slave_pending_jobs_size_max= 2147483648
# master info 元信息存储到table,效率提升50%~80%
master_info_repository= table
# relay log 日志元信息存储到table(表),默认是file文件中
relay_log_info_repository= table
# relay log 恢复功能开启。
relay_log_recovery= 1
# 下面的功能是调优用的,为了提升效率,但会花费一定存储空间,不要轻易配置
# 开启slave保证提交顺序功能。保证事务按照relay log中记录的顺序来回放
slave_preserve_commit_order= 1
# 开启slave日志更新。开启slave_preserve_commit_order= 1,就必须开启log_slave_updates
log_slave_updates= 1
# 开启logbin,如果要保证slave_preserve_commit_order= 1有序,就需要开启bin log功能
log_bin=mysql-bin # 开启binlog功能,名字指定为mysql-bin
sync-binlog = 1 # 同步模式,=1表示每次写入,都进行磁盘同步(刷盘)
看看效果吧,前面讲解并行复制理论的时候,介绍过如何监控,这里就直接上效果图
- 先看看主库修改,从库是否同步成功
- 通过查看performance_schema库的replication_applier_status_by_worker表数据,如果出现相关信息,表示并行复制功能正常。
mysql> use performance_schema
mysql> show tables like 'replication%';
mysql> select * from replication_applier_status_by_worker;
5. 读写分离理论
大多数互联网项目都是读多写少的,数据库的读操作,会首先成为数据库瓶颈,如果我们已经优化了SQL,但是读性能依然处于瓶颈,这时就可以选择“读写分离”架构了
如果一个库建立太多索引,写的效率会受很大影响。所以读写分离架构中,主库一般很少建立索引,负责读操作的从库才会建立大量索引以提高查询效率。
- 读写分离是数据库主从架构的基础上衍生而来。核心思想是主库用于写,多个从库负责读操作。
- 主从库之间依然通过上面我们介绍的主从复制机制进行数据同步。
- 也就是读写分离,就是在上面主从模式的基础上,实现主库负责写,从库负责读。
同时,读写分离架构,需要解决
主从同步延迟
和读写分配机制
的问题
- 主从同步延迟:读写分离架构中,主从同步具有延迟性,数据一致性会受到影响,对于实时性要求比较高的操作,需要特殊的解决方案处理,下面列出3种:
- 写后立刻读主库:主库写入数据后,在主从正在同步的时间段,所有读操作去主库直接读,而不去从库。同步完成,再去从库读。
- 二次查询:先前从库查,找不到就去主库读取数据。
- 根据业务特殊处理:重要的业务,全部在主库完成,不重要,对实时性要求不高的,可以分离到从库去读,写操作依然在主库。
- 读写分配机制:读操作和写操作如何分配到对应服务器。常见的两种方案如下:
- 基于编程和配置实现:代码中,根据操作类型进行路由分配,增删改时,将请求发送到主库,查询发送到从库,也是目前应用最广泛的,并且还引入了redis等中间件缓存。但是如果结点挂掉,就需要修改项目配置,重启项目(主要是简单,一般超高并发的项目还是比较少的,实现读写分离后数据库很少有宕机的情况)。
- 服务端代理实现:处于应用服务器和数据库服务器之间,专门做代理的服务器,当应用服务器发送请求时,统一发送给代理服务器。代理服务器根据规则将请求转发给对应的数据库服务器(主库,或者某个从库)
- 针对服务端代理,目前有很多性能不错的数据库中间件,常用的有MySQL Proxy、MyCat以及Shardingsphere等等,这些在后面的章节,实战运维阶段会详细介绍。
- MySQL Proxy:官方提供的MySQL中间件,可以实现均衡负载,读写分离等。
- MyCat:MyCat是一款基于阿里开源产品Cobar而研发的,基于Java语言编写的开源数据库中间件。
- ShardingSphere:一套开源的分布式数据库中间件解决方案,有Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(还在计划中)这3款相互独立的产品组成,在2020年4月16日从Apache孵化器毕业,成为Apache顶级项目。
- Atlas:Atlas由Qihoo 360公司Web平台部基础架构团队开发维护的一个数据库中间件。
- Amoeba:变形虫,2008年发布的一款Amoeba for MySQL软件。
6. 读写分离实战
关于读写分配,基于程序的就很简单,配置个地址就好,完全没必要讲,所以我们这里主要讲,如何基于代理服务器实现读写分配
我们这里采用MySQL官方自带的MySQL Proxy中间件,后面我们会有专门的章节讲解ShardingSphere和MyCat
6.1 安装mysqlProxy
我们需要搞一台代理服务器,所以我们需要再整一台虚拟机,不过这台虚拟机不需要安装mysql。我们设置它的主机名为proxy,ip为192.168.10.6
然后我们需要安装mysql-proxy
- 直接使用yum安装最新版(我这里不使用这种方式)
# 安装到指定目录,要不,不好找
# -c /etc/yum.conf指定yum的配置文件路径
# --installroot=/opt/module指定安装目录
[hadoop100@proxy share]$ sudo yum -c /etc/yum.conf --installroot=/opt/module --releasever=/ install mysql-proxy
- 使用wget下载指定链接。(我使用的方式,可以下载指定的版本)
- 先看看我们有没有安装wget这个工具
# 查看是否安装wget
[hadoop100@proxy ~]$ rpm -qa | grep "wget"
wget-1.14-18.el7_6.1.x86_64
# 没有就通过下面的命令安装
[hadoop100@proxy ~]$ yum -y install wget
# 如果想要卸载wget,就用下面的命令
[hadoop100@proxy ~]$ yum remove wget
- 有这个工具后,我们下载mysql-proxy-0.8.5-linux-el6-64bit.tar.gz
# 链接如果有变动,大家百度找到下载链接后,贴在这里就好了
[hadoop100@proxy ~]$ wget https://cdn.mysql.com/archives/mysql-proxy/mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz
- 然后安装下载好的tar.gz包,可见在安装目录下/share/doc/mysql-proxy/文件夹下有很多lua脚本,我们待会需要使用这里面一些脚本
6.2 配置MysqlProxy
配置/etc/mysql-proxy.cnf文件
[hadoop100@proxy ~]$ vim /etc/mysql-proxy.cnf
[mysql-proxy]
#当前运行mysqlProxy的用户
user=root
# 主从库管理员的账号和密码
admin-username = root
admin-password = root
# 代理主机(本机)的ip和端口号,端口号不指定,默认4040
proxy-address=192.168.10.6:4040
# 主从地址信息
# 指定主(backend)库,可以进行所有操作
proxy-backend-addresses=192.168.10.100:3306
# 指定从库,只负责读操作,多个从库,用逗号分隔,比如192.168.10.1:3306,192.168.10.2:3306
proxy-read-only-backend-addresses=192.168.10.101:3306
# 指定分发策略(分发脚本),这个路径是你安装路径下的
proxy-lua-script=/opt/moudule/mysql-proxy-0.8.5-linux-el6-x86-64bit/share/doc/mysql-proxy/rw-splitting.lua
#日志文件路径,和日志输出基本
log-file=/var/log/mysql-proxy.log
log-level = debug
# 以守护进程的方式运行proxy代理服务,说白了就是后台进程
daemon = true
# 如果崩溃,尝试重启
keepalive = true
让这个配置文件的权限为可读可写,否则会提示,发生意想不到的错误
[hadoop100@proxy module]$ sudo chmod 660 /etc/mysql-proxy.cnf
6.3 修改使用的lua脚本
前面我们指定使用rw-splitting.lua脚本,它里面有一个连接池,设置了只有线程达到4个才进行读写分发,这样我们不容易测算出效果,我们需要将其改为,线程达到1个就可以分发
vim /opt/module/mysql-proxy-0.8.5-linux-el6-x86-64bit/share/doc/mysql-proxy/rw-splitting.lua
6.4 启动MysqlProxy
可以配置环境变量,全局都可以启动,我们这里就不配置了,直接进入bin目录启动它(注意:配置文件读写权限不够,mysql服务器ip端口指定错误,防火墙不关是启动不了的)
# 进入bin目录
[hadoop100@proxy bin]$ pwd
/opt/module/mysql-proxy-0.8.5-linux-el6-x86-64bit/bin
[hadoop100@proxy bin]$ ls
mysql-binlog-dump mysql-myisam-dump mysql-proxy
# 运行mysql-proxy,指定配置文件--defaults-file=配置文件目录
[hadoop100@proxy bin]$ sudo ./mysql-proxy --defaults-file=/etc/mysql-proxy.cnf
6.5 使用MysqlProxy代理
我们可以借助远程连接工具,这里我用Navicat15连接MysqlProxy
使用和普通mysql一样,就不演示了,我将特征列出来
- 初始的表数据状态,是从slave库读出来的,这个是代理拿来的数据,就是看一看,不会对这些数据做任何操作,后期读写操作都会分发到对应MySQL数据库上
- 写操作,是直接发送到Master库的。
- 读操作,会从从库或者主库读取,具体看lua脚本的规则。