MOT内存和存储规划

本节描述了为满足特定应用程序需求,在评估、估计和规划内存和存储容量数量时,需要注意的事项和准则,以及影响所需内存数量的各种数据,例如计划表的数据和索引大小、维持事务管理的内存以及数据增长的速度。

MOT内存规划

MOT是一种内存数据库存储引擎(IMDB),其中所有表和索引完全驻留在内存中。

MOT内存和存储规划 - 图1 说明: 内存存储是易失的,需要电力来维护所存储的信息。磁盘存储是持久的,写入磁盘是非易失性存储。MOT使用两种存储,既把所有数据保存在内存中,也把事务性更改同步(通过WAL日志记录)到磁盘上以保持严格一致性(使用同步日志记录模式)。

服务器上必须有足够的物理内存以维持内存表的状态,并满足工作负载和数据的增长。所有这些都是在传统的基于磁盘的引擎、表和会话所需的内存之外的要求。因此,提前规划好足够的内存来容纳这些内容是非常有必要的。

开始可以使用任何数量的内存并执行基本任务和评估测试。但当准备好生产时,应解决以下问题:

  • 内存配置

    openGauss数据库和标准Postgres类似,其内存上限是由max_process_memory设置的,该上限在postgres.conf文件中定义。MOT及其所有组件和线程,都驻留在openGauss进程中。因此,分配给MOT的内存也是在整个openGauss数据库进程的max_process_memory定义的上限内分配。

    MOT为自己保留的内存是max_process_memory的一部分。可以通过百分比或通过小于max_process_memory的绝对值定义。这个部分在mot.conf配置文件中由<min / max>_mot_<global / local>_memory配置项定义。

    max_process_memory中可以除了被MOT使用的部分之外,必须为Postgres(openGauss)封装留下至少2GB的可用空间。为了确保这一点,MOT在数据库启动过程中会进行如下校验:

    1. (max_mot_global_memory + max_mot_local_memory) + 2GB < max_process_memory

    如果违反此限制,则调整MOT内存内部限制,最大可能地满足上述限制范围。该调整在启动时进行,并据此计算MOT最大内存值。

    MOT内存和存储规划 - 图2 说明: MOT最大内存值是配置或调整值(max_mot_global_memory + max_mot_local_memory)的逻辑计算值。

    此时,会向服务器日志发出警告,如下所示:

    以下是报告问题的警告消息示例:

    1. [WARNING] <Configuration> MOT engine maximum memory definitions (global: 9830 MB, local: 1843 MB, session large store: 0 MB, total: 11673 MB) breach GaussDB maximum process memory restriction (12288 MB) and/or total system memory (64243 MB). MOT values shall be adjusted accordingly to preserve required gap (2048 MB).

    以下警告消息示例提示MOT正在自动调整内存限制:

    1. [WARNING] <Configuration> Adjusting MOT memory limits: global = 8623 MB, local = 1617 MB, session large store = 0 MB, total = 10240 MB

    新内存限制仅在此处显示。

    此外,当总内存使用量接近所选内存限制时,MOT不再允许插入额外数据。不再允许额外数据插入的阈值即是MOT最大内存百分比(如上所述,这是一个计算值)。MOT最大内存百分比默认值为90,即90%。尝试添加超过此阈值的额外数据时,会向用户返回错误,并且也会注册到数据库日志文件中。

  • 最小值和最大值

    为了确保内存安全,MOT根据最小的全局和本地设置预先分配内存。数据库管理员应指定MOT和会话维持工作负载所需的最小内存量。这样可以确保即使另一个消耗内存的应用程序与数据库在同一台服务器上运行,并且与数据库竞争内存资源,也能够将这个最小的内存分配给MOT。最大值用于限制内存增长。

  • 全局和本地

    MOT使用的内存由两部分组成:

    • 全局内存:全局内存是一个长期内存池,包含MOT的数据和索引。它平均分布在NUMA节点,由所有CPU核共享。

    • 本地内存:本地内存是用于短期对象的内存池。它的主要使用者是处理事务的会话。这些会话将数据更改存储在专门用于相关特定事务的内存部分(称为事务专用内存)。在提交阶段,数据更改将被移动到全局内存中。内存对象分配以NUMA-local方式执行,以实现尽可能低的延迟。

      被释放的对象被放回相关的内存池中。在事务期间尽量少使用操作系统内存分配(malloc)函数,避免不必要的锁和锁存。

      这两个内存的分配由专用的min/max_mot_global_memory和min/max_mot_local_memory设置控制。如果MOT全局内存使用量太接近最大值,则MOT会保护自身,不接受新数据。超出此限制的内存分配尝试将被拒绝,并向用户报告错误。

  • 最低内存要求

    在开始执行对MOT性能的最小评估前,请确保:

    除了磁盘表缓冲区和额外的内存,max_process_memory(在postgres.conf中定义)还有足够的容量用于MOT和会话(由mix/max_mot_global_memory和mix/max_mot_local_memory配置)。对于简单的测试,可以使用mot.conf的默认设置。

  • 生产过程中实际内存需求

    在典型的OLTP工作负载中,平均读写比例为80:20,每个表的MOT内存使用率比基于磁盘的表高60%(包括数据和索引)。这是因为使用了更优化的数据结构和算法,使得访问速度更快,并具有CPU缓存感知和内存预取功能。

    特定应用程序的实际内存需求取决于数据量、预期工作负载,特别是数据增长。

  • 最大全局内存规划:数据和索引大小

    要规划最大全局内存,需满足:

    1. 确定特定磁盘表(包括其数据和所有索引)的大小。如下统计查询可以确定customer表的数据大小和customer_pkey索引大小:

      • 数据大小:选择pg_relation_size(’customer’);
      • 索引:选择pg_relation_size(’customer_pkey’);
    2. 额外增加60%的内存,相对于基于磁盘的数据和索引的当前大小,这是MOT中的常见要求。

    3. 额外增加数据预期增长百分比。例如:

      5%月增长率 = 80%年增长率(1.05^12)。因此,为了维持年增长,需分配比表当前使用的还多80%的内存。

      至此,max_mot_global_memory值的估计和规划就完成了。实际设置可以用绝对值或Postgres max_process_memory的百分比来定义。具体的值通常在部署期间进行微调。

  • 最大本地内存规划:并发会话支持

    本地内存需求主要是并发会话数量的函数。平均会话的典型OLTP工作负载最大占用8MB。此值乘以会话的数量,再加一点额外的值。

    可以通过这种方式进行内存计算,然后进行微调:

    1. SESSION_COUNT * SESSION_SIZE (8 MB) + SOME_EXTRA (100MB should be enough)

    默认指定Postgres最大进程内存(默认为12GB)的15%。相当于1.8GB可满足230个会话,即max_mot_local内存需求。实际设置可以用绝对值或Postgres max_process_memory的百分比来定义。具体的值通常在部署期间进行微调。

  • 异常大事务

    某些事务非常大,因为它们将更改应用于大量行。这可能导致单个会话的本地内存增加到允许的最大限制,即1GB。例如:

    1. delete from SOME_VERY_LARGE_TABLE;

    在配置max_mot_local_memory设置和应用程序开发时,请考虑此场景。

    MOT内存和存储规划 - 图3 说明: 有关配置的更多信息,请参阅内存(MOT)部分。

