1、简介

DB2 合理使用内存,可以防止过度分配内存,并有助于对内存的使用进行调优,从而获得更好的性能。以下分享将对DB2的内存结构以及如何合理分配内存做简单介绍。

 

2、DB2 内存结构概述

首先,我们用图1说明 DB2 内存结构。这种内存结构在所有平台上都是一致的;另外如果在多分区环境中,下面的图适用于多分区实例中的每个分区。

图1 DB2 内存结构

db2执行计划结果 id含义 db2执行计划图详解_java

DB2 在 4 种不同的内存集(memory set)内拆分和管理内存。这 4 种内存集分别是:

1.   实例共享内存(instance shared memory)

2.   数据库共享内存(database shared memory)

3.   应用程序组共享内存(application group shared memory)

4.   代理私有内存(agent private memory)

每种内存集由各种不同的内存池(亦称堆)组成。图 1 也给出了各内存池的名称。例如,locklist是属于数据库共享内存集的一个内存池。 sortheap是属于代理私有内存集的一个内存池。

实例共享内存

每个 DB2 实例都有一个实例共享内存。实例共享内存是在数据库管理器启动(db2start)时分配的,并随着数据库管理器的停止(db2stop)而释放。这种内存集用于实例级的任务,例如监控、审计和节点间通信。下面的数据库管理器配置(dbm cfg)参数控制着对实例共享内存以及其中个别内存池的限制:

1.   实例内存( instance_memory)。

2.   监视器堆( mon_heap_sz):用于监控。

3.   Audit Buffer( audit_buf_sz):用于 db2audit 实用程序。

4.   Fast Communication buffers ( fcm_num_buffers):用于分区之间的节点间通信。仅适用于分区的实例。

instance_memory参数指定为实例管理预留的内存数量。默认值是 AUTOMATIC。这意味着 DB2 将根据监视器堆、审计缓冲区和 FCM 缓冲区的大小计算当前配置所需的实例内存数量。此外,DB2 还将分配一些额外的内存,作为溢出缓冲区。每当某个堆超出了其配置的大小时,便可以使用溢出缓冲区来满足实例共享内存区内任何堆的峰值需求。在这种情况下,个别堆的设置是 软限制的,它们可以在内存使用的峰值期间进一步增长。

如果instance_memory被设置为某一个数字,则采用instance_memory与mon_heap_sz、audit_buf_sz和fcm_num_buffers的和之间的较大者。这时,对实例内存就施加了一个硬性的限制,而不是软限制。当达到这个限制时,就会收到内存分配错误。出于这个原因,建议将instance_memory的设置保留为AUTOMATIC。

如果instance_memory被设为AUTOMATIC,则可以使用下面的命令来确定它的值:

1.   db2 attach to instance_name(其中 instance_name是实例的名称)

2.   db2 get dbm cfg show detail

下面的输出表明有 42 MB 的内存被预留给实例共享内存集(10313 页 * 4096 字节/页):

1.   Size of instance shared memory (4KB) (INSTANCE_MEMORY) = AUTOMATIC(10313) AUTOMATIC(10313)

instance_memory参数只是设置了实例共享内存的限制。它并没有说出当前使用了多少内存。要查明一个实例的内存使用情况,可以使用 DB2 内存跟踪器工具db2mtrk。例如,

1.   db2start

2.   db2mtrk -i -v

Memory for instance

FCMBP Heap is of size 17432576 bytes

Database Monitor Heap is of size 180224 bytes

Other Memory is of size 3686400 bytes

Total: 21299200 bytes

上面的例子表明,虽然预留给实例共享内存集的内存有 42 MB,但在db2mtrk运行时只用到了大约 21 MB。注意:在某些情况下,db2mtrk显示的大小会大于指定给配置参数的值。在这种情况下,赋予配置参数的值被作为一种软限制,内存池实际使用的内存可能会增长,从而超出配置的大小。

 

数据库共享内存

每个数据库有一个数据库共享内存集。数据库共享内存是在数据库被激活或者第一次被连接上的时候分配的。该内存集将在数据库处于非激活状态时释放(如果数据库先前是处于激活状态)或者最后一个连接被断开的时候释放。这种内存用于数据库级的任务,例如备份/恢复、锁定和 SQL 的执行。

图2展示了数据库共享内存集内的各种内存池。括号中显示了控制这些内存池大小的配置参数。

图 2 - DB2 数据库共享内存

db2执行计划结果 id含义 db2执行计划图详解_db2执行计划结果 id含义_02

