一. 简单了解MySQL主从复制
- 主从复制原理: 在主从复制中数据库分为master一个主库与slave一个或多个从库,MySql主从复制是异步且串行化执行的
master将修改数据的操作记录到二进制日志文件中(binary log),这些记录过程叫做二进制日志事件,binary log events
slave从库读取master主库的binlog日志到中继日志中(relay log)
slave从库做中继日志的事件,将改变应用到数据库中
- 主从复制的基本原则
一个master,一个或多个slave
每个slave有且仅有一个服务器id
- 再次解释
1)当master节点数据发生改变时,会将改动写入二进制事件日志文件中binlog
2)salve从服务器会在一定时间间隔内检测master主服务器的binlog日志文件是否有改动,如果有会开启一个io线程,请求master二进制事件日志
3)同时master主服务器为每个IO线程启动一个dump转储 线程,用于向其发送二进制事件日志
4)salve从节点接收到二进制事件日志保存到自己本地的中继日志文件中
5)salve从节点会启动一个sql 线程,从中继日志中读取二进制日志,在本地重放,进而保证数据一致性
6)最后检测是否有改动的io线程,与salve中读取中继日志文件的sql线程会进入休眠状态,等待下次被唤醒
一主一从常见配置
mysql四种同步方式
- mysql有四种同步方式:
- 同步复制
- 半同步复制
- 异步复制
- 增强半同步复制、无损复制
- 同步复制:主库将更新写入Binlog日志文件后,需要等待数据更新已经复制到从库中,并且已经在从库执行成功,然后才能返回继续处理其它的请求。同步复制提供了最佳安全性,保证数据安全,数据不会丢失,但对性能有一定的影响
- 半同步复制:写入一条数据请求到master,从服务器只要有一台接收到写入自己的中继日志,会给客户端返回一条接收成功的信息, 然后主库才能再继续处理其它请求, 该方式能够确保至少有1个从库接收
- 半同步复制,是最佳安全性与最佳性能之间的一个折中, MySQL 5.5版本之后引入了半同步复制功能,主从服务器必须安装半同步复制插件,如果等待超时,超过rpl_semi_sync_master_timeout参数设置时间默认为10秒,则关闭半同步复制,并自动转换为异步复制模式,当master dump线程发送完一个事务的所有事件之后,如果在rpl_semi_sync_master_timeout内,收到了从库的响应,则主从又重新恢复为增强半同步复制
- 异步复制:主库将更新写入Binlog日志文件后,不需要等待数据更新是否已经复制到从库中的结果,可以继续处理更多的请求。在异步复制的机制的情况下,如果Master宕机,事务在Master上已提交,但很可能这些事务没有传到任何的Slave上。假设有Master->Salve故障转移的机制,此时Slave也可能会丢失事务
- 增强半同步复制、无损复制: 是在MySQL 5.7引入,和半同步不同的等待ACK时间不同
rpl_semi_sync_master_wait_point = AFTER_SYNC(默认)
- 半同步的问题是因为等待ACK的点是Commit之后,此时Master已经完成数据变更,用户已经可以看到最新数据,当Binlog还未同步到Slave时,发生主从切换,那么此时从库是没有这个最新数据的,用户看到的是老数据。
- 增强半同步将等待ACK的点放在提交Commit之前,此时数据还未被提交,外界看不到数据变更,此时如果发送主从切换,新库依然还是老数据,不存在数据不一致的问题
并行复制
- MySQL 5.6 版本之前,只支持单线程复制,解决高并发下,串行复制出现的延迟问题,5.6 引入了多个 SQL 线程的概念 ,可以并发还原数据
- 在并行复制时由 slave_parallel_workers 配置并行的worker线程数,在分发请求时,有一定的规则
- 更新同一行的两个事务,必须被分发到同一个 worker 中(避免更新覆盖)
- 同一个事务不能被拆开,必须放到同一个 worker 中(保证事务隔离性)
- 分发策略
- 按表分发策略:如果两个事务更新不同的表,可以并行,两个表并发时不会操作同一条数据, 按表分发的方案,缺点:如果碰到热点表,比如所有的更新事务都会涉及到某一个表的时候,所有事务都会被分配到同一个 worker 中,就变成单线程复制了。
- 按行分发策略:如果两个事务没有更新相同的行,则它们在备库上可以并行。这个模式要求 binlog 格式必须是 row。
该方式解决了热点表的问题,并行度更高,缺点: 相比于按表并行分发策略,按行并行策略在决定线程分发的时候,需要消耗更多的计算资源
- MySQL 5.6 版本,基于 Schema 支持了按库并行
- MySQL 5.7 引入了基于组提交group commit机制并行复制,因为能够在同一组里提交的事务,一定不会修改同一行(由于 MySQL 的锁机制)因为事务已经通过锁冲突的检验了,参数 slave_parallel_workers 设置并行线程数,由参数 slave-parallel-type 来控制并行复制策略:
- 配置为 DATABASE,表示使用 MySQL 5.6 版本的按库并行策略;
- 配置为 LOGICAL_CLOCK,表示使用基于组提交的并行复制策略
- 基于组提交的并行复制具体流程
- 在一组里面一起提交的事务,有一个相同的 commit_id,下一组就是 commit_id+1;commit_id 直接写到 binlog 里面;
- 传到备库应用的时候,相同 commit_id 的事务分发到多个 worker 执行;
- 这一组全部执行完成后,coordinator 再去取下一批执行。
- binlog 的组提交的两个有关参数,这两个参数是用于故意拉长 binlog 从 write 到 fsync 的时间,以此减少 binlog 的写盘次数,在 MySQL 5.7 的并行复制策略里,它们可以用来制造更多的“同时处于 prepare 阶段的事务”。可以考虑调整这两个参数值,来达到提升备库复制并发度的目的
- binlog_group_commit_sync_delay 参数,表示延迟多少微秒后才调用 fsync 刷盘;
- binlog_group_commit_sync_no_delay_count 参数,表示累积多少次以后才调用 fsync
主从复制总结
- 为了提高并发量通常会对数据库进行主从架构设计
- 主库在对数据进行增删改操作时,mysql除了处理数据以外还会记录一个biniog日志
- 从库连接主库,主库后台会开启一个IO线程连接从库,在通过主库对数据进行增删改操作时,会记录biniog日志,主库通过io线程读取biniog日志,发送给从库,从库接收biniog日志信息将数据写入relay日志中,从库中开启SQL线程读取relay日志,将数据写入库中,进而做到数据同步,
- 从库读取biniog到日志后有biniog日志数据加载到relay日志中,由relay日志将转换为数据的整个过程是串行化同步的,由于主库接收请求操作是并行的,而从库是串行的,高并发下可能会出现主库接两个操作数据的请求,从库只能同步处理一个,从库数据与主库数据出现延迟问题, 测试发现,主库并发达到1000/s时,从库与主库会有几毫秒的延迟,主库并发达到2000/s时延迟可能会增加到几十毫秒
- 主从数据延迟过高可能产生的问题: 假设当前请求数据库插入一条数据,由于主从同步延迟问题,在插入数据后,同步到从库以前,发生读请求打到从库上,查询数据为空(一般很少出现,通常情况下的主从延时问题体现是代码层面,插入数据后,很短时间内接着又查询该数据,通过从库发现查询为空,通过 Seconds_Behind_Master 命令可以查看从库落后主库的毫秒数)
- mysql 5.7以后从库支持多线程SQL,每个线程连接一个主库,提高同步主库数据的效率,在一定程度上减少主从数据同步的延迟,但是并不能实际解决掉主从延迟问题
- 重点解决主从同步延迟:
- 增加主库服务器,减少并发,开启从库的多IO线程,多SQL线程,也就是并行复制
- 代码层面,减少插入数据后很短时间内接着查询的操作,一般插入成功后接着查询没有太大的意义
- 必须要有插入成功后的很短时间内接着查询的操作,设置该查询直连主库,通过主库获取数据
- 一主多从架构,减轻从库压力
- 判断主备无延迟方案,例如判断 seconds_behind_master 参数是否已经等于 0
- mysql防止主库接收写请求后再数据同步到从库过程中,主库宕机,自动将从库提升为写库,造成的数据丢失问题,开启semi-sync半同步复制,就是说当主库接收写请求时,强制立即将数据进行同步,至少有一台从库通过biniog日志将数据写入relayr中,此次执行的写请求才会响应成功
- mysql支持同步复制, 半同步复制, 异步复制, 增强半同步复制四种复制方案,其中半同步复制是最佳安全性与最佳性能之间的一个折中, MySQL 5.5版本之后引入了半同步复制功能,主从服务器必须安装半同步复制插件,如果等待超时,超过rpl_semi_sync_master_timeout参数设置时间默认为10秒,则关闭半同步复制,并自动转换为异步复制模式,当master dump线程发送完一个事务的所有事件之后,如果在rpl_semi_sync_master_timeout内,收到了从库的响应,则主从又重新恢复为增强半同步复制, 与增强半同步复制的区别
- 半同步的问题是因为等待ACK的点是Commit之后,此时Master已经完成数据变更,用户已经可以看到最新数据,当Binlog还未同步到Slave时,发生主从切换,那么此时从库是没有这个最新数据的,用户看到的是老数据。
- 增强半同步将等待ACK的点放在提交Commit之前,此时数据还未被提交,外界看不到数据变更,此时如果发送主从切换,新库依然还是老数据,不存在数据不一致的问题
- 什么是并行复制: MySQL 5.6 版本之前,只支持单线程复制,解决高并发下,串行复制出现的延迟问题,5.6 引入了多个 SQL 线程的概念 ,可以并发还原数据,但是5.6版本是基于 Schema 支持了按库并行,粒度较大, MySQL 5.7 引入了基于组提交group commit机制并行复制
- 并行复制时并行的线程数由slave_parallel_workers配置参数决定,并且并行分发时
- 更新同一行的两个事务,必须被分发到同一个 worker 中(避免更新覆盖)
- 同一个事务不能被拆开,必须放到同一个 worker 中(保证事务隔离性)
- 并行分发策略
- 按表分发策略:如果两个事务更新不同的表,可以并行,两个表并发时不会操作同一条数据, 按表分发的方案,缺点:如果碰到热点表,比如所有的更新事务都会涉及到某一个表的时候,所有事务都会被分配到同一个 worker 中,就变成单线程复制了。
- 按行分发策略:如果两个事务没有更新相同的行,则它们在备库上可以并行。这个模式要求 binlog 格式必须是 row。
该方式解决了热点表的问题,并行度更高,缺点: 相比于按表并行分发策略,按行并行策略在决定线程分发的时候,需要消耗更多的计算资源
二. 读写分离
- 数据库写入效率要低于读取效率,一般系统中数据读取频率高于写入频率,单个数据库实例在写入的时候会影响读取性能,这是做读写分离的原因