由 John Doe 九月 23, 2025
你对 PostgreSQL 依赖系统的页面缓存感到烦恼吗?现在,PostgreSQL 支持直接 I/O 了。
特性提交日志
添加 io_direct 配置项(仅开发者可用)。
提供一种方式,可在数据文件和 WAL 日志文件支持的情况下,请求内核使用 O_DIRECT(或系统本地的等效接口),以避免或最小化内核缓存的影响。目前,该配置项会导致性能下降,暂不面向普通用户使用。后续计划新增数据库自身的 I/O 聚合、预读等功能,以替代启用该选项后禁用的内核相关机制。
若未使用这个仅开发者可见的 GUC 配置参数,用户能感知到的唯一变更为:本次提交还移除了一套晦涩的逻辑,此前当wal_sync_method=open_[data]sync
、wal_level=minimal
(且需同时满足max_wal_senders=0
)时,会自动为 WAL 文件启用O_DIRECT。这些配置均为非默认值,实际使用场景极少,且该行为从未正确地在文档中进行过说明。如今,通过设置io_direct=wal
即可实现相同效果。
将 io_direct 重命名为 debug_io_direct。
为新的 GUC 配置参数 io_direct 赋予一个明确标识“暂不面向主流场景使用”的名称。
未来只有在新增基础设施以实现高效运行后,才会考虑移除该参数名称中的前缀。目前将该配置参数保留在代码树中是有益的,因为它可能帮助我们发现更多在各类系统中潜藏的风险;但是原来的名称io_direct
过于具有吸引力,可能在未来引发跨版本混淆的问题,故此次进行重命名。
讨论:https://postgr.es/m/CA%2BhUKGK1X532hYqJ_MzFWt0n1zt8trz980D79WbjwnT-yYLZpg%40mail.gmail.com
直接 I/O 特性
在典型的操作系统中,文件 I/O 的过程通常涉及多个缓存层。操作系统会把磁盘上的文件内容缓存到页面缓存(page cache)里,读写操作一般先经过这个缓存层,再与磁盘交互。这样设计对于很多场景是合适的,但有些场景下,这种缓存会带来额外开销或不必要的资源使用。
数据库系统,尤其是 PostgreSQL 这样的 OLTP / OLAP 系统,对 I/O 性能要求很高。忽略或减少 OS 缓存的干预,可以使 I/O 延迟更加稳定、更加可控。数据库系统对 I/O 的延迟和一致性敏感,通常会自己维护缓存(例如shared_buffers
、wal_buffers
),以处理 WAL 日志、后台刷写、恢复、复制等。
因此,有开发者提出让 PostgreSQL 支持直接 I/O 来绕开操作系统的页面缓存,从用户空间的缓冲区直接与块设备交互,从而减少中间复制、降低缓存污染、提高某些场景下的 I/O 性能可预测性。本次提交就是用来为 PostgreSQL 添加这类支持。
不过,需要注意的是,开启 Direct I/O 后,某些场景下性能反而可能变差。例如小的、频繁的顺序读写操作,因为不能使用 OS 的预读,或者不能利用缓存;每次 I/O 可能成为一次真实的磁盘访问。邮件讨论里面举了几个“变慢”的例子,如 8KB 的顺序读写每次都要到磁盘一趟,或者 WAL 写入后被 WAL Sender 读取时没有缓存帮助。
示例
debug_io_direct
是字符串类型的配置项,支持通过“逗号分隔的选项列表”指定对哪些文件启用直接 I/O,默认值为空字符串(禁用直接 I/O)。其支持的选项及含义如下表所示:
配置选项 | 作用范围 |
---|---|
data |
主数据文件(如表、索引对应的物理文件) |
wal |
WAL(预写式日志)文件 |
wal_init |
WAL 文件初始化阶段(如创建新 WAL 段文件) |
例如,debug_io_direct = 'data,wal'
表示对数据文件和 WAL 文件均启用直接 I/O。
# postgresql.conf
debug_io_direct = 'data,wal' # 数据和 WAL 日志均绕开内核缓存
修改配置启用直接 I/O,绕开内核缓存,需要重启生效。
非常不错的特性。感谢社区的所有相关人员。
参考
提交日志:https://git.postgresql.org/pg/commitdiff/d4e71df6d757fd21c363164a3a4d3b5681462662