完整的绿色方框意味着,在数据库启动的时候,该内存池是完全分配的,否则,就只分配部分的内存。例如,当一个数据库第一次启动时,不管 util_heap_sz的值是多少,只有大约 16 KB 的内存被分配给实用程序堆。当一个数据库实用程序(例如备份、恢复、导出、导入和装载)启动时,才会按 util_heap_sz指定的大小分配全额的内存。

下面的公式可以计算出数据库共享内存集大致需要多少内存:

数据库共享内存 = (主缓冲池 + 4 个隐藏的缓冲池 + 数据库堆 +实用程序堆 + locklist + 包缓存 + 编目缓存) + (estore 的页数 * 100 字节) + 大约 10% 的开销

-------------------------------------------------------------------------------------

对于启用了 intra_parallel 或集中器情况下的数据库,共享排序内存必须作为数据库共享内存的一部分预先分配,因而上述公式变为:

数据库共享内存 = (主缓冲池 + 4 个隐藏的缓冲池 + 数据库堆 +实用程序堆 + locklist + 包缓存 + 编目缓存 + sheapthres_shr) + (estore 的页数 * 100 字节) + 大约 10% 的开销

-------------------------------------------------------------------------------------

提示: 为了发现分配给主缓冲池的内存有多少,可以发出: 
SELECT * FROM SYSCAT.BUFFERPOOLS

虽然大多数内存池的大小是由配置参数预先确定的,但下面两种内存池的大小在默认情况下却是动态的:

1.   包缓存: pckcachesz = maxappls * 8

2.   编目缓存: catalogcache_sz = maxappls * 4

3.   活动应用程序的最大数量: maxappls = AUTOMATIC

AUTOMATIC的效果是允许任意数量的连接数据库的应用程序。DB2 将动态地分配所需资源,以支持新的应用程序。因此,包缓存和编目的大小可以随着maxappls的值而变化。

除上述参数以外,database_memory也会影响数据库共享内存的数量。该参数的缺省值是 AUTOMATIC。表示 DB2 将根据以上列出的各内存池的大小来计算当前配置所需的数据库内存量。此外,DB2 还将为溢出缓冲区分配一些额外的内存。每当某个堆超出了其配置的大小时,便可以使用溢出缓冲区来满足实例共享内存区内任何堆的峰值需求。

如果database_memory被设为某个数字,则采用database_memory与各内存池之和这两者之间的较大者。

如果database_memory被设为 AUTOMATIC,则可以使用以下命令来显示它的值:

db2 get db cfg for dbname show detail

使用 db2mtrk 工具显示当前使用的内存量: db2mtrk -i -d -v

Memory for database: SAMPLE

   Backup/Restore/Util Heap is of size 16384   bytes

   Package Cache is of size 81920 bytes

   Catalog Cache Heap is of size 65536 bytes

   Buffer Pool Heap is of size 4341760 bytes

   Buffer Pool Heap is of size 655360 bytes

   Buffer Pool Heap is of size 393216 bytes

   Buffer Pool Heap is of size 262144 bytes

   Buffer Pool Heap is of size 196608 bytes

   Lock Manager Heap is of size 491520 bytes

   Database Heap is of size 3637248 bytes

   Other Memory is of size 16384 bytes

   Application Control Heap is of size 327680   bytes

    Application Group Shared Heap is of size   57344000 bytes

   Total: 67829760 bytes


应用程序组共享内存

这种共享内存集仅适用于以下环境。

1.   多分区(multi-partitioned)数据库。

2.   启用了内部并行(intra-parallel)处理的未分区(non-partitioned)数据库。

3.   支持连接集中器的数据库。

注意:当max_connections的值大于max_coordagents的值时,连接集中器便被启用。这两个参数可以在数据库管理器(DBM CFG)配置中找到。

在以上环境中,应用程序通常需要不止一个的代理来执行其任务。允许这些代理之间能够彼此通信(相互发送/接收数据)很有必要。为了实现这一点,我们将这些代理放入到一个称作 应用程序组的组中。属于相同应用程序组的所有 DB2 代理都使用应用程序组共享内存进行通信。

应用程序组内存集是从数据库共享内存集中分配的。其大小由appgroup_mem_sz数据库配置参数决定。

多个应用程序可以指派给同一个应用程序组。一个应用程序组内可以容纳的应用程序数可以这样计算: appgroup_mem_sz / app_ctl_heap_sz

在应用程序组内,每个应用程序都有其自己的 应用程序控制堆。此外,应用程序组共享内存中有一部分要预留给应用程序组共享堆。如下图3所示:

图3 - 应用程序组共享内存

db2执行计划结果 id含义 db2执行计划图详解_数据库_03

例 1 考虑以下数据库配置:

1.   最大应用程序内存集大小 (4KB) (APPGROUP_MEM_SZ) = 40000

2.   最大应用程序控制堆大小 (4KB) (APP_CTL_HEAP_SZ) = 512

