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

【译】MyDumper的数据流执行

原创 QIU飞 2022-06-23
518

原文链接:https://www.percona.com/blog/mydumper-stream-implementation/
作者:David Ducos

您可能知道mysqldump 是单线程的,而 STDOUT 是其默认输出。由于 MyDumper 是多线程的,它必须写入不同的文件。由于 0.11.3 版本于 2021 年 11 月发布之后,我们可以在 MyDumper 中流式传输我们的备份。我们思考了几个月,直到我们确定了实现它的最简单方法,并且我们还必须添加对压缩的支持。所以,在修复了几个错误之后,我们现在认为它已经足够稳定了,我们可以解释它是如何工作的。

如果 MyDumper 是多线程的,您如何进行流式传输?

接收流对于 myloader 来说不是问题,它一次接收一个文件并将其发送到一个线程来处理它。但是mydumper 中的每个工作线程都连接到数据库,并且一旦读取数据,就应该将其发送到流中,这可能会导致与正在从数据库读取数据的其他工作线程发生冲突。为了避免这个问题,我们最终得到了最简单的解决方案:mydumper 将进行备份并将其存储在您配置的本地文件系统中,文件名将入队以由弹出一个 Stream Thread 处理一次文件并通过管道传输到标准输出。我们研究了在转储文件时发送文件块的替代方案,但我们实现的方式更简单并提高了整体性能。

实施细节

这是我们如何实现它的高级图表:
1.png

当 mydumper 工作线程处理作业时,它会连接到数据库并将输出存储到文件中。这没有改变,使用流,我们将文件名推送到 mydumper stream_queue。

mydumper Stream Thread 正在从 mydumper stream_queue 中弹出文件名,它将文件头发送到 stdout,然后打开文件并发送其内容。

然后,myloader Stream Thread 接收并检测标题,它将使用标题中的文件名创建新文件并将内容存储在其中。

关闭文件后,它会将文件名排入 myloader 的 stream_queue 中。 myloader 工作线程将获取该文件并根据文件的类型对其进行处理。

默认情况下,文件会被删除,但如果要保留它们,可以使用 –no-delete 选项。

标头只是简单地将 - 添加到文件名,因此您可以使用 myloader 或 mysql 客户端导入数据库。这是一个例子:

-- sbtest-schema-create.sql
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `sbtest` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

-- sbtest.sbtest1-schema.sql
/*!40101 SET NAMES binary*/;
/*!40014 SET FOREIGN_KEY_CHECKS=0*/;

/*!40103 SET TIME_ZONE='+00:00' */;
CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  `pad2` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100010 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- sbtest.sbtest1.00000.sql
/*!40101 SET NAMES binary*/;
/*!40014 SET FOREIGN_KEY_CHECKS=0*/;
/*!40103 SET TIME_ZONE='+00:00' */;
INSERT INTO `sbtest1` VALUES(1,49929,"83868641912-28773972837-60736120486-75162659906-27563526494-20381887404-41576422241-93426793964-56405065102-33518432330","67847967377-48000963322-62604785301-91415491898-96926520291","")
…
复制

简单用例

线程写入单个文件以避免冲突,从而提高性能。但是,拥有数千个文件来备份几个表是不可管理的。因此,最简单的用例是将所有内容发送到单个文件:

mydumper -B <SCHEMA_NAME> -h <FROM> > filename.sql
复制

然后您可以使用以下方法简单地导入它:

myloader --stream -o -h <TO_SERVER> < filename.sql
复制

现在您可以从 mydumper 进程通过管道传输到 myloader,可以执行以下操作:

Shell
mydumper -B <SCHEMA_NAME> -h <FROM> | myloader --stream -o -h <TO>
1
mydumper -B <SCHEMA_NAME> -h <FROM> | myloader --stream -o -h <TO>
复制

2.png
或者您可以使用 nc 通过网络发送流:

mydumper -B <SCHEMA_NAME> -h <FROM_SERVER> | nc <MYDUMPER_SERVER> <ANY_PORT>
nc -l <MYDUMPER_SERVER> <ANY_PORT> | myloader --stream -o -h <TO_SERVER>
复制

3.png
此实现使用 mydumper 和 myloader 上的备份目录作为缓冲区,您必须考虑到这一点,因为默认情况下它将创建一个运行它的目录。

您需要考虑的另一件事是 mydumper 和 myloader 将写入磁盘,整个备份将在处理时写入两个文件系统,并使用具有足够磁盘空间的文件系统。

最后,您可以保持 myloader 运行并发送多个 mydumper 备份。首先,您需要运行:

nc -k -l <MYDUMPER_SERVER> <ANY_PORT> | myloader --stream -o -h <TO_SERVER>
复制

然后执行:

mydumper -B <SCHEMA_NAME_1> -h <FROM_SERVER> | nc <MYDUMPER_SERVER> <ANY_PORT>
mydumper -B <SCHEMA_NAME_2> -h <FROM_SERVER> | nc <MYDUMPER_SERVER> <ANY_PORT>
mydumper -B <SCHEMA_NAME_3> -h <FROM_SERVER> | nc <MYDUMPER_SERVER> <ANY_PORT>
mydumper -B <SCHEMA_NAME_4> -h <FROM_SERVER> | nc -N <MYDUMPER_SERVER> <ANY_PORT>
复制

某些版本的 nc 有以下两个选项:

  • k 当一个连接完成时,监听另一个。需要-l。

  • N shutdown(2) 输入 EOF 后的网络套接字。一些服务器需要这个来完成他们的工作。

如果您正在刷新一些测试环境并且只需要不同数据库上的几个表,或者如果您使用仅适用于某些表的 where 子句,这将非常有用。

注意事项
通常,当您将数据发送到 STDOUT 时,您不会遇到转储服务器上的磁盘空间使用问题。如果您使用的是 MyDumper,情况则会不一样。文件将存储在 mydumper 服务器上,直到它们被传输到接收服务器。例如,如果您有一个 10TB 的数据库,与磁盘带宽相比,网络带宽非常低,您最终可能会填满临时保存文件的磁盘。

结论
我们专注于实施以加快进出口流程。与其他软件或实现相反,我们将文件系统用作缓冲区,从而导致更高的磁盘利用率。

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

评论