aws rds,导入大文件时在查询过程中失去与MySQL服务器的连接

ken*_*ter 5 mysql rds amazon-web-services

我尝试将1.4G mysql文件导入aws rds。我尝试了2 cpu和4G mem选项。我仍然有错误:Lost connection to MySQL server during query。我的问题是,如何将大型mysql文件导入rds。

Mic*_*bot 7

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

这被设计为一种安全检查,以防止在数据损坏导致连接的接收端相信数据包¹ 非常大时可能发生的大量内存的无用和破坏性分配。

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

不幸的是,这个参数的客户端设置和服务器设置是两个独立的设置,它们是不协调的。从技术上讲,不要求它们相同,但只有当它们都不超过另一个施加的限制时,差异值才有效。

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

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

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

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

使用此单行查找:

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

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

您可能希望将其四舍五入到下一个 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
Run Code Online (Sandbox Code Playgroud)

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

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

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


¹数据包是指 MySQL 客户端/服务器协议意义上的第 7 层数据包。不要与 IP 数据包或数据报混淆。