PostgreSQL 18 preview - 新增IO合并硬限制: io_max_combine_limit
PostgreSQL 18 preview - 新增IO合并硬限制: io_max_combine_limit
这两个patch都是在PostgreSQL 18引入了对AIO支持后的调整: 关于PostgreSQL数据库中I/O合并限制的改进,目的是提高I/O性能,并为未来的扩展做准备。
新增IO合并硬限制: io_max_combine_limit. 同时将IO合并软限制参数 io_combine_limit 最大值增加到 1MB.
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=10f6646847515b1ab02735c24b04abaf1996f65f
Introduce io_max_combine_limit.
author Thomas Munro <[email protected]>
Tue, 18 Mar 2025 22:40:56 +0000 (11:40 +1300)
committer Thomas Munro <[email protected]>
Wed, 19 Mar 2025 02:23:54 +0000 (15:23 +1300)
commit 10f6646847515b1ab02735c24b04abaf1996f65f
tree e49ca63aec12d99997f4fa91a6d4e3a11dbbe858 tree
parent 17d8bba6dad12e14a7cafca9ef5eef21e577e9c3 commit | diff
Introduce io_max_combine_limit. The existing io_combine_limit can be changed by users. The new
io_max_combine_limit is fixed at server startup time, and functions as a
silent clamp on the user setting. That in itself is probably quite
useful, but the primary motivation is:
aio_init.c allocates shared memory for all asynchronous IOs including
some per-block data, and we didn't want to waste memory you'd never used
by assuming they could be up to PG_IOV_MAX. This commit already halves
the size of 'AioHandleIov' and 'AioHandleData'. A follow-up commit can
now expand PG_IOV_MAX without affecting that.
Since our GUC system doesn't support dependencies or cross-checks
between GUCs, the user-settable one now assigns a "raw" value to
io_combine_limit_guc, and the lower of io_combine_limit_guc and
io_max_combine_limit is maintained in io_combine_limit.
Reviewed-by: Andres Freund <[email protected]> (earlier version)
Discussion: https://postgr.es/m/CA%2BhUKG%2B2T9p-%2BzM6Eeou-RAJjTML6eit1qn26f9twznX59qtCA%40mail.gmail.com
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=06fb5612c970b3af95aca3db5a955669b07537ca
Increase io_combine_limit range to 1MB. master github/master
author Thomas Munro <[email protected]>
Wed, 19 Mar 2025 02:23:12 +0000 (15:23 +1300)
committer Thomas Munro <[email protected]>
Wed, 19 Mar 2025 02:40:35 +0000 (15:40 +1300)
commit 06fb5612c970b3af95aca3db5a955669b07537ca
tree a3cfb560033bfd70e68f72e8d58ddc99250f5afb tree
parent 10f6646847515b1ab02735c24b04abaf1996f65f commit | diff
Increase io_combine_limit range to 1MB. The default of 128kB is unchanged, but the upper limit is changed from
32 blocks to 128 blocks, unless the operating system's IOV_MAX is too
low. Some other RDBMSes seem to cap their multi-block buffer pool I/O
around this number, and it seems useful to allow experimentation.
The concrete change is to our definition of PG_IOV_MAX, which provides
the maximum for io_combine_limit and io_max_combine_limit. It also
affects a couple of other places that work with arrays of struct iovec
or smaller objects on the stack, so we still don't want to use the
system IOV_MAX directly without a clamp: it is not under our control and
likely to be 1024. 128 seems acceptable for our current usage.
For Windows, we can't use real scatter/gather yet, so we continue to
define our own IOV_MAX value of 16 and emulate preadv()/pwritev() with
loops. Someone would need to research the trade-offs of raising that
number.
NB if trying to see this working: you might temporarily need to hack
BAS_BULKREAD to be bigger, since otherwise the obvious way of "a very
big SELECT" is limited by that for now.
Suggested-by: Tomas Vondra <[email protected]>
Discussion: https://postgr.es/m/CA%2BhUKG%2B2T9p-%2BzM6Eeou-RAJjTML6eit1qn26f9twznX59qtCA%40mail.gmail.com
AI 解读
这两个patch都是关于PostgreSQL数据库中I/O合并限制的改进,目的是提高I/O性能,并为未来的扩展做准备。下面是详细的中文解读:
Patch 1: Introduce io_max_combine_limit (引入 io_max_combine_limit)
这个patch引入了一个新的配置参数 io_max_combine_limit,它与现有的 io_combine_limit 协同工作,但目的和行为有所不同。
背景和动机:
现有的 io_combine_limit允许用户修改,用于控制单个I/O操作可以合并的最大块数。aio_init.c文件为异步I/O分配共享内存,包括每个块的数据。为了避免浪费内存,需要限制可以合并的最大块数。 之前,程序假设可以合并的块数最大为PG_IOV_MAX,这可能导致不必要的内存分配。这个patch的目标是减少 AioHandleIov和AioHandleData的大小,以便后续的patch可以扩大PG_IOV_MAX,而不会显著增加内存占用。主要功能:
io_max_combine_limit的引入: 这是一个在服务器启动时固定的参数,作为用户设置的io_combine_limit的上限。io_combine_limit的行为改变: 用户设置的io_combine_limit现在被存储在一个名为io_combine_limit_guc的变量中,这是一个“原始”值。 实际使用的io_combine_limit是io_combine_limit_guc和io_max_combine_limit中的较小值。目的: io_max_combine_limit充当一个“静默钳制器”,确保用户设置的io_combine_limit不会超过系统允许的最大值。 这主要是为了控制内存使用,并为未来的扩展提供灵活性。为什么需要两个参数?
PostgreSQL的GUC(Grand Unified Configuration)系统不支持参数之间的依赖关系或交叉检查。 因此,无法直接限制用户设置的 io_combine_limit。 引入io_max_combine_limit提供了一种间接的方式来强制执行上限。总结: 这个patch引入了
io_max_combine_limit,作为用户可配置的io_combine_limit的上限,主要目的是控制内存使用,并为后续扩大PG_IOV_MAX做准备。
Patch 2: Increase io_combine_limit range to 1MB (将 io_combine_limit 范围增加到 1MB)
这个patch扩展了 io_combine_limit 的允许范围,允许更大的I/O合并,从而可能提高性能。
背景和动机:
之前的 io_combine_limit的上限是32个块。其他关系型数据库管理系统(RDBMS)似乎将它们的多块缓冲区池I/O限制在类似的数量级。 允许更大的I/O合并可能是有益的,因此需要扩展 io_combine_limit的范围。主要功能:
PG_IOV_MAX的修改:PG_IOV_MAX定义了io_combine_limit和io_max_combine_limit的最大值。 这个patch增加了PG_IOV_MAX的值,允许更大的I/O合并。范围扩展: 默认值保持不变(128kB),但上限从32个块增加到128个块,除非操作系统的 IOV_MAX太低。Windows 特殊处理: 由于Windows不支持真正的scatter/gather I/O,因此继续使用自定义的 IOV_MAX值(16),并使用循环来模拟preadv()和pwritev()。 提高Windows上的IOV_MAX需要进一步的研究。注意事项:
即使增加了 io_combine_limit的范围,BAS_BULKREAD的大小也可能成为性能瓶颈。 可能需要临时修改BAS_BULKREAD的大小,才能充分利用更大的io_combine_limit。即使系统 IOV_MAX很大(例如1024),PG_IOV_MAX仍然被限制为128,因为在某些情况下,PostgreSQL在堆栈上使用iovec结构体数组,过大的值可能会导致堆栈溢出。总结: 这个patch通过增加
PG_IOV_MAX的值,扩展了io_combine_limit的允许范围,允许更大的I/O合并,从而可能提高性能。 同时,它也考虑了Windows平台的特殊性,并提醒注意其他潜在的性能瓶颈。
总而言之,这两个patch共同作用,旨在提高PostgreSQL的I/O性能,并为未来的扩展提供更大的灵活性。 第一个patch引入了 io_max_combine_limit 来控制内存使用,而第二个patch则扩展了 io_combine_limit 的范围,允许更大的I/O合并。
好的,让我们来详细了解一下 BAS_BULKREAD 在 PostgreSQL 中的作用,以及它与 I/O 性能的关系。
BAS_BULKREAD 的作用
BAS_BULKREAD 是 PostgreSQL 源代码中定义的一个常量,它控制着后端进程(backend process)在一次操作中可以从磁盘读取的最大字节数。 简单来说,它限制了后端进程一次性读取的数据量。
更详细的解释:
Bulk Read(批量读取):
BAS_BULKREAD涉及的是 PostgreSQL 的批量读取机制。当需要从磁盘读取大量数据时(例如,执行一个大的SELECT查询,或者扫描一个大的表),PostgreSQL 会尝试使用批量读取来提高效率。批量读取意味着一次性读取多个数据块,而不是逐个读取。限制读取大小:
BAS_BULKREAD定义了单次批量读取操作可以读取的最大字节数。 如果需要读取的数据量超过BAS_BULKREAD,PostgreSQL 会将读取操作分解为多个较小的批量读取操作。与
io_combine_limit的关系:io_combine_limit控制的是单个 I/O 操作可以合并的最大块数。BAS_BULKREAD则限制了 总共 可以读取的字节数。 即使io_combine_limit允许合并多个块,如果这些块的总大小超过BAS_BULKREAD,实际读取的数据量仍然会受到BAS_BULKREAD的限制。
BAS_BULKREAD 的重要性
BAS_BULKREAD 的值直接影响 PostgreSQL 的 I/O 性能,尤其是在处理大型数据集时。
性能瓶颈: 如果
BAS_BULKREAD的值太小,即使磁盘和 I/O 子系统具有很高的吞吐量,PostgreSQL 也可能无法充分利用它们。 因为读取操作会被分解为许多小的批量读取,这会增加 I/O 操作的开销(例如,磁盘寻道时间)。内存使用:
BAS_BULKREAD的值也与内存使用有关。 更大的BAS_BULKREAD值意味着后端进程需要分配更大的缓冲区来存储读取的数据。 因此,需要根据系统的可用内存来调整BAS_BULKREAD的值。
如何调整 BAS_BULKREAD
BAS_BULKREAD 不是一个可以通过 GUC 参数直接配置的选项。它通常在编译时通过 C 预处理器定义。这意味着要更改 BAS_BULKREAD 的值,需要修改 PostgreSQL 的源代码,然后重新编译。
修改 BAS_BULKREAD 的步骤(仅供参考,请谨慎操作):
找到定义
BAS_BULKREAD的位置: 在 PostgreSQL 源代码中搜索BAS_BULKREAD的定义。它通常位于src/include目录下的某个头文件中(例如,src/include/storage/bufpage.h或类似的)。修改定义: 修改
BAS_BULKREAD的值。 例如,如果原来的定义是#define BAS_BULKREAD (8192 * BLCKSZ),你可以将其修改为#define BAS_BULKREAD (16384 * BLCKSZ),将读取大小翻倍(假设BLCKSZ是块大小,通常是 8192 字节)。重新编译 PostgreSQL: 使用标准的 PostgreSQL 编译过程重新编译 PostgreSQL。
部署新版本: 停止 PostgreSQL 服务器,替换可执行文件,然后重新启动服务器。
警告:
修改源代码有风险: 修改 PostgreSQL 的源代码可能会引入错误,导致系统不稳定。 请务必在测试环境中进行充分的测试,然后再在生产环境中使用。 了解你的系统: 在修改 BAS_BULKREAD之前,请务必了解你的系统的硬件配置和工作负载。 不正确的BAS_BULKREAD值可能会降低性能,甚至导致系统崩溃。考虑其他优化方法: 在修改 BAS_BULKREAD之前,请考虑其他可能的优化方法,例如调整shared_buffers、work_mem等 GUC 参数,或者优化查询语句。
总结
BAS_BULKREAD 是 PostgreSQL 中控制批量读取大小的一个重要常量。它直接影响 I/O 性能,尤其是在处理大型数据集时。虽然可以修改 BAS_BULKREAD 的值,但需要谨慎操作,并充分了解系统的硬件配置和工作负载。在修改 BAS_BULKREAD 之前,请考虑其他可能的优化方法。
希望这个解释能够帮助你更好地理解 BAS_BULKREAD 的作用。