亚马逊AWS官方博客

Amazon RDS for PostgreSQL 的 Optimized Reads 功能介绍

2022 年 3 月,我们为 Amazon Relational Database Service(Amazon RDS)for PostgreSQL 推出了全新多可用区部署选项,称为多可用区数据库集群。此部署选项通过两个可读的备用实例增加了读取容量,同时缩短了事务的写入延迟和失效转移时间。使用专门构建的 Amazon Elastic Compute Cloud(Amazon EC2)实例上的本地存储对事务延迟进行优化。这些实例配备了用于本地存储的快速 NVMe SSD,非常适合高速和低延迟存储。有关更多信息,请参阅多可用区数据库集群部署

为了达到最佳性能,PostgreSQL 等数据库系统会尝试在内存中执行操作,但有时必须使用磁盘上的临时工作区。PostgreSQL 使用临时工作区进行多项操作,包括保存中间结果以构建索引,以及对查询记录进行排序或分组。中间结果是一个临时数据集,SQL 操作需要用此数据集来计算实际最终结果。例如,要提取价格前 10 名的订单,需要对每个订单的价格值按降序进行预先计算的排序。这种排序即为中间结果集。从经过排序的中间结果集将价格前 10 名的订单发送到客户端后,中间结果集将被删除。有时,根据数据量,需要扫描多个表中的数亿行来构建中间结果集,既耗时又浪费资源。

现在,我们推出了全新 Amazon Relational Database Service(Amazon RDS)部署选项 Optimized Reads,对于严重依赖临时工作区的工作负载,可实现两倍的读取性能。Optimized Reads 使用本地存储,该存储由在多可用区数据库集群中使用的底层实例上的 NVMe SSD 提供。通过在实例创建期间选择此新选项或将现有 RDS 实例的数据库实例类修改为 Optimizied Reads 实例类,Amazon RDS 可以通过使用本地存储而不是 Amazon Elastic Block Store(Amazon EBS)来自动提高临时工作区的性能。

在此系列的两篇文章中,我们将了解 Amazon RDS for PostgreSQL 如何使用 Optimized Reads 来提高 SQL 操作的性能。第一篇博文中,我们将讨论 Optimized Reads 的使用案例、Amazon RDS 如何为 Optimized Reads 功能启用本地存储、如何监控本地存储的性能、何时考虑将数据迁移至 Optimized Reads 实例,以及使用 Amazon EBS 的 RDS 实例和使用本地存储的 RDS 实例在查询性能上的差异。第二篇博文中,我们将讨论 PostgreSQL 为何使用临时存储,以及 PostgreSQL 何时在磁盘而不是内存中执行操作。我们还将深入分析并比较仅支持 Amazon EBS 的 RDS 实例与 Optimized Reads RDS 实例的性能表现。

哪些使用案例可以受益于 Optimized Reads?

对使用临时工作区的查询进行性能优化非常重要,对于严重依赖临时工作区的高并发工作负载尤其如此。一种方法是使用增强内存的实例类型,但这可能会导致过度配置整体工作负载。此外,当 Amazon RDS 使用 Amazon EBS 进行临时数据处理时,它还会消耗您的预调配 IOPS。根据工作负载的性质,这可能会造成 IOPS 的争用并带来延迟,从而降低性能。

通过在本地存储而不是 Amazon EBS 中进行临时处理,可以最大限度地减少永久存储(Amazon EBS)的负载,将其用于其他读取/写入操作。临时处理所需的 IOPS 数量来自本地存储预调配的而非 Amazon EBS。通过节省预调配 IOPS,您可以提高 RDS 实例的磁盘吞吐量以进行持续操作并提高整体性能。但是,这仅限于依赖临时存储的使用案例。正如全新功能:Amazon RDS Optimized Reads 和 Optimized Writes 中所述,以下是一些可受益于 Optimized Reads 的使用案例:

  • 包括通用表表达式(CTE)、派生表和分组操作的分析查询
  • 处理应用程序未优化查询的只读副本
  • 带有复杂操作(例如 GROUP BY 和 ORDER BY)但无法始终使用适当索引的按需或动态报告查询
  • 使用内部临时表的其他工作负载

