【发布时间】:2015-07-17 20:45:16
【问题描述】:
我正在编写一个遍历一些 MySQL 表的工作,根据一些标准选择一些行,从中提取电子邮件地址并向每个表发送一封电子邮件。
过滤过程查看一个相当大的表(我们称之为storage)(转储约6gb),如下所示:
Columns:
id varchar(64) PK
path varchar(64) PK
game varchar(64)
guid varchar(64)
value varchar(512)
timestamp timestamp
有两个索引:(id, path)(如上所示的 PK)和guid。
该作业首先从一个表中检索一长串 guid,然后对它们进行批处理并在 storage 表上执行类似这样的连续查询:
SELECT guid, timestamp FROM storage
WHERE game = 'somegame'
AND path = 'path' AND value = 'value' AND timestamp >= '2015-04-22 00:00:00.0' AND timestamp <= '2015-04-29T14:53:07+02:00'
AND guid IN ( ... )
IN 子句包含一个 guid 列表。
我需要检索时间戳才能进一步过滤。
在我的本地 MySQL 上运行时,一切正常,查询需要大约 180 毫秒,批量 1000 个 guid。
在 Amazon RDS 上针对同一数据库运行时,查询开始很快,但在某个时间点之后,它们突然开始需要大约 30 秒,并继续这样做直到作业结束。
我尝试了很多方法来解决此问题,但无法找出原因。一些注意事项:
- 作业仅使用一个
sql.DB对象。另外,我准备了一次上述语句并大量重复使用它。 - 起初,我以为是因为RDS DB运行的是MySQL 5.5,而我运行的是5.6。我制作了 RDS DB 的副本,升级到 5.6,再次运行该作业。问题又出现了。
- 两个数据库中的数据量相同:我转储生产数据库并将其导入本地数据库并运行作业。相同的行为(它仍然在本地快速运行)。
- RDS 节点的 AWS 监控未显示任何明显的峰值。 CPU 使用率从 1% 跃升至最高 10%,并且该作业似乎只打开了几个连接 (~4)。
- 我让一位同事在他们的 PC 上运行该作业,指向 我的 MySQL 数据库,只是为了确保出色的性能并非源于本地连接这一事实。它的运行速度与在我的 PC 上一样快(诚然,通过 LAN)。
- 我从我的本地 PC 和 Amazon EC2 节点 对 RDS 运行了该作业,该节点非常接近 RDS。从EC2开始,它的表现更好,但问题仍然出现。
- 作业非常并发,每一步都有输入和输出通道(缓冲区大小为1000),工作由goroutines执行。在这两个步骤之间,我还有其他 goroutine 可以批量处理前一个 goroutine 的输出。
- 速度突然变慢,一个查询需要几毫秒,下一个需要几十秒。
我完全不知道为什么会发生这种情况。任何建议,将不胜感激。
【问题讨论】:
-
我在这里给出答案,但亚马逊会在您运行一定数量的查询后限制您的带宽。他们实际上是在更慢地运行您的每个查询,还是仅以特定间隔运行它们,这是任何人的猜测。
-
我实际上可以回答这个问题,我在作业运行时在数据库上运行了 SHOW FULL PROCESSLIST,并且查询实际上花费了更长的时间,它们并没有间隔运行。但是他们怎样才能使查询运行时间更长呢?另外,我在哪里可以看到?是否有关于限制等的文档?
-
好吧,如果查询与其他任务并行运行,那么它们似乎需要更长的时间。
-
我什至在我专门为此目的委托的副本上运行了这个,它没有运行其他查询。 :-|
-
这里只是在黑暗中拍摄...尝试将
http://godoc.org/database/sql#DB.SetMaxIdleConns设置为0。听起来您的联系可能正在停滞不前。最终他们被清理干净,但在此期间一切都在等待。 (github.com/go-sql-driver/mysql/issues/257)
标签: mysql amazon-web-services go amazon-rds