解密 MySQL 的主备一致

MySQL 实现主备一致肯定是 binlog。毫不夸张的说,MySQL 能够成为现在最流行的开源数据库,binlog 功不可没。

MySQL主备的基本原理

主备流程图

解密 MySQL 的主备一致_第1张图片

备库 B 跟主库 A 之间维持了一个长连接。主库 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 读取中转日志,解析出日志里的命令,并执行。

binlog 有三种格式:

  • statement

    当binlog_format=statement 时,binlog里面的记录就是SQL语句的原文,statement 可能会导致主备数据不一致,因为可能两个库用到的索引不一样。

  • row

    row 格式的 binlog 里没有了 SQL 语句的原文,而是替换成了 event,不会导致主备数据不一致。

  • mixed

    statement 和 row 两种格式的混合。 mixed 格式的意思是,MySQL 自己会判断这条 SQL 语句是否可能引起主备不一致,如果有可能,就用 row 格式,否则就用 statement 格式。

优缺点:

  • statement

    • 优点: 占用空间小,益于程序员读

    • 缺点:可能会导致主备数据不一致,因为可能两个库用到的索引不一样

  • row

    • 优点:不会导致主备数据不一致
    • 缺点:很占空间。比如删除一万条语句,statement 往binlog写一句话,row 往binlog写一万条记录。
  • mixed

    • mixed 格式可以利用 statment 格式的优点,同时又避免了数据不一致的风险。

循环复制问题

解密 MySQL 的主备一致_第2张图片
双M结构

业务逻辑在节点 A 上更新了一条语句,然后再把生成的 binlog 发给节点 B,节点 B 执行完这条更新语句后也会生成 binlog。(建议把参数 log_slave_updates 设置为 on,表示备库执行 relay log 后生成 binlog)。

那么,如果节点 A 同时是节点 B 的备库,相当于又把节点 B 新生成的 binlog 拿过来执行了一次,然后节点 A 和 B 间,会不断地循环执行这个更新语句,也就是循环复制了。这个要怎么解决呢?

  1. 规定两个库的 server id 必须不同,如果相同,则它们之间不能设定为主备关系;
  2. 一个备库接到 binlog 并在重放的过程中,生成与原 binlog 的 server id 相同的新的 binlog;
  3. 每个库在收到从自己的主库发过来的日志后,先判断 server id,如果跟自己的相同,表示这个日志是自己生成的,就直接丢弃这个日志。

按照这个逻辑,如果设置了双 M 结构,日志的执行流就会变成这样:

  1. 从节点 A 更新的事务,binlog 里面记的都是 A 的 server id;
  2. 传到节点 B 执行一次以后,节点 B 生成的 binlog 的 server id 也是 A 的 server id;
  3. 再传回给节点 A,A 判断到这个 server id 与自己的相同,就不会再处理这个日志。所以,死循环在这里就断掉了。

你可能感兴趣的:(MySQL,mysql,数据库,sql)