语境
ActiveRecord::StatementInvalid
昨天的 4 个小时内,我们发现 MySQL 服务器偶尔出现错误。此后再没有出现过此类错误。
奇怪的是,SQL 语句似乎被破坏了:一个或多个随机字符被向前或向后移动了 2 个字节。例如,"Unknown table 'erades'"
针对表的查询grades
。这不仅限于表名:这些查询中的列名、SQL 关键字和值都受到了影响。
错误
错误消息示例:
.
->,
:表'[数据库名称].id'不存在:SELECT [..] FROM [..] INNER JOIN [..] ON [..] = `[表名称]`.`id` ..
`
->b
:表名'topic_setsb ON'不正确:SELECT [..] FROM [..] INNER JOIN `topic_sets` ON ...
s
->q
:'字段列表'中未知列'aqsigned_[redacted]'
U
->W
:您的 SQL 语法有错误;[..] 靠近'NWLL GROUP BY ...
8
->:
:您的 SQL 语法有错误;[..] 靠近':887)',第 1 行:SELECT [..] WHERE [..] IN (48846, 48901, 48887)
由于 MySQL 可能只报告语句中的第一个错误,因此我无法确定每个语句的确切损坏数量。消息中包含的完整 SQL 查询似乎是客户端持有的声明副本,并且该部分消息没有任何损坏。
在某些情况下,我无法从错误消息中判断哪个字符可能被损坏,例如“第 1 行 '' 附近使用的语法正确”,并且并非所有损坏都与字节移位有关。这可能是来自不可打印的字符,也可能是插入/删除了字符。
有一个有些语句被破坏的方式有固定的模式,但似乎没有明确的规则。例如,会出现 10-20 次相同的语句以相同的方式被破坏的模式,但这些模式中破坏的位置会有所不同。
我从 RDS 控制台获取的错误日志为空。该时间段内未报告任何 AWS 服务降级情况。
我们的异常跟踪工具总共报告了 143 个错误。这些错误来自 4 个 Passenger 工作程序,其中 2 个在同一个 EC2 实例上,另两个在另一个 EC2 实例上。这些工作程序中的错误计数分布:1、41、42、50。这约占发生此情况的 4 小时内处理的总请求数的 0.001%。
对于每个工人来说,错误都是零星发生的:每个工人报告这些错误大约持续 5 分钟,每隔几秒到 2-3 分钟就会发生 1-2 个错误 - 除了只有一个错误的错误之外。
一些查询针对主数据库,一些查询针对副本数据库。
环境和其他事实:
- AWS RDS MySQL 5.6.39
- AWS EC2 实例 c4.4xlarge。当时有 15 多个实例为同一网站提供服务。
- Apache 2,mpm 模块:事件
- Passenger 5.3.3,并发模型:进程。通常,单个 EC2 实例中有 30 多个工作进程。
- Rails 4.2.10,数据库池大小:2。
- MySQL 客户端库:mysql2 0.4.10
- Ruby 2.3.7
时间线
instance A launch 2018-11-13 12:00 UTC
instance A process P errors 2018-11-13 13:40-13:43 UTC
instance A process Q errors 2018-11-13 14:22-14:26 UTC
instance A shutdown 2018-11-13 20:00 UTC
instance B launch 2018-11-13 15:00 UTC
instance B process R errors 2018-11-13 15:39-15:40 UTC
instance B process S errors 2018-11-13 17:39-17:43 UTC
instance B shutdown 2018-11-13 23:00 UTC
可能的原因
一位熟人承认,他们在同一天在 AWS 中看到了同样的错误,并提到这次谈话 [1]关于网络级数据损坏:讨论了网络交换机在重新路由时如何重新计算数据包的以太网 CRC,以及重新路由过程中的损坏可能导致“有效”的 CRC,以及 TCP 校验和如何也存在漏洞。(文字注释来自 kevinchen.co)。
[1] !!Con 2017:数据中心的腐败!TCP 无法保证您的数据安全!作者:Evan Jones
他们的建议是所有通信都使用 TLS,因为 TLS 层将无法解密损坏的字节。
我还发现这一页描述了 CRC 和校验和的限制。此错误中有一个类似的错误serverfault 问题而这其中的原因也和网络有关。
我越来越相信这些错误是由网络层面的故障引起的。
问题
以太网/TCP 理论是否同意我所描述的错误行为?我不确定一次只有一个进程可能看到此错误,但我认为如果交换机决定根据源 - 目标端口对以不同方式处理数据包,则可能会发生这种情况,因为每个连接将使用不同的端口。
如果这实际上是一个 XY 问题,我很乐意重新构建这个问题。
注意:我已发布请求至AWS 论坛确认/调查这是来自 AWS 基础设施的问题。在这里,在 serverfault 中,我感兴趣的是了解该假设的合理性以及它如何表现出我看到的行为(或没有表现出来)。
答案1
这在合理范围内,很难得出任何结论。您列出的位翻转在 8 位对齐时是一致的。尽管看到整个消息会很有趣,因为(可能)网络帧中还必须有其他翻转才能挫败 CRC/校验和。
就“同一台机器上只有部分工作程序报告错误”而言,可能是 - 工作程序之间的负载不相等,这只是每个进程生成的流量字节数的影响,或者如果工作程序确实保持持久连接,那么您只是在路径选择中输掉了机会游戏。即,如果沿途有多个活动链接,则报告错误的工作程序恰好具有散列到坏链接的连接。(请参阅散列(srcip、srcport、dstip、dstport)进行链接选择并不罕见,无论是 L2(lacp/bond)还是 L3(ECMP))。对于较短的连接也有可能,尽管现在这种可能性越来越小。AWS 也完全有可能为其网络提供更深奥的路径选择,这可以解释这一点。
我通常会有些棘手并寻找其他确凿证据,例如来自操作系统、网卡和交换机/路由器的校验和错误计数器,尽管我倾向于说您对某些实例的分割没有问题,而其他实例确实存在问题作为很好的确凿证据。
翻页样式:
00101110 .
00101100 ,
00000010 xor
01100000 `
01100010 b
00000010 xor
01110011 s
01110001 q
00000010
01010101 U
01010111 W
00000010 xor
00111000 8
00111010 :
00000010 xor