3.   用于应用程序组堆的内存所占百分比 (GROUPHEAP_RATIO) = 70

可以计算出下面的值: 

1.   应用程序组共享内存集是: 40000 页 * 4K/页 = 160 MB

2.   应用程序组共享堆的大小是: 40000 * 70% = 28000 4K 页 = 114MB

3.   该应用程序组内可容纳的应用程序数为: 40000/512 = 78

4.   用于每个应用程序的应用程序控制堆为: (100-70)% * 512 = 153 4K 页 = 0.6MB

 

例 2 假设在一天中最忙的时间里,有 400 个应用程序连接到数据库上。 由于每个应用程序组可以容纳 80 个应用程序,因此我们需要 400/80 = 5 个应用程序组来容纳总共 400 个应用程序。这里应确保系统有足够多的 RAM 来支持这一配置。否则就会发生 SQL10003N 错误。

 

代理私有内存

每个 DB2 代理进程都需要获得内存,以执行其任务。代理进程将代表应用程序使用内存来优化、构建和执行访问计划,执行排序,记录游标信息(例如位置和状态),收集统计信息,等等。为响应并行环境中的一个连接请求或一个新的 SQL 请求,要为一个 DB2 代理分配代理私有内存。

代理的数量受下面两者中的较低者限制:

1.   所有活动数据库的数据库配置参数 maxappls 的总和,这指定了允许的活动应用程序的最大数量。

2.   数据库管理器配置参数 maxagents 的值,这指定了允许的最大代理数。

代理私有内存集由以下内存池组成。这些内存池的大小由括号中的数据库配置参数指定:

1.   Application Heap (applheapsz)

2.   Sort Heap (sortheap)

3.   Statement Heap (stmtheap)

4.   Statistics Heap (stat_heap_sz)

5.   Query Heap (query_heap_sz)

6.   Java Interpreter Heap (java_heap_sz)

7.   Agent Stack Size (agent_stack_sz) (仅适用于 Windows)

私有内存是在一个 DB2 代理被“指派”执行任务时分配给该代理的。私有内存的释放取决于 dbm cfg 参数 num_poolagents的值。该参数的值指定任何时候可以保留的闲置代理的最大数目。如果该值为 0,那么就不允许有限制代理。只要一个代理完成了它的工作,这个代理就要被销毁,它的内存也要返回给操作系统。如果该参数被设为一个非零值,那么一个代理在完成其工作后不会被销毁。相反,它将被返回到闲置代理池,直到闲置代理的数目到达 num_poolagents指定的最大值。当传入一个新的请求时,就要调用这些闲置代理来服务该新请求。这样就减少了创建和销毁代理的开销。

当代理变成闲置代理时,它仍然保留了其代理的私有内存。这样设计是为了提高性能,因为当代理被再次调用时,它便有准备好的私有内存。如果有很多的闲置代理,并且所有这些闲置代理都保留了它们的私有内存,那么就可能导致系统耗尽内存。为了避免这种情况,DB2 使用一个注册表变量来限制每个闲置代理可以保留的内存量。这个变量就是 DB2MEMMAXFREE。它的默认值是 8 388 608 字节。这意味着每个闲置代理可以保留最多 8MB 的私有内存。如果有 100 个闲置代理,那么这些代理将保留 800MB 的内存,因此它们很快就会耗尽 RAM。您可能希望降低或增加这一限制,这取决于 RAM 的大小。

图 4展示在同一个系统上有两个实例并发运行的情况。虚拟内存包括物理 RAM 和调页空间(paging space)。共享内存“倾向于”留在 RAM 中,因为对它们的访问更频繁。如果代理闲置了较长的一段时间,则其代理私有内存将被调出。

图 4 - 并发运行的两个 DB2 实例

db2执行计划结果 id含义 db2执行计划图详解_数据库_04

 

3、小结:

此次小结我们简单比较以下DB2与Oracle在内存架构上的不同:

DB2 和 Oracle 使用的都是共享内存块,但是 DB2 与 Oracle 内存架构的实现方式略有不同——

由于 DB2 实例可以包含多个数据库,因此存在两个级别的配置(DB2的一个实例可包含一个或多个数据库,Oracle的实例与数据库是一对一的关系)。 DB2实例级的配置可以在 DBM CFG 文件中完成,而数据库级的配置则可以在 DB CFG 文件中完成。这两个级别上的配置参数都可以进行调整,以调优内存使用情况。

Oracle 是在实例和数据库启动时将内存分配给它们的,而 DB2 则是在不同级别上分配内存。这主要是因为 DB2 实例可以包含多个数据库。



转载于:https://blog.51cto.com/5063935/2074303