如果您的工作负载符合其中一个或多个用例,则以下因素可能会进一步影响使用本地存储的优势:

  • 并发性:由于 Amazon EBS 通过网络进行数据传输,因此将这些数据转移到本地存储可以避免网络 I/O 延迟。而且,如果您的工作负载具有高度并发的读取/写入临时处理,这会大大帮助提高 RDS 实例的整体性能。
  • RDS 实例的类型:性能提升的程度还可能取决于您的 RDS 实例是单可用区还是多可用区。与仅支持 Amazon EBS 的多可用区实例相比,具有本地存储的多可用区实例性能更好。这是因为在仅由 Amazon EBS 支持的 RDS 多可用区实例中,会将整个 EBS 卷复制到同时包含临时数据的辅助实例。由于复制发生在存储层,因此无法控制不对某些数据集进行复制。使用 Optimizied Reads 则可以完全避免这种情况,因为复制不涉及本地存储磁盘,恢复或失效转移也不需要本地存储磁盘。

Amazon RDS 如何为临时处理启用本地存储?

在本节中,我们将讨论哪些内容允许 Amazon RDS 使用本地存储。

数据库实例类

Amazon RDS 使用专门构建的 Amazon Elastic Compute Cloud(Amazon EC2)实例,这些实例提供本地 NVMe SSD 存储。实例类的模型名称均有特殊符号 “d”。 例如,db.m5d、db.r6gd、db.r6d 等。当您使用 PostgreSQL 的表空间概念创建实例或修改现有 RDS 实例的实例类时,选择此实例类,Amazon RDS 会为数据库配置自动使用这些本地磁盘的功能。

表空间

表空间是帮助在不同存储磁盘之间组织数据的有效逻辑结构。以两种方式提供帮助:

  • 将非关键数据分流或归档到低成本存储
  • 将关键或最常用的数据放到高度优化的存储(例如 SSD)上,以提升性能

Optimized Reads 实例使用表空间指定本地 SSD 为临时工作区。使用 PostgreSQL 的配置设置 temp_tablespaces 来设置磁盘位置。以下查询返回表空间的名称及其位置:

postgres=> show temp_tablespaces ;
  temp_tablespaces
---------------------
 rds_temp_tablespace
(1 row)
postgres=> SELECT spcname,pg_tablespace_location(oid) FROM pg_tablespace WHERE pg_tablespace_location(oid) LIKE '%local%';
       spcname       |        pg_tablespace_location
---------------------+--------------------------------------
 rds_temp_tablespace | /rdslocalstorage/rds_temp_tablespace
(1 row)

什么时候应该使用 Optimized Reads?

如何确定 Optimized Reads 是否有利于您的工作负载? 除了本文讨论的一般指导外,您还可以使用监控数据来评估 Optimized Reads 是否有利于您的工作负载。利用来自数据库级别监控查询的监控数据,您可以评估已进行读取优化的 RDS 实例是否适合您的工作负载。如果有许多查询需要磁盘访问权限才能进行临时处理,则 Optimizied Reads 实例或许非常合适。一种评估方法是还原 RDS 实例的快照并重放工作负载。有关详细信息,请参阅从快照还原

在还原页面上,在 DB instance class(数据库实例类)的 Instance configuration(实例配置)选项下,您可以选择与当前生产实例类相似的 Optimizied Reads 实例类。例如,如果您的生产实例类是 db.m5.4xlarge,则可以选择 db.m5d.4xlarge。

当您准备好已创建最新生产快照的实例,并完成延迟加载后,您可以运行常规性能测试,作为应用程序性能评估的一部分。性能测试结束后,在性能详情查看结果,与仅支持 Amazon EBS 的 RDS 实例的结果进行比较。对于特定查询的性能,您可以使用 pg_stat_statements.total_exec_timetotal_time 比较 PostgreSQL 13 之前版本的热门查询的运行时。

监控本地存储的性能

