MySQL主从复制和Redis主从复制有点像, 可以相互对照一下. Redis主从复制
Binary Log日志格式
- STATEMENT
记录每一条会修改数据的SQL语句. 相比ROW来说日志量少, 性能更高, 但在某些特殊情况下会丢失数据, 比如使用sleep()函数等. - ROW
如果是表结构变更, 仍然以STATEMENT格式记录SQL, 对于其他增删改SQL语句, 会将其分解为基于行更改的SQL语句. ROW格式相比STATEMENT格式来说日志量更大, 性能会低一些, 但数据不会丢失. - MIXED
这是STATEMENT和ROW两种格式的结合, 它根据每一条具体的SQL语句来选择使用STATEMENT或ROW.
MySQL主从复制的原理
异步复制
MySQL主从复制默认是异步复制.
- 主库修改数据会记录Binary Log日志, 只有记录Binary Log日志成功后, 事务才能提交.
- 从库接入后会开启一个IO线程, 根据position偏移量从主库的Binary Log日志中拷贝数据.
- 将拷贝过来的数据写入Relay Log中.
- 开启一个SQL线程从Relay Log日志中读取SQL, 然后再执行.
半同步复制
半同步复制是在异步复制的基础上进行优化, 即主库写入binlog日志之后, 会立即将数据同步到从库, 从库将binlog日志写入自己本地的Relay Log之后, 会返回一个ack命令给主库, 主库只有接收到至少一个从库的ack命令之后, 才会认为写操作完成.
半同步复制插件: semisync_master.so
并行复制
并行复制是对异步复制导致的主从同步延时问题的解决方案.
(1) 为什么会产生主从同步延时呢?
主库写入binlog日志是多线程并发执行的, 而从库执行Relay Log日志中的SQL是单线程执行的, 所以当主库的写并发太大时, 就会导致主从同步延时. 解决这个问题的方向就是让从库多线程并发地执行Relay Log日志中的SQL.
并行复制可以基本解决主从同步延迟的问题, 但当主库的写并发太大时, 还是会有延迟, 这时就只能拆分主库了, 降低单库的写并发.
(2) 并行复制的原理
MySQL5.6是基于库的并行复制, 即不同数据库的SQL可以并发地执行, 而MySQL5.7是基于组提交的并行复制, 即同一组的事务可以并发地执行, 我们来看下具体实现.
- SQL层有一个全局的logical clock: commit_clock
- 当事务进入prepare阶段时(执行SQL, 但还未提交), 从commit_clock获取一个逻辑时间保存在binlog中.(last_committed)
- 当事务准备commit之前, 从commit_clock再获取一个逻辑时间保存在binlog中.(sequence_number)
- last_committed - sequence_number能覆盖地就属于同一组(能同时执行说明没有锁冲突)
- 从节点对属于同一组事务的binlog会并发地执行.
如何解决MySQL主库宕机导致的数据丢失情况?
使用半同步复制来解决这个问题.
如何解决主从同步延时的问题?
(1) 主从同步延时的原因
主库写入binlog日志是多线程并发执行的, 而从库执行Relay Log日志中的SQL是单线程执行的, 所以当主库的写并发太大时, 就会导致主从同步延时.
(2) 解决办法
- 并行复制
MySQL5.7开启并行复制后, 主从同步延时问题基本就解决了. - 分库
主从同步延时的根本原因还是主库写并发太高, 我们可以通过分库来降低单库的写并发. - 优化代码
较短时间的主从同步延时是可以接受的, 我们不要写那种insert+select+update式的语句, 即插入一条数据后立即查询, 然后再修改.