aws rds,在查询期间丢失与 MySQL 服务器的连接,当导入大文件时

aws rds, lost connection to MySQL server during query, when importing large file

我尝试将一个 1.4G mysql 文件导入 aws rds。我尝试了 2 cpu 和 4G 内存选项。我仍然遇到错误:Lost connection to MySQL server during query。我的问题是如何将大 mysql 文件导入 rds.

如果您从本地计算机或笔记本电脑或与 RDS 实例不在同一区域的机器导入,您的连接可能会超时。

尝试从有权访问此 RDS 的 EC2 实例导入。您需要将文件上传到 S3,ssh 到 EC2 实例,然后 运行 导入到 RDS。

MySQL 服务器和 MySQL 客户端都有一个参数 max_allowed_packet.

这是一项安全检查,旨在防止在数据损坏导致连接的接收端认为数据包 1 非常大时可能发生的大量内存的无用和破坏性分配。

传输查询和结果集时,客户端和服务器都不允许发送任何大于max_allowed_packet的单个"thing"(通常是查询或列的值)——发送方会抛出一个错误并拒绝发送,如果你尝试,接收方会抛出一个错误然后关闭你的连接(所以客户端可能会或可能不会实际报告抛出的错误 - 它可能只是报告连接丢失了)。

很遗憾,同一个参数的client setting和server setting是两个独立的设置,不协调。 技术上不要求它们相同,但差异值只有在它们都不超过对方施加的限制时才有效。

更糟糕的是,它们的默认值实际上不同。在最近的版本中,服务器默认为 4 MiB,而客户端默认为 16 MiB。

查找服务器的值 (SELECT @@MAX_ALLOWED_PACKET) 然后设置客户端以匹配服务器 (mysql --max-allowed-packet=max_size_in_bytes) 将 "fix" 神秘的 Lost connection to MySQL server during query 错误消息导致客户端做正确的事情™,而不是尝试发送服务器不会接受的数据包。但是您仍然会收到一个错误 - 只是一个信息量更大的错误。

所以,我们需要将双方重新配置为更合适的东西……但我们如何知道正确的值?

你必须知道你的数据。任何列中的最大可能值是多少?如果这是一个延伸(在许多情况下,它是),您可以根据转储文件中最长的行简单地从一个相当大的值开始。

使用这一行发现:

$ perl -ne '$max = length($_) > $max ? length($_) : $max; END { print "$max\n" }' dumpfile.sql

输出将是文件中最长行的长度(以字节为单位)。

您可能希望将其四舍五入为下一个 2 的幂,或者至少为 1024 的下一个增量(1024 是服务器接受的粒度——值已四舍五入)或任何您认为合适的值,但是这个结果应该会给你一个值,让你可以毫无问题地加载你的转储文件。

既然我们已经建立了一个应该起作用的新值,请将服务器上的 max_allowed_packet 更改为您刚刚发现的新值。在 RDS 中,这是在参数组中完成的。确保该值已应用于您的服务器 (SELECT @@GLOBAL.MAX_ALLOWED_PACKET;)。

然后,您需要将相同的值传递给您的客户端程序,例如mysql --max-allowed-packet=33554432 如果 此值小于默认客户端值。您可以通过以下方式找到默认客户端值:

$ mysql --help --verbose | grep '^max.allowed.packet'
max-allowed-packet                16777216

客户端还允许您以 SI 单位指定值,例如 --max-allowed-packet=32M 表示 32 MiB(33554432 字节)。

这个参数——事实上有两个参数,一个用于客户端,一个用于服务器——引起了很多混乱,并导致了一些不良信息的传播:你会发现Internet 上的人告诉您将其设置为荒谬的值,例如 1G(1073741824,这是可能的最大值),但这并不是一个真正好的策略,因为如上所述,这是一种保护机制。如果数据包碰巧在网络上以错误的方式损坏,服务器可能会得出结论,它实际上需要分配大量内存,以便该数据包可以成功加载到缓冲区中——这可能会导致通过使系统因可用内存不足而导致系统受损或拒绝服务。

服务器通常分配用于从线路读取数据包的实际内存量是 net_buffer_length。数据包中指示的大小实际上并未分配,除非它大于 net_buffer_length.


¹ 一个数据包 指的是 MySQL Client/Server 协议意义上的第 7 层数据包。不要与 IP 数据包或数据报混淆。