PostgreSQL 19 preview - 刷脏调试利器“干预缓存, 标记脏页”
本期播客
PostgreSQL 19 preview - 刷脏调试利器“干预缓存, 标记脏页”
刷脏是数据库checkpointer 检查点进程、bgwriter 后台进程、backend process后端进程可能会触发的事情, 但是为了使数据库运行更平滑, 用户的请求响应时间抖动更小, 刷脏的参数要好好控制!
以前可能需要通过压测、观察监控数据来调试这些参数. PG 19 更先进了, 直接引入了可以干预缓存中的页面状态的SQL 函数, 可将页面标记为脏, 触发刷脏行为, 便于随时观察刷脏时的数据库性能.
https://github.com/postgres/postgres/commit/9660906dbd696146da2c1d8bfdce26b1a2bed1c3
Add routines for marking buffers dirty efficiently
This commit introduces new internal bufmgr routines for marking shared
buffers as dirty:
* MarkDirtyUnpinnedBuffer()
* MarkDirtyRelUnpinnedBuffers()
* MarkDirtyAllUnpinnedBuffers()
These functions provide an efficient mechanism to respectively mark one
buffer, all the buffers of a relation, or the entire shared buffer pool
as dirty, something that can be useful to force patterns for the
checkpointer. MarkDirtyUnpinnedBufferInternal(), an extra routine, is
used by these three, to mark as dirty an unpinned buffer.
They are intended as developer tools to manipulate buffer dirtiness in
bulk, and will be used in a follow-up commit.
Author: Nazir Bilal Yavuz <[email protected]>
Reviewed-by: Andres Freund <[email protected]>
Reviewed-by: Aidar Imamov <[email protected]>
Reviewed-by: Amit Kapila <[email protected]>
Reviewed-by: Joseph Koshakow <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Yuhang Qiu <[email protected]>
Reviewed-by: Xuneng Zhou <[email protected]>
Discussion: https://postgr.es/m/CAN55FZ0h_YoSqqutxV6DES1RW8ig6wcA8CR9rJk358YRMxZFmw@mail.gmail.com
https://github.com/postgres/postgres/commit/9ccc049dfe655ca9927f7c62559ec32f4d1f94dd
pg_buffercache: Add pg_buffercache_mark_dirty{,_relation,_all}()
This commit introduces three new functionsfor marking shared buffers as
dirty by using the functions introduced in 9660906:
* pg_buffercache_mark_dirty() for one shared buffer.
- pg_buffercache_mark_dirt_relation() for all the shared buffers in a
relation.
* pg_buffercache_mark_dirty_all() for all the shared buffers in pool.
The "_all" and "_relation" flavors are designed to address the
inefficiency of repeatedly calling pg_buffercache_mark_dirty() for each
individual buffer, which can be time-consuming when dealing with with
large shared buffers pool.
These functions are intended as developer tools and are available only
to superusers. There is no need to bump the version of pg_buffercache,
4b203d4 having done this job in this release cycle.
Author: Nazir Bilal Yavuz <[email protected]>
Reviewed-by: Andres Freund <[email protected]>
Reviewed-by: Aidar Imamov <[email protected]>
Reviewed-by: Amit Kapila <[email protected]>
Reviewed-by: Joseph Koshakow <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Yuhang Qiu <[email protected]>
Reviewed-by: Xuneng Zhou <[email protected]>
Discussion: https://postgr.es/m/CAN55FZ0h_YoSqqutxV6DES1RW8ig6wcA8CR9rJk358YRMxZFmw@mail.gmail.com
详细解读
这两个补丁是紧密相关的,它们共同为 PostgreSQL 增加了在共享缓冲区(shared buffers)中批量标记页面为“脏”(dirty)的功能,主要目的是作为开发和超级用户工具,以控制或测试 Checkpointer 的行为模式。
补丁一:9660906dbd696146da2c1d8bfdce26b1a2bed1c3
提交信息: Add routines for marking buffers dirty efficiently (添加高效标记缓冲区为脏的例程)
主要内容:
这个补丁在 PostgreSQL 的核心代码(缓冲区管理器 bufmgr)中引入了新的内部 C 语言函数,用于高效地将共享缓冲区标记为脏页(Dirty Buffer)。
新增的内部函数:
MarkDirtyUnpinnedBuffer(): 尝试将一个未被固定的(unpinned)共享缓冲区标记为脏。MarkDirtyRelUnpinnedBuffers(): 尝试将属于某个关系(Relation) 的所有未被固定的共享缓冲区标记为脏。MarkDirtyAllUnpinnedBuffers(): 尝试将整个共享缓冲区池(shared buffer pool) 中所有未被固定的缓冲区标记为脏。MarkDirtyUnpinnedBufferInternal(): 一个内部辅助函数,用于执行实际的标记操作。
目的:
提供一种高效的机制来批量修改缓冲区的脏状态。 这些函数主要用作开发工具,用于操作缓冲区的脏状态,例如可以用于强制 Checkpointer 进程以特定模式工作(即迫使它将大量脏页写入磁盘)。 此提交是功能实现的基础,它为后续的补丁暴露给用户奠定了基础。
补丁二:9ccc049dfe655ca9927f7c62559ec32f4d1f94dd
提交信息: pg_buffercache: Add pg_buffercache_mark_dirty{,_relation,_all}() (pg_buffercache:添加 pg_buffercache_mark_dirty{,_relation,_all}() 函数)
主要内容:
这个补丁在 pg_buffercache 扩展中引入了新的 SQL 函数,将补丁一中实现的底层功能暴露给超级用户使用。
新增的 SQL 函数(仅限超级用户):
pg_buffercache_mark_dirty(buffer_id): 用于标记一个特定的共享缓冲区 ID 为脏。pg_buffercache_mark_dirty_relation(relation_oid): 用于标记某个关系(表、索引等) 的所有共享缓冲区为脏。pg_buffercache_mark_dirty_all(): 用于标记整个缓冲区池的所有共享缓冲区为脏。
目的和价值:
提供了比单独标记每个缓冲区更高效的方式,尤其是 _all和_relation变体,解决了在共享缓冲区池较大时,重复调用单个缓冲区标记函数所带来的性能低效问题。这些功能被定位为开发工具,允许超级用户通过 SQL 接口,方便地对缓冲区缓存状态进行干预和测试。
总结:
简而言之,第一个补丁(9660906)在 PostgreSQL 内核中实现了批量标记缓冲区为脏的底层 C 函数;第二个补丁(9ccc049)则在 pg_buffercache 扩展中创建了对应的 SQL 函数,将这一功能以方便超级用户使用的方式暴露出来。