目录
- 备库为什么要设置为只读模式?
- 备库设置为只读,如何与主库保持同步更新?
- A到B的内部流程如何?
- binlog内容是什么?
- `row`格式对于恢复数据有何好处
- M-M结构的循环复制问题以及解决方案
备库为什么要设置为只读模式?
有这样几点考虑:
1、有时候一些运营类的查询语句会被放到备库上去查,设置为只读可以防止误操作
2、防止切换逻辑有bug,比如切换过程中出现双写( 同时写两个库(A、B )),造成主备不一致
3、可以用 readonly
状态,来判断节点的角色
备库设置为只读,如何与主库保持同步更新?
readonly
的设置对于super权限用户是无效的。用于同步的线程,就拥有super权限。
A到B的内部流程如何?
主库接收到客户端的更新请求后,执行内部事务的更新逻辑,同时写binlog;
备库B与主库A之间维持一个长连接。主库内部有一个线程,专门用于服务备库B这个长连接。
一个事务日志同步的完整过程:
1、备库B通过change master
命令,设置主库A的IP、端口、用户名、密码,以及请求binlog的起始位置(文件名+日志偏移量)
2、备库B执行start slave
命令,备库启动两个线程io_thread
、sql_thread
。io_thread
负责与主库建立连接
3、主库A校验完用户名、密码后,按照备库B传过来的起始位置,读取本地的binlog然后发给备库B
4、备库B拿到binlog后,写到本地文件,称为中转日志(relay log)
5、sql_thread
读取中转日志relay log ,解析日志里的命令,并执行
binlog内容是什么?
在解释内容之前,需要知道binlog的格式。
binlog有三种格式:statement
、row
、mixed
statement
binlog_format=statement
时,binlog 里面记录的就是 SQL 语句的原文
statement格式的binlog的缺陷有个缺陷:
主备使用的索引可能是不一致的,最终导致执行删除时删除的数据不一致。
**row **
row 格式的 binlog 里没有了 SQL 语句的原文,而是替换成了两个 event: Table_map
和Delete_rows
.
1、 Table_map
, 用于说明操作的表是test库的表t
2、Delete_rows
, 用于定义删除的行为
当binlog_format = row
,binlog里面记录了真实删除行的主键id,这样binlog传到备库去的时候,肯定不会出现主备删除不同行的问题
mixed
mixed格式用于哪些场景呢?
statement
格式可能会导致主备不一致,所以要使用row
格式
row
格式比较占空间,同时也更要耗费IO资源,影响执行速度
所以采用这种方案,采用mixed
格式,MySQL自己会判断这条SQL语句是否可能引起主备不一致,如果可能,使用row
格式,否则使用statement
格式。
row
格式对于恢复数据有何好处
现在,越来越多场景要求使用row
格式的binlog,可以从delete、insert、update三种sql语句角度看待这个问题。
使用delete语句,row
格式会把被删除的行的整行信息保存。所以删错之后,只需要把binlog记录的delete语句转成insert就能恢复了。
使用insert语句,row
格式会记录所有的字段信息。所以插入错误的时候,只需要把binlog记录的insert语句转成delete语句就能恢复了。
使用update语句,binlog会记录修改前整行的数据和修改后的整行数据。所以如果update误执行,只需要把event前后的两行信息对调,再去数据库执行,就能恢复数据了。
M-M结构的循环复制问题以及解决方案
图1是M-S结构,但是现在常用的是M-M结构,M-M结构区别在于:节点A与节点B总是互为主备关系,所以在切换的时候就不用修改主备关系了。
M-M存在循环复制问题:
在节点A更新一个语句,把生成的binlog发给节点B。
节点B执行完更新语句后也会生成binlog。
如果A同时为B的备库,A会把节点B新生成的binlog拿过去执行。节点A和B之间会不断循环执行这个更新语句。
解决方案:
已知MySQL在binlog中记录了命令第一次执行所在实例的server id。
1、规定两个库的server id 必须不同。若相同,则不能设定为主备关系
2、备库接到binlog,生成与原binlog的server id相同的新的binlog
3、每个库在收到从自己的主库发过来的日志后,先判断server id,如果和自己的相同,表示这个日志是自己生成的,丢弃这个日志。
所以使用M-M结构的日志执行流程如下:
1、从节点A更新的事务,binlog里记录的都是A的server id
2、传到节点B执行一次后,节点B生成的binlog的server id 也是A的server id
3、再传给节点A,A判断这个server id与自己的相同,不处理这个日志