了解 RDS 数据库的性能数据历史记录能让您了解 Optimized Reads 对工作负载产生的好处。在本节中,我们将讨论如何监控 Optimized Reads 性能,帮助您做出使用 Optimized Reads 的决定,或帮助您解决可能遇到的性能问题。

Amazon CloudWatch

Amazon RDS for PostgreSQL 支持多种监控 RDS 实例性能的方法,Amazon CloudWatch 就是其中之一。有关更多信息,请参阅使用 Amazon CloudWatch 监控 Amazon RDS 指标。随着 Optimized Reads 的推出,我们在 CloudWatch 中添加了以下专门用于衡量本地存储性能的额外指标。这些指标仅显示于 Optimized Read 实例。

指标 说明
ReadIOPSLocalStorage  每秒对本地存储进行磁盘读取 I/O 操作的平均次数
WriteIOPSLocalStorage  每秒向本地存储器写入 I/O 操作的平均次数
ReadLatencyLocalStorage  本地存储每次进行磁盘读取 I/O 操作所花费的平均时间(以毫秒为单位)
WriteLatencyLocalStorage  本地存储每次进行磁盘写入 I/O 操作所花费的平均时间(以毫秒为单位)
ReadThroughputLocalStorage  本地存储每秒从磁盘读取的平均字节数(以 MB/秒为单位)
WriteThroughputLocalStorage  本地存储每秒写入磁盘的平均字节数(以 MB/秒为单位)
FreeLocalStorage  可用本地存储空间量(以 MB 为单位)

数据库级别监控

在数据库级别,PostgreSQL 提供两个目录视图,用于报告查询和数据库的统计信息,包括临时使用情况。但是,无法区分查询是写入 Amazon EBS 还是本地存储。您可以根据实例类和 temp_tablespaces 的默认设置来确定查询使用的是本地存储还是 Amazon EBS。

pg_stat_statements

使用 pg_stat_stat_satements 扩展,您可以监控特定查询对内存和磁盘中的临时空间使用分配情况。

以下查询返回临时磁盘使用量排在前 10 位的查询。您可以调整 LIMIT 以查看其他结果。

WITH q AS (
    SELECT
        SUBSTR(query, 1, 100),
        calls,
        round(mean_exec_time::numeric / 1000 / 60, 2) AS avg_ex_time_in_min,
        (local_blks_read + local_blks_written + temp_blks_read + temp_blks_written) * 8 * 1024 AS total_disk_temp_io,
        ((temp_blks_read + temp_blks_written) * 8 * 1024) AS disk_temp_io_queries_indexes,
        ((temp_blks_written) * 8 * 1024) AS disk_temp_write_io_queries_indexes,
        ((temp_blks_read) * 8 * 1024) AS disk_temp_read_io_queries_indexes,
        ((local_blks_read + local_blks_written) * 8 * 1024) AS disk_temp_io_temp_tables,
        ((local_blks_written) * 8 * 1024) AS disk_temp_write_io_temp_tables,
        ((local_blks_read) * 8 * 1024) AS disk_temp_read_io_temp_tables,
        round(total_exec_time::numeric, 2) / 1000 / 60 AS total_exec_time_msec
    FROM (
        SELECT
            *
        FROM
            pg_stat_statements
        WHERE (local_blks_read + local_blks_written + temp_blks_read + temp_blks_written) > 0) q
ORDER BY
    total_disk_temp_io DESC
LIMIT 10
)
SELECT
    pg_size_pretty(total_disk_temp_io) AS total_disk_temp_io,
    pg_size_pretty(disk_temp_io_queries_indexes) AS disk_temp_io_queries_indexes,
    pg_size_pretty(disk_temp_read_io_queries_indexes) AS disk_temp_read_io_queries_indexes,
    pg_size_pretty(disk_temp_io_temp_tables) AS disk_temp_io_temp_tables,
    pg_size_pretty(disk_temp_write_io_temp_tables) AS disk_temp_write_io_temp_tables,
    pg_size_pretty(disk_temp_read_io_temp_tables) AS disk_temp_read_io_temp_tables
FROM
    q;

请注意,对于 PostgreSQL 13 之前的版本,您需要使用 total_time 而不是 total_exec_time

