暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

[译文] 将 MySQL 二进制日志流式传输到 S3(或任何对象存储)

原创 Peter Boros 2021-08-26
1894

问题陈述

如今,备份二进制日志是相当正常的。异地复制的最新二进制日志越多,实现的 RPO(恢复点目标)就越好。最近有人多次问我是否可以采取措施将二进制日志尽可能实时地“流式传输”到 S3。不幸的是,没有现成的解决方案可以做到这一点。在这里,我展示了可以做什么,并展示了一个不适合生产使用的概念实现证明。

image.png

在此示例中,实例有两个二进制日志文件(mysql-bin.000001 和 mysql-bin.000002)已经关闭,并且正在写入 mysql-bin.000003。备份这些二进制日志文件的一个简单解决方案是只备份关闭的文件(未写入的文件)。二进制日志文件的默认大小为 1 GB。这意味着使用此解决方案,我们将在最坏的情况下不备份 1 GB 的二进制日志。平均而言,我们将有 500M 二进制日志未备份。通过降低 max_binlog_size 参数可以使这些数字更好,但这会导致大量文件和频繁轮换。

上传到对象存储

可以使用分段上传将文件分块上传到 S3 。有了这个,文件可以分块上传,最小块大小为 5 MB。这意味着 binlog 可以在写入时被另一个进程读取,并以 5 MB 的块上传到 S3。这绝对比 500 MB 的文件复制或将 max_binlog_size 设置为 5M 好。我们的备份解决方案可以做的另一件事是在将二进制日志上传到 S3 之前将它们流式传输到远程位置。

image.png

分段上传完成后,这些块会在 S3 上再次组装在一起。

mysqlbinlog 命令生成的文件可以读取,如果我们有 5M,它们可以上传到 S3。分段上传的最后一个块可以小于 5M。有了这个,就可以保证文件可以上传。文件在写入时分块读取。

概念实施证明

概念验证的流程如下。

  • 启动 mysqlbinlog 进程以将备份流式传输到临时目录。这是在后台。
  • 以块的形式读取临时目录中的文件。可能会发生 read() 调用返回的数据少于 5MB。为了处理这种情况,有一个用于读取调用的缓冲区。如果缓冲区达到分段上传的最小块大小(5M),我们将上传它。这意味着可能会发生 4.5M 已经读取到缓冲区的几个小读取,并且下一个 read() 调用将能够读取 5M。在这种情况下,该块的大小将为 9.5M。这完全没问题,块的大小可以是可变的。目标是尽快上传数据,因此最好在一个请求中完成。这意味着在这个概念验证实现中,块大小将在 5M 到 10M 之间。
  • 一旦到达文件末尾,无论大小如何都会上传最后一部分,并且文件将被关闭,接下来将读取下一个文件的块。分段上传的最后一部分可以小于 5M。文件完整上传到 S3 后,会从本地临时目录中删除该文件。因此,本地临时目录包含正在上传或尚未开始上传的文件。
  • 如果读取器在最后一个未关闭的文件上,它只会等待更多数据,当缓冲区填满时,它将继续上传部分。

示例

在这个例子中,我有一个带有两个二进制日志的服务器:

mysql> show binary logs; +------------------+-----------+-----------+ | Log_name | File_size | Encrypted | +------------------+-----------+-----------+ | mysql-bin.000001 | 105775625 | No | | mysql-bin.000002 | 85147151 | No | +------------------+-----------+-----------+ 2 rows in set (0.00 sec)

为方便起见,max_binlog_size 为 100M。

$ binlog2s3 --binary /usr/local/bin/mysqlbinlog --hostname db1.172.17.17.12.nip.io --port 3306 --username repl --password repl --start-file mysql-bin.000001 --tempdir /Users/pboros/tmpdir --bucket_name pboros-binlogtest Waiting for binlog files to appear 2021-07-01 17:45:41.672730 Creating multipart uploader for mysql-bin.000001 2021-07-01 17:45:42.460344 Uploading part 1 for mysql-bin.000001 size 5242880 2021-07-01 17:45:51.465913 Uploading part 2 for mysql-bin.000001 size 5242880

临时目录包含二进制日志:

$ ls -la total 372896 drwxr-xr-x 4 pboros staff 128 Jul 1 17:45 . drwxr-xr-x+ 73 pboros staff 2336 Jun 30 18:04 .. -rw-r----- 1 pboros staff 105256799 Jul 1 17:45 mysql-bin.000001 -rw-r----- 1 pboros staff 85663391 Jul 1 17:45 mysql-bin.000002

在这种情况下,从一开始就流式传输二进制日志比将它们上传到 S3 快得多(因为我是从本地虚拟机流式传输的,而我是通过家庭互联网连接上传到 S3)。

很快就会上传二进制日志:

2021-07-01 17:48:23.865630 Uploading part 19 for mysql-bin.000001 size 5242880 2021-07-01 17:48:33.350739 Uploading part 20 for mysql-bin.000001 size 5242880 2021-07-01 17:48:41.708166 Uploading part 21 for mysql-bin.000001 size 399199 2021-07-01 17:48:42.160303 Finishing multipart upload for mysql-bin.000001 2021-07-01 17:48:42.407308 Creating multipart uploader for mysql-bin.000002 2021-07-01 17:48:43.521756 Uploading part 1 for mysql-bin.000002 size 5242880 2021-07-01 17:48:52.517424 Uploading part 2 for mysql-bin.000002 size 5242880

第 17 部分会更大,因为从有新二进制日志到新数据可用时,它的缓冲区不到 5M。除此之外,它还可以读取额外的 5M。

$ ls -la total 593496 drwxr-xr-x 5 pboros staff 160 Jul 1 17:52 . drwxr-xr-x+ 73 pboros staff 2336 Jun 30 18:04 .. -rw-r----- 1 pboros staff 105267370 Jul 1 17:52 mysql-bin.000002 -rw-r----- 1 pboros staff 105255295 Jul 1 17:52 mysql-bin.000003 -rw-r----- 1 pboros staff 66061395 Jul 1 17:52 mysql-bin.000004
$ aws s3 ls s3://pboros-binlogtest/ 2021-07-01 17:45:43 105256799 mysql-bin.000001 2021-07-01 17:48:43 105267370 mysql-bin.000002

上传的部分可以通过 S3 API 访问(并且它们可以组装成二进制日志):

$ aws s3api list-multipart-uploads --bucket pboros-binlogtest

S3 存储桶可以有一个策略来定期自动删除未完成的分段上传(例如,超过 7 天的未完成分段上传)。

概念验证代码可在 https://github.com/pboros/binlog2s3 获得。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论