存储IO

MOT是一个内存优化的持久化数据库存储引擎。需要磁盘驱动器来存储WAL重做日志和定期检查点。

推荐采用低延迟的存储设备,如配置RAID-1的SSD、NVMe或者任何企业级存储系统。当使用适当的硬件时,数据库事务处理和竞争将成为瓶颈,而非IO。

由于持久性存储比RAM内存慢得多,因此IO操作(日志和检查点)可能成为内存中数据库和内存优化数据库的瓶颈。但是,MOT具有针对现代硬件(如SSD、NVMe)进行优化的高效持久性设计和实现。此外,MOT最小化和优化了写入点(例如,使用并行日志记录、每个事务的单日志记录和NUMA-aware事务组写入),并且最小化了写入磁盘的数据(例如,只把更改记录的增量或更新列记录到日志,并且只记录提交阶段的事务)。

容量需求

所需容量取决于检查点和记录的要求,如下所述:

  • 检查点

    检查点将所有数据的快照保存到磁盘。

    需要给检查点分配两倍数据大小的容量。不需要为检查点索引分配空间。

    检查点 = 2 x MOT数据大小(仅表示行,索引非持久)。

    检查点之所以需要两倍大小,是因为快照会保存数据的全部大小到磁盘上,此外还应该为正在进行的检查点分配同样数量的空间。当检查点进程结束时,以前的检查点文件将被删除。

MOT内存和存储规划 - 图4 说明: 在下一个openGauss版本中,MOT将有一个增量检查点特性,这将大大降低存储容量需求。

  • 日志记录

    MOT日志记录与基于磁盘的表的其它记录写入同一个数据库事务日志。

    日志的大小取决于事务吞吐量、数据更改的大小和检查点之间的时间(每次检查点,重做日志被截断并重新开始扩展)。

    与基于磁盘的表相比,MOT使用较少的日志带宽和较低的IO争用。这由多种机制实现。

    例如,MOT不会在事务完成之前记录每个操作。它只在提交阶段记录,并且只记录更新的增量记录(不像基于磁盘的表那样的完整记录)。

    为了确保日志IO设备不会成为瓶颈,日志文件必须放在具有低延迟的驱动器上。

MOT内存和存储规划 - 图5 说明: 有关配置的更多信息,请参阅存储(MOT)