Amazon RDS PostgreSQL 只读副本中的查询运行速度非常慢

Mah*_*oor 6 postgresql performance aws master-slave-replication amazon-rds postgresql-performance

我们一直在维护一个具有网络和移动应用程序平台的项目。该项目的后端使用Django 1.10开发并部署在AWS中。

一开始,当用户很少时,我们使用一个 EC2 实例和一个带有 PostgreSQL 数据库的 RDS 实例进行部署。一段时间后,用户数量增加,我们遇到了响应速度很慢、不同页面超时等问题。由于性能问题,我们采取了以下措施:

  • 我们开始使用 Redis 缓存来存储频繁访问的数据(AWS 中的 ElasticCache)
  • 我们部署在两个不同的 EC2 实例中(一个用于 Web 平台,另一个用于移动应用程序的 API)。
  • 我们在RDS中创建了一个只读副本,并添加了一个数据库路由器,该路由器选择仅使用主数据库进行写入操作,所有读取操作都在只读副本数据库中执行。

该解决方案在短短几周内运行良好。一段时间后,所有读取操作都变得太慢。此时,与主数据库的数据库连接数量平均为 2-3 个,有时会激增至 5-7 个。但由于只读副本数据库中的查询执行速度较慢,30-50 个连接在只读副本数据库中很常见。

使用 JOIN 和聚合的查询经常失败,并在只读副本中出现以下错误:

canceling statement due to conflict with recovery DETAIL: User query might have needed to see row versions that must be removed.

但与主数据库相比,只读副本中的所有查询通常都非常慢,即使是最简单的 SELECT 查询也是如此。

为了确保问题不在于特定的只读副本实例,我们创建了另一个只读副本 RDS 实例(例如 read-replica-2)并将所有读取操作指向 read-replica-2 DB。此配置一开始表现良好,但一天内性能显着下降(对于第一个只读副本,需要 3-4 周)。

之后,我们修改了数据库路由器,以针对任何读取操作随机达到只读副本和只读副本 2 之一的峰值,但对这两个只读副本数据库的所有查询执行速度仍然非常慢。我们通过将读操作切换到master数据库进行检查,相同的读操作在master数据库中执行顺利,没有任何问题。

一些服务器负载相关信息:

  • 在高峰时段,有 500-1000 个用户使用该系统,其中大多数来自移动应用程序(通过 API EC2 实例)。
  • 在高峰时段,访问Web平台的用户很少。但它们经常执行繁重的数据库密集型任务(例如批量导入和导出数据)。
  • 在非高峰时段(当地夜间的 6 小时窗口内),系统中会执行一些繁重的数据库密集型 cron 作业,以进行报告生成和维护。

考虑到这种情况,适合我们的架构应该是什么?我们是否遗漏了一些明显的东西?什么会导致相同的查询在 RDS 的主数据库中运行得很快,而在只读副本数据库中运行得很慢?

小智 -1

缓慢是其他问题,但我可以告诉您由于恢复错误而导致的查询超时。

由于与恢复冲突而取消语句详细信息:用户查询可能需要查看必须删除的行版本。

发生这种情况是因为当选择查询运行时,wal 文件会应用于只读副本。这将终止查询。

有两种解决方案。

  1. hot_standby_feedback 启用此功能。但要小心,如果假设只读副本查询运行的时间更长,然后 wal 文件不断累积并导致磁盘已满,那么延迟也会更高。所以不要建议理想的方法。

  2. 启用这些参数并增加这两个参数的值,考虑到任何特定巨型查询执行所需的最长时间。假设如果最高查询在副本上运行 10 分钟,则将以下参数的值保持为较高的值。

900000 毫秒(15 分钟) max_standby_archive_delay = 900000
max_standby_streaming_delay = 900000

我也遇到了同样的问题并使用这种方法解决了。

这些参数需要为副本参数组设置。