我工作中的一个项目涉及Vitess和VReplication。我最近做了一次深入的研究,以弄清楚VReplication是如何工作的,以及它的可扩展性瓶颈在哪里。以下是我的笔记,我认为值得与社区分享。
什么是VReplication?总结其文档,它是一个让你从一个数据库复制和维护一个实时数据子集到另一个数据库的工具--类似于Shopify的Ghostferry,但为Vitess的世界量身定做,并在其之上有一个协调层。
VReplication是Vitess的一个核心组件,支持它的许多功能,但它的代码究竟在哪里运行?
-
每当你通过执行SQL语句(如
INSERT INTO _vt.vreplication (db_name, source, pos, ...))创建一个VReplication流时,作为流的目的地的VTTablet将为每个流创建多个goroutine。 -
一个goroutine来管理流。如果你从外部将流的状态更新为 "停止",这个程序将停止复制。
-
一个goroutine,通过GRPC从源头获取binlog事件。
-
一个goroutine来应用取来的binlog事件
-
一些用于管理HTTP2/GRPC连接的goroutines
在一个VTTablet上运行着152个流,我观察到每个流有11个goroutine在运行,因此有1672个goroutine来管理152个流。
VTTablet在流的目的方的Go进程最终会成为一个瓶颈,以运行超过一个Go进程所能处理的流。你可能要在多个目的地上划分流,以实现非常多的流(在我的例子中,必须是数万个流的规模)。
初始拷贝的性能
过于简化,VReplication的生命周期由两部分组成:初始拷贝(SELECT + INSERT)和来自binlog的持续数据流。
重要的是,对现有行的初始拷贝(相对于从binlog的流)需要合理的时间。为了确定这一点,我用500万行填充了一个表,每行大约有13Kb大小--总共有65Gb。
我观察到该表需要90分钟来复制这65Gb。
[14:18:31 vcopier.go:201] Copying table orders, lastpk: <nil>
[15:49:11 vcopier.go:328] Copy of orders finished at lastpk: map[lastpk:type:VARBINARY value:"fields:{name:\"tenant_id\" type:INT64} fields:{name:\"id\" type:INT64} rows:{lengths:3 lengths:7 values:\"1004893000\"}"]
提示:vttablet日志包含表开始/完成复制的时间戳。
$ kubectl logs production-vttablet-zone1-0428408676-c778c4e9 -f -c vttablet
请注意,VTTablet自带的vstream_packet_size ,建议调整该设置以增加复制的吞吐量。它越小,我们将在vstreamer和vcopier之间看到更多的来回gRPC流量:这些将是更多的从源头到目的地的数据批次(更小的批次)的发送。我用vstream_packet_size = 500’000 ,这是默认值的两倍,进行了我的测试。这大大增加了小于5M的数据集的复制速度。
90分钟复制65Gb是~722Mb/min,或12Mb/sec,这甚至没有接近网络或磁盘带宽限制。瓶颈可能还是在Vitess抽象之间或GRPC中。
必须指出的是,Vitess是以串行方式复制属于同一数据流的表,这意味着两个65Gb的表需要180分钟来复制,而不是90分钟。考虑到我们想要复制大量的表,而且可以并行完成,这似乎真的很浪费。我们可能必须改变VReplication的这部分行为。
binlog流的性能
在VReplication完成复制现有的行后,它将开始流式处理binlog以捕获实时变化。你可以指定你希望VReplication从主站还是从副本进行流式传输。从主站复制的好处是没有复制滞后,这也是我最初尝试的方法。我观察到,(正如预期的那样)它复制的数据没有滞后,而复制的数据却滞后了几个小时。但是,超过50~的复制流,似乎对主站的负载太大,而将Replication改为从副本中流出来,显示出更好的可扩展性--主要是因为你可以向它扔更多的副本。然而,目的地的数据和副本本身一样滞后。
最终,我能够把它推到多达400个流而不中断,处理一个吞吐量为330 mb/s的binlog。用VReplication复制的数据并没有比副本本身延迟更多,这说明Go堆栈能够跟上330 mb/s的binlogs。
工具
作为实验的一部分,控制许多VReplication流是很棘手的,因为管理它的CLI工具大多是为机器设计的,而不是为人设计的。Vitess的文档甚至推荐了一个很小的Go程序,可以生成shell命令来启动VReplication。
为了管理我的实验,我写了一个潦草的Ruby脚本,让我能够列出、创建和删除数据流,而不需要制作和转义SQL语句。欢迎在你的项目中使用它!