由 John Doe 九月 9, 2025
PostgreSQL 18 正式版发布在即。那么,你知道该版本最大的亮点在哪吗?
异步 I/O 子系统
新增异步 I/O 子系统(Asynchronous I/O,简称 AIO),是 PostgreSQL 18 中一项重要的性能特性。引入异步 I/O 特性的目的是提升 I/O 吞吐量,尤其针对顺序扫描、位图堆扫描与VACUUM
操作。在 Linux 系统上使用io_uring
时,通过将磁盘访问与数据处理并行执行,该特性可带来 2 至 3 倍的性能提升。
为 PostgreSQL 新增异步 I/O 的主要原因如下:
- 提前发起 I/O 请求,减少等待时间:过去,PostgreSQL 的读写操作严重依赖阻塞式 I/O(blocking I/O)。这意味着后端进程发起一个 I/O 调用后,会进入空闲状态,等待操作系统或磁盘响应后才能继续执行其他操作。而异步 I/O 的设计思路是,在实际需要数据之前就提前启动 I/O 操作,让 PostgreSQL 能将 I/O 操作与有效工作(如计算或其他 I/O 请求)并行执行,从而避免空闲时间的浪费。
- 支持直接 I/O(Direct I/O,简称 DIO):直接 I/O 指绕过操作系统内核的页面缓存,直接在应用程序与存储设备之间执行 I/O 操作。直接 I/O 可将大部分 I/O 工作转移到硬件层面完成,从而提升吞吐量、降低 CPU 使用率,并减少延迟。此外,该特性还支持通过 GUC 参数设置来配置直接 I/O,下文将详细介绍 GUC 参数
io_method
。
异步 I/O 基础设施支持通过多种方式实现异步 I/O 功能。该特性引入了一个名为io_method
的新 GUC 参数,用于控制异步 I/O 实现方式的选择。io_method
参数需在postgresql.conf
文件中设置,并在服务器启动时生效;若不重启服务器,无法修改该参数;若尝试通过ALTER SYSTEM
命令修改,服务器会返回如下错误:
ERROR: parameter "io_method" cannot be changed without restarting the server
io_method
参数可设置为以下三个值:
- sync(同步模式):这是异步 I/O 基础设施刚引入时的默认设置,即传统的阻塞式同步 I/O,行为与 PostgreSQL 17 完全一致。将该参数设为
sync
时,不会执行任何异步 I/O 操作,仅会跳过为该特性新增的代码。 - worker(工作进程模式):这是 PostgreSQL 18 的默认设置。该模式使用后台 I/O 工作进程,后端进程将 I/O 请求加入队列,由后台工作进程异步处理读写操作。后台 I/O 工作进程的数量由
io_workers
参数控制,在操作系统的进程列表中,这些后台工作进程会显示为独立进程。
示例如下:
SHOW io_method;
io_method
-----------
worker
(1 row)
后台 I/O 工作进程的数量由io_workers
参数控制,在操作系统的进程列表中可看到这些独立的后台进程:
$ ps ux | grep 'io worker'
redrock 352900 352899 0 16:53 ? 00:00:01 postgres: io worker 0
redrock 352901 352899 0 16:53 ? 00:00:00 postgres: io worker 1
redrock 352902 352899 0 16:53 ? 00:00:00 postgres: io worker 2
SHOW io_workers;
io_workers
------------
3
(1 row)
- io_uring(Linux 专用异步 I/O 模式):
io_uring
是 Linux 系统特有的现代高性能接口,支持真正的异步 I/O。使用该模式时,PostgreSQL 需在编译时添加--with-liburing
选项,且需运行在兼容的内核与文件系统上。io_uring
模式无需工作进程,而是通过 PostgreSQL 与内核之间的共享环形缓冲区(shared ring buffer)高效地加入和分发 I/O 请求。
该异步 I/O 模式的系统调用开销极低,尤其在高延迟存储系统上,能显著提升性能,是 Linux 系统上性能最快的异步 I/O 模式。
使用io_uring
模式需先配置如下内核参数:
$ echo 0 | sudo tee /proc/sys/kernel/io_uring_disabled
下面,我们来针对三种受支持的io_method
(sync
、worker
、io_uring
)进行异步 I/O 测试,并比较下测试结果。测试表明,从sync
到worker
再到io_uring
,随着io_method
模式的切换,性能呈现出明显的提升趋势。
以下示例展示了如何在三种受支持的io_method
模式下使用异步 I/O 特性:
- 创建测试表并插入数据
CREATE TABLE aio_test AS
SELECT generate_series(1, 10000000) AS id,
repeat('x', 100) AS filler;
- 创建索引
CREATE INDEX ON aio_test(id);
- 开启 I/O 时间跟踪
ALTER SYSTEM SET track_io_timing = on;
- 使用 sync 模式测试
SHOW io_method;
io_method
-----------
sync
(1 row)
EXPLAIN (ANALYZE, TIMING) SELECT count(*) FROM aio_test;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------
Finalize Aggregate (cost=225499.55..225499.56 rows=1 width=8) (actual time=573.824..577.110 rows=1.00 loops=1)
Buffers: shared hit=15927 read=156489
-> Gather (cost=225499.33..225499.54 rows=2 width=8) (actual time=573.674..577.104 rows=3.00 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=15927 read=156489
-> Partial Aggregate (cost=224499.33..224499.34 rows=1 width=8) (actual time=568.825..568.825 rows=1.00 loops=3)
Buffers: shared hit=15927 read=156489
-> Parallel Seq Scan on aio_test (cost=0.00..214082.67 rows=4166667 width=0) (actual time=0.092..444.480 rows=3333333.33 loops=3)
Buffers: shared hit=15927 read=156489
Planning:
Buffers: shared hit=16 read=6
Planning Time: 2.263 ms
Execution Time: 577.863 ms
- 使用 worker 模式测试
SHOW io_method;
io_method
-----------
worker
(1 row)
EXPLAIN (ANALYZE, TIMING) SELECT count(*) FROM aio_test;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Finalize Aggregate (cost=212777.59..212777.60 rows=1 width=8) (actual time=431.819..431.967 rows=1.00 loops=1)
Buffers: shared hit=12 read=27331 written=1
I/O Timings: shared read=120.329 write=0.017
-> Gather (cost=212777.37..212777.58 rows=2 width=8) (actual time=431.814..431.963 rows=3.00 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=12 read=27331 written=1
I/O Timings: shared read=120.329 write=0.017
-> Partial Aggregate (cost=211777.37..211777.38 rows=1 width=8) (actual time=426.209..426.209 rows=1.00 loops=3)
Buffers: shared hit=12 read=27331 written=1
I/O Timings: shared read=120.329 write=0.017
-> Parallel Index Only Scan using aio_test_id_idx on aio_test (cost=0.43..201360.64 rows=4166691 width=0) (actual time=0.396..333.324 rows=3333333.33 loops=3)
Heap Fetches: 0
Index Searches: 1
Buffers: shared hit=12 read=27331 written=1
I/O Timings: shared read=120.329 write=0.017
Planning:
Buffers: shared hit=36 read=20 dirtied=1
I/O Timings: shared read=1.706
Planning Time: 2.186 ms
Execution Time: 432.178 ms
- 使用 io_uring 模式测试
SHOW io_method;
io_method
-----------
io_uring
(1 row)
EXPLAIN (ANALYZE, TIMING) SELECT count(*) FROM aio_test;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Finalize Aggregate (cost=212777.59..212777.60 rows=1 width=8) (actual time=389.182..389.555 rows=1.00 loops=1)
Buffers: shared hit=13 read=27331
I/O Timings: shared read=86.715
-> Gather (cost=212777.37..212777.58 rows=2 width=8) (actual time=388.204..389.549 rows=3.00 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=13 read=27331
I/O Timings: shared read=86.715
-> Partial Aggregate (cost=211777.37..211777.38 rows=1 width=8) (actual time=377.915..377.916 rows=1.00 loops=3)
Buffers: shared hit=13 read=27331
I/O Timings: shared read=86.715
-> Parallel Index Only Scan using aio_test_id_idx on aio_test (cost=0.43..201360.64 rows=4166691 width=0) (actual time=0.083..276.593 rows=3333333.33 loops=3)
Heap Fetches: 0
Index Searches: 1
Buffers: shared hit=13 read=27331
I/O Timings: shared read=86.715
Planning:
Buffers: shared hit=36 read=20
I/O Timings: shared read=0.352
Planning Time: 0.840 ms
Execution Time: 389.683 ms
执行计划中的 “I/O Timings: shared” 字段表明,该查询计划已触发异步 I/O 操作。
总结
PostgreSQL 18 中异步 I/O 带来的性能提升,无疑是数据库 I/O 性能领域的一大步飞跃。该特性并非通过简单调整来模拟异步 I/O 功能,而是真正新增了一套异步 I/O 子系统。借助为支持该特性而新增的基础设施,可在 PostgreSQL 的多个模块中实现异步 I/O。该特性允许数据库同时发起多个读取请求,突破了以往的 I/O 瓶颈,使 PostgreSQL 能更充分地利用 CPU 与 I/O 带宽。
新的io_method
参数为切换异步 I/O 模式提供了灵活的方式,同时支持通过 GUC 设置配置直接 I/O。在 Linux 系统上,io_uring
模式能带来更高的效率,但需注意的是,要使用该模式,需在编译 PostgreSQL 时添加--with-liburing
选项。
上面对比三种受支持的io_method
模式性能的测试结果表明,worker
模式与io_uring
模式均能带来性能提升。针对该特性的基准测试显示,对于典型工作负载,磁盘读取吞吐量可提升 2 至 3 倍。此外还需注意,当前异步 I/O 仅支持读取操作,暂不支持写入操作与 WAL(预写日志)操作。
总而言之,PostgreSQL 18 中的异步 I/O 特性为读取性能带来了革命性的飞跃。数据库管理员与开发者通过合理利用worker
与io_uring
选项,并相应地调整可观测性配置与性能调优策略,可实现显著的效率提升。不过,由于该特性目前仍处于测试版阶段,在投入生产环境前,务必在自身环境中进行全面测试。
参考
提交日志:https://git.postgresql.org/pg/commitdiff/da7226993fd4b73d8b40abb7167d124eada97f2e