Galera 4 Streaming Replication in Percona XtraDB Cluster 8.0
我正在测试最新的Percona XtraDB Cluster 8.0 (PXC)版本, 其中包含了Galera 4插件, 我想分享一下到目前为止我在Streaming Replication特性方面的经验和想法,
What Is Streaming Replication, in One Sentence?
在Galera 4中, 大型事务可以分割成更小的片段, 甚至在提交之前, 这些片段就已经被复制到其他节点, 并且已经开始了认证(certification)和应用(apply)过程.
手册描述了所有的优点和缺点, 但是让我们看看它是如何工作的. 我已经创建了一个包含1千万行的表, 我将在这个表上运行一些大的update语句,
首先, 我在不使用Streaming Replication的情况下运行更新, 由于默认情况下Streaming Replication是disabled, 所以我们不需要做任何事情, 只需运行更新即可. 在node1
上, 我记录更新之前和之后的时间, 在node2
上, 我每秒钟运行一次select, 以查看这个更新在其他节点上实际提交的时间.
On the writer:
1 | node1-T1 mysql> select now();update sbtest1 set k=1 where id < 1000000;select now(); |
运行和这个update语句花费了大约34秒
Check the other node:
1 | +---------------------+ |
正如我所说, 我每秒钟都在运行一个查询, 以查看k
何时变为1. node2
花了28秒
的时间来验证、应用和提交这个更新. 重要的是要理解, 当节点正在验证这个大更新时, 任何其他表上的所有其他更改都将被阻塞, 因此该节点将停滞/冻结近30秒.
Will Streaming Replication Decrease This Delay?
理论上, 其他节点应该可以更快地进行更新, 因为当更新在node1
上运行时, 片段(fragments 指事务的部分binlog)已经被复制并应用到其他节点上,
我将把片段大小设置为1MB,
1 | set session wsrep_trx_fragment_size=1048576; |
现在这个更新要跑40s, 我们看看其他节点.
1 | +---------------------+ |
在同一秒内, k
在node2
上也已经是2
了, 我们不再有28秒
的延迟, 这很好, 但是这个uupdate语句本身变慢了一点, 我多次运行这些更新, 在没有Streaming Replication的情况下总是更快, 但是对于大型事务, 我更喜欢流复制, 因为其他节点不会与写节点(执行更新语句的节点)差的太远.
Why Could It Be Slower With Streaming Replication?
其中一个原因可能是, 使用Streaming Replication时, Galera基本上会写两份write-sets.它在mysql.wsrep_streaming_log中记录write-sets, 以确保在发生崩溃的情况下也可以进行Streaming Replication updates.这就是为什么为所有查询启用流复制不是一个好主意的原因.
Does the Fragment Size Matter?
Let’s change the fragment size to 0.1MB:
1 | node1-T1 mysql> set session wsrep_trx_fragment_size=104857; |
现在花了50多秒钟, 因此我们可以看到gragment size很重要. 当我将片段大小增加到100MB时, 我也进行了测试, 在这种情况下, 查询又花了40秒钟左右, 但其他节点需要更多时间才能赶上, 差不多10秒钟左右.
找到正确的片段大小很重要, 在我的测试中1MB是可以接受的, 但是您也可以定义行数, 如每10000行之后创建片段.
Locking
在Galera 4之前, 锁没有传播到其他节点. 如果您在node1
上运行查询, 则InnoDB仅在node1
上锁定了必要的行, 但是node2
和node3
不知道哪些行被锁定. 如果有人在写node2
和node3
, 那么Galera必须处理这些冲突, 基本上是先提交的事务获胜. 如果要在多个节点进行写入, 则可能会有很多冲突.
但随着Streaming Replication的出现, 这种情况也发生了变化.片段被复制到其他节点, 它们也将在那里持有必要的锁.
Let’s see how this works, first without Streaming Replication, step by step.
在node1
和node2
上启动事务, 在node1
上运行大型更新, 在node2
上删除单个行, 然后在node2
上提交事务.当我在node1
上提交时, 我得到一个死锁:
1 | node1-T1 mysql> begin; |
因为没有集群范围的锁定, 所以在本例中, 它将使用乐观锁定, 并在认证过程中获得一个错误.
How Does This Work With Streaming Replication?
Repeat the same steps:
1 | node1-T1 mysql> set session wsrep_trx_fragment_size=1048570; |
同样的步骤, 但是当我们试图在node2
上运行delete时, 它只是hang在那里, 等待获取锁, 但是被来自node1的更新语句产生的锁阻塞了, 这正是因为Streaming Replication.当我在node1
上提交事务时, node2
可以继续运行delete语句了.这可以将我们从许多僵局和冲突中解救出来.查询可能必须等待锁, 但最终它们仍然会完成.
这听起来很好, 但我仍然不建议将Streaming Replication作为默认设置启用, 因为它会影响性能, 而且它会将所有内容重复写入mysql.wsrep_streaming_log表.此外, 如果您想回滚一个大事务, 那么它必须在所有节点上执行, 而不是只在一个节点上执行.
Metrics/Monitoring
有一个表叫做mysql.wsrep_streaming_log
, 其中包含关于当前正在运行的流的信息.
1 | node1-T1 mysql> SELECT node_uuid, trx_id, seqno, flags FROM mysql.wsrep_streaming_log; |
但是要小心, 因为名为frag
的列包含整个二进制日志复制事件, 这个事件可能非常大.在我意识到这一点之前, 我得到了以下错误:
1 | node1-T1 mysql> select * from mysql.wsrep_streaming_log; |
不幸的是, 据我所知, 没有计数器来监视通过Streaming Replication复制了多少语句.为此, 我创建了一个feature request.
Conclusion
到目前为止, Streaming Replication效果很好, 我认为它具有巨大的潜力. 因为我们可以在会话级启用它, 所以您自己或应用程序可以在需要时轻松打开它, but I am also waiting to see real-life experiences with it.