pg_stat_database

使用 pg_stat_database,您可以监控数据库级别的临时空间使用情况。

以下查询返回每个数据库的临时磁盘使用情况:

SELECT
    datname,
    temp_files,
    pg_size_pretty(temp_bytes)
FROM
    pg_stat_database
ORDER BY temp_files DESC;

有关更多信息,请参阅使用 PostgreSQL 管理临时文件

性能比较

让我们看看仅支持 Amazon EBS 的 RDS 实例和 Optimized Reads RDS 实例之间的性能差异。

基于并发性如何影响读取性能的讨论,让我们看看依赖临时存储的工作负载的并发性增加会如何影响单可用区 RDS 实例的性能。

在查看这些使用案例的性能结果之前,让我们来看看评估背后的设置。

并发性

并发的定义是在对存储子系统(包括本地存储)进行并发读取/写入请求的同时,活跃运行的客户端或会话的数量。因为我们的目标是了解本地存储,所以我们更多地关注严重依赖临时处理的使用案例。以下是用于本次评估的各种并发级别:4、8、12、16。

基础设施

下表汇总了每个实例的基础设施详细信息。实例类中的 “d” 表示支持本地存储,即 Optimized Reads RDS 实例。

实例类型 实例类 vCPU 内存(GiB) 存储 专用 EBS 带宽(Mbps) 网络性能(Gbps) 分配的存储空间(GB) IOPS
Optimized Reads db.m5d.4xlarge 16 64 2 个 300 NVMe SSD 4750 最多 10 个 2048 5000
仅限 EBS db.m5.4xlarge 16 64 仅限 Amazon EBS 4750 最多 10 个 2048 5000

我们也不希望 vCPU 数量超过并行运行的最大客户端数量,因此并发最大值为 16。

架构

在本实验中,我们使用 sysbench 创建了规模为 1000 的架构。Sysbench 部署了三个表,每个表有 1 亿条记录。构建脚本如下所示:

sysbench —db-driver=pgsql —report-interval=2 —oltp-table-size=100000000 —oltp-tables-count=3 —threads=3 —time=60 —pgsql-host=$PGHOST —pgsql-port=$PGPORT —pgsql-user=$PGUSER —pgsql-db=$BMDB /usr/share/sysbench/tests/include/oltp_legacy/parallel_prepare.lua run

要了解有关安装和使用的说明,请查看 sysbench GitHub 页面

要在使用 sysbench 初始化数据后验证记录数,请使用以下代码:

 sbtest=> SELECT relname AS table_name,TO_CHAR(reltuples::bigint,'fm999G999G999') AS rows FROM pg_class WHERE relname iLIKE '%sbtest%' AND relkind = 'r' ORDER BY relname;
 table_name |    rows
------------+-------------
 sbtest1    | 100,000,008
 sbtest2    | 100,000,008
 sbtest3    | 100,000,008
(3 rows)

数据库参数

下表列出了影响临时处理性能的核心参数。我们使用默认设置,其中一些默认设置基于 RDS 实例类。

参数 设置 单位
checkpoint_timeout 300
huge_pages 开启
maintenance_work_mem 1064641 kB
max_parallel_workers 8
max_parallel_workers_per_gather 2
max_wal_size 2048 MB
shared_buffers 2029473 8kB
temp_buffers 1024 8kB
wal_compression 开启
work_mem 4096 kB

PostgreSQL 的并行度

根据优化器选择的查询运行计划以及 max_parallel_workers_per_gather 设置的配置,可能会分配多个工作程序来处理特定查询。查询可以提供的默认并行线程数(max_parallel_workers_per_gather)为 2。因此,PostgreSQL 创建的用于处理查询的会话数是([max_parallel_workers_per_gather * 并发性] + 每个父进程的数量 max_parallel_workers_per_gather)。每个并行处理查询都有一个父进程。

例如,若并发为 16,总共会创建 ([2*16] + 16) = 48 个会话。

查询

