MySQL 主从同步 触发复制延迟的测试脚本
我目前正在编写一个脚本,在存在复制滞后时自动启用并行复制/多线程复制 (MTR)。为了测试这个脚本,我需要触发在启用 MTR 后会消失的复制延迟。我为此想出了一个简单的解决方案,我认为它可能对很多人有用,所以我正在写这篇关于它的博客文章。阅读详细信息。
在解释如何触发复制延迟之前,先说一下这个 Auto-MTR 脚本。当存在滞后时运行启用 MTR 的脚本似乎很复杂(它甚至比这更复杂一点,因为一旦滞后消失,脚本也会禁用 MTR)。一个更简单的解决方案可能是一直启用 MTR,但事情并不是那么简单。
遗憾的是,并没有那么稳定,它有时会死锁,这是分页类以恢复复制(为此,我们监控 GTID 的进展,当它卡住时,我们会发出警报)。为了尽量减少对 DBA 的干扰,我们更喜欢仅在需要时使用 MTR(是的,我也可以为此编写一个自愈脚本,但我还没有)。
此外,使用 MTR 运行意味着复制负载监控不起作用(我没有在博客上写过我最近实现的内容,我可能有一天会分享更多关于这个的细节)。如果您还没有实现任何复制负载监控,您应该查看 Mark Leith 的博客文章 A MySQL Replication Load Average with Performance Schema。它的主要思想是使用 SQL 线程中的“空闲时间”来计算复制负载。但是,此计算仅适用于单线程复制。
现在让我们谈谈触发复制延迟。我已经完成了 Auto-MTR 脚本,但我想测试它,这需要复制滞后。我可以使用许多表运行 sysbench
以生成一个 IO 绑定的复制工作负载,其中 sync_binlog = 1
和 innodb_flush_log_at_trx_commit = 1
,但我更喜欢简单的东西。
更简单的解决方案使用基于语句的复制
使用基于语句的复制,副本运行与在主服务器上运行的语句相同的语句。所以如果语句包含一个sleep
,这个sleep
也将在副本上运行,这可以用来触发复制延迟。
所以在创建这个表之后:
CREATE TABLE t(id INT AUTO_INCREMENT PRIMARY KEY, v DOUBLE, d DATETIME);
并在其中插入几行(以下是在简短语句中在表中插入 10 行的技巧):
INSERT INTO t (v, d) SELECT 1, NOW() FROM information_schema.INNODB_METRICS LIMIT 10;
我运行此脚本来生成复制滞后:
while sleep 1; do for i in $(seq 1 10); do
mysql $schema <<< "
SET binlog_format = STATEMENT;
UPDATE t SET v = SLEEP(0.2), d = now() WHERE id = $i" &
done; done
所以现在,我在副本上有复制滞后,但还没有办法通过启用 MTR 来消除滞后。为了能够消除副本上的滞后,我需要并行运行sleep
。为此,我需要调整主节点以确保上面的 UPDATE 语句可以在副本上并行运行。为此,我使用减慢主节点来加速副本(我在最近的 Percona Live MTR 演讲和博客文章 A Metric for Tuning Parallel Replication in MySQL 5.7 中提到了这种调整,但由于这篇文章很旧,所以那篇文章将其称为Slowing Down the Master [sic] to Speed-Up the Slave [sic]). 。为了启用这种调整,我在主服务器上运行它:
SET GLOBAL binlog_group_commit_sync_delay = 50000;
如上所述设置变量 binlog_group_commit_sync_delay
后,MySQL 等待 50 毫秒(变量以微秒为单位)等待事务加入同一个提交组。由于来自同一提交组的自动提交事务可以在副本上并行运行,因此 UPDATE
语句将能够在此更改后并行运行。因此,要处理人为生成的延迟,我只需将 slave_parallel_workers
设置为 10(或更多),我的脚本在检测到延迟时正在执行此操作(slave_parallel_type 之前应该设置为 LOGICAL_CLOCK 和 slave_preserve_commit_order 为 ON,正如我在我的 Percona 中解释的那样,这已经在我工作的环境中完成)。
此脚本的一些变化是:
- 运行更多更新以更快地生成更多滞后(增加
seq 1 10
中的 10,这也需要表中的更多行), - 在启用 MTR 后减少
sleep
(SQL SLEEP(0.2) 而不是sleep 1)以在启用 MTR 后更快地赶上滞后(这也需要更多的工作人员), - 保持更新次数和 SQL sleep延迟的乘积(乘积)高于 1(与 while 的sleep 1 相关),因此脚本在单线程复制中运行时会不断产生复制滞后。