• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

关于MySQL复制中server_id的研究

MySQL 彭东稳 4年前 (2018-04-12) 20103次浏览 已收录 0个评论

做过 MySQL 主从复制的同学都知道,主从复制能够有效工作的一些基本原则,如下:

  • master 必须开启 binlog,这是主从复制能够工作的基本要求,slave 需要同步 master 的 binlog 进行回放来同步数据。
  • master 和 slave 实例都需要设置 server_id,且不能相同,否则复制会报错;同一个复制集群中必须保证 server_id 唯一。
  • 每个 master 可以有多个 slave,从 MySQL 5.7 开始支持多源复制,允许单个 slave 有多个 master。
  • slave 开启 binlog,并设置 log_slave_updates 参数,其可以作为其他它 slave 的 master,从而扩散 master 的更新,这种复制方式被称为联级复制。

这几个基本原则都比较容易理解,对于 master 和 slave 实例都需要设置 server_id,且不能相同,和同一个复制集群(指各种复制拓扑)必须保证 server_id 唯一。这点就有问题可以思考了,大概总结如下。

1. master 与 slave 的 server_id 不能相同,主要是 slave 要依靠 server_id 来决定是否执行事件

在双主复制结构中,master 发生数据更新,会在 binlog event 的 header 中存储 server_id,然后发送到 slave。

然后 slave 的 io 线程通过读取到 event 拿到 server_id,判断此 server_id 与自己的 server_id 是否相同,相同则丢弃,否则记录 event 到 relay log。然后通过 sql 线程回放 event 并记录到 binlog 中,这里记录的 event 是 master 的 binlog event,也就是说其 server_id 是 Master 的,而不是 Slave 的。

slave 会将 binlog event 通过 dump 线程又发送给 master,因此最初 master 上执行的 binlog event 又传了回来,同样 master 通过读取 event header 中存储的 server_id,判断与自己的 server_id 是否一致,相同则丢弃,否则记录 event 到 relay log。

在这个过程中,如果 master 记录的 binlog event 的 server_id 与 master&slave 的 server_id 都不相同,则该 binlog event 则在 master&slave 中无限循环执行,也就是通常所说的复制风暴。最简单产生这种问题的架构 M -> (MS <-> MS)。

2. 当 Master 有多个 Slave 时,那么如何来区分这些 Slave 呢?

MySQL 5.6 版本之前就需要用到 server_id。

我们首先看看一个 slave 向 master 请求二进制时会发生什么?首先 slave 会向 master 发送一个 COM_BINLOG_DUMP 命令,会带上自己的 server_id 和 binlog filename & position 信息。然后 master 会调用 kill_zombie_dump_threads 函数,这个函数会遍历 MySQL 中的所有线程,如果遍历到一个线程是 dump 线程并且线程的 server_id 是等于 slave 的 server_id,则跳出遍历循环,并对 kill 掉这个线程。

但 MySQL 5.6 版本时,因为有了 uuid 的概念,所以 kill_zombie_dump_threads 函数逻辑也变动了,会先调用 get_slave_uuid 函数获取 slave uuid,然后同样会遍历 MySQL 中的所有线程,但如果找到 dump 线程时,首先看一下这个线程有没有 uuid 字段(兼容 <MySQL 5.6 版本),如果有 uuid 字段并且 slave 的 uuid 不为空,则进行比较,否则用 server_id 进行比较。

事实上,如果 slave 停止了,而 Binlog_dump 线程正在等待(mysql_cond_wait)binlog 更新,那么它将一直存在,直到有查询被写入 binlog。如果 master 是空闲的,那么这可能会持续很长时间,如果 slave 重新连接,就可能会有 2 个 Binlog_dump 线程。为了避免这种情况,当 slave 重新连接并发送 COM_BINLOG_DUMP,master 会杀死任何带有 slave 的 uuid/server_id 的现有线程(如果这个 id 不是零的话;对于真正的 slave 来说,它将是真的,但对于 mysqlbinlog 来说,当它发送 COM_BINLOG_DUMP 以获得远程 binlog 时,它是假的)。

结论就是在一个复制集群中,必须保证 server_id 都唯一,避免可能会有一些不可预知的错误。

<参考>

MySQL中server_id一致带来的问题

MySQL多个Slave同一server_id的冲突原因分析


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (0)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!