我们使用以下查询来评估性能测试。每个查询与运行相同查询的多个会话并行运行;会话数量定义了并发级别。

  • 查询 1:此查询旨在获取唯一值。DISTINCT 需要在 PostgreSQL 中进行排序,因此当 work_mem 不足时,会造成磁盘溢出。
EXPLAIN(analyze, buffers)
SELECT DISTINCT padFROM sbtest1 limit 65000000;
  • 查询 2:此查询结合了 GROUP BY 和 ORDER BY 操作。两者通常都会在 work_mem 不足时导致临时使用磁盘。
EXPLAIN (analyze, buffers )
 SELECT c1.pad
 ,sum(c1.c)
 ,avg(c1.k)
 FROM (
 SELECT pad
 ,length(c) AS c
 , k
 FROM sbtest2 limit 100000000
 ) AS c1 GROUP BY c1.pad ORDER BY 3;
  • 查询 3:此查询仅关注非索引列上的 ORDER BY:
EXPLAIN(ANALYZE, BUFFERS)
 SELECT k
 , length(pad)
 FROM sbtest3 ORDER BY pad LIMIT 50000000;

结果

下表汇总了每个并发级别的平均时间、使用的磁盘空间量以及每个并发级别下本地存储与 Amazon EBS 相比的性能提升百分比。

并发性 性能提升百分比 Amazon EBS(以分钟为单位的时间) 本地存储(以分钟为单位的时间) 临时磁盘使用情况(以 GB 为单位)
4 6.6 11.3 10.6 1090
8 33.3 22 16.5 2268
12 72.6 40.4 23.4 3449
16 106.9 66.2 32 4629

下图是汇总表的图形视图。

从结果中,我们看到使用 Optimized Reads 后,在运行时方面,运行需要临时存储的查询的高并发工作负载得到了提升。仅支持 Amazon EBS 的 RDS 实例花了大约 66 分钟来处理 16 次的并发测试,而 Optimized Reads 实例只用了 32 分钟来处理具有相同并发性的相同工作负载。结果还显示,随着并发增加,磁盘空间的使用量和运行时间也会增加。这很正常,但它对仅支持 Amazon EBS 的 RDS 实例的性能影响要大得多,相比之下,Optimized Reads 实例在性能上提升了 106.9%。这是因为 Amazon EBS 是一种网络存储,受网络带宽容量、Amazon EBS 带宽容量和存储配置(例如通用 Amazon EBS 存储类型的存储量和预调配 IOPS 存储类型的 IOPS 数量)的约束。

由于存储直接本地连接到 Optimized Reads 实例,这些限制不影响本地存储,但同时影响 Amazon EBS 和本地磁盘的实例限制除外。

结论

在这篇文章中,我们介绍了 Optimized Reads,讨论了临时工作区的重要性,还展示了如何使用 CloudWatch 监控本地磁盘的临时使用情况,以及如何使用 PostgreSQL 的系统表监控数据库级别的临时使用情况。我们还比较了 Optimized Reads 实例和仅支持 Amazon EBS 的 RDS 实例的查询性能,并讨论了如何考虑将数据迁移到 Optimized Reads 实例。

依赖临时工作区的查询的性能对于高度并发的工作负载至关重要。使用 Optimized Reads,您只需选择支持 Optimized Reads 的类似实例类,即可提高需要进行中间处理的 SQL 操作的性能。Optimized Reads 实例还有更多优势:通过将 I/O 使用量分流到本地磁盘,您可以对节省的 Amazon EBS 资源进行最佳平衡,将其用于其他持久性操作,提高磁盘吞吐量,提升数据库和应用程序的整体性能状况。

目前 RDS 单可用区和多可用区实例(包括 RDS 只读副本)中均已推出 Optimized Reads 功能,同时可以在 Amazon RDS for PostgreSQL 版本 15.2 及更高版本、14.7 及更高版本以及 13.10 及更高版本中已推出多可用区数据库集群。今天就开始享受 Optimized Reads 带来的优势吧!

想要更深入地了解 Optimized Reads,请继续关注本系列的第二篇博文。

Original URL:https://aws.amazon.com/blogs/database/introducing-optimized-reads-for-amazon-rds-for-postgresql/