服务器 频道

DB2如何使用内存(上篇)

  应用程序组共享内存

  这种共享内存集仅适用于以下环境。(对于其他环境,这种内存集不存在。)

  • 多分区(multi-partitioned)数据库。
  • 启用了内部并行(intra-parallel)处理的未分区(non-partitioned)数据库。
  • 支持连接集中器的数据库。

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

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

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

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

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

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

 

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

  • 最大应用程序内存集大小 (4KB) (APPGROUP_MEM_SZ) = 40000
  • 最大应用程序控制堆大小 (4KB) (APP_CTL_HEAP_SZ) = 512
  • 用于应用程序组堆的内存所占百分比 (GROUPHEAP_RATIO) = 70

  

  可以计算出下面的值:

  • 应用程序组共享内存集是: 40000 页 * 4K/页 = 160 MB
  • 应用程序组共享堆的大小是: 40000 * 70% = 28000 4K 页 = 114MB
  • 该应用程序组内可容纳的应用程序数为: 40000/512 = 78
  • 用于每个应用程序的应用程序控制堆为: (100-70)% * 512 = 153 4K 页 = 0.6MB

  

  不要被 app_ctrl_heap_sz 参数迷惑。这个参数不是一个应用程序组内用于每个应用程序的各应用程序控制堆的大小。它只是在计算这个应用程序组内可容纳多少应用程序时用到的一个值。每个应用程序的实际应用程序控制堆大小都是通过 图 3中给出的公式计算的,这个公式就是 ((100 - groupheap_ratio)% * app_ctrl_heap_sz)。

  因此,groupheap_ratio 越高,应用程序组共享堆就越大,从而用于每个应用程序的应用程序控制堆就越小。

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

  代理私有内存

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

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

  • 所有活动数据库的数据库配置参数 maxappls 的总和,这指定了允许的活动应用程序的最大数量。
  • 数据库管理器配置参数 maxagents 的值,这指定了允许的最大代理数。

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

  • Application Heap ( applheapsz
  • Sort Heap ( sortheap
  • Statement Heap ( stmtheap
  • Statistics Heap ( stat_heap_sz
  • Query Heap ( query_heap_sz
  • Java Interpreter Heap ( java_heap_sz
  • 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 的大小。

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

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

 

  共享内存与私有内存

  至此,我们已经讨论了实例共享内存、数据库共享内存和应用程序组共享内存以及代理私有内存。但是共享内存和私有内存的意义是什么呢?

  为了理解共享内存与私有内存之间的不同之处,首先让我们通过快速阅读 DB2 进程 model来了解一下 DB2 代理进程。在 DB2 中,所有数据库请求都是由 DB2 代理或子代理来服务的。例如,当一个应用程序连接到一个数据库时,就有一个 DB2 代理指派给它。当该应用程序发出任何数据库请求(例如一个 SQL 查询)时,该代理就会出来执行完成这个查询所需的所有任务 —— 它代表该应用程序工作。(如果数据库是分区的,或者启用了 intra-parallel,那么可以分配不止一个的代理来代表应用程序工作。这些代理叫做 子代理。)

  每个代理或子代理都被当作一个 DB2 进程,它获得一定数量的内存来执行工作。这种内存被称作 代理私有内存—— 它不能与其他任何代理共享。之前我们曾提到过,代理私有内存包括一些内存池,例如应用程序堆大小、排序堆大小和语句堆大小。(参见 图 1)

  除了私有内存(代理在其中使用 排序堆执行“私有”任务,例如私有排序)外,代理还需要数据库级的资源,例如缓冲池、 locklist和日志缓冲区。这些资源在数据库共享内存中(参见 图 1)。 DB2 的工作方式是,数据库共享内存中的所有资源都由连接到相同数据库的所有代理或子代理共享。因此,该内存集被称作共享内存,而不是私有内存。例如,连接到数据库 A 的代理 x 使用数据库 A 的数据库共享内存中的资源。现在又有一个代理,即代理 y 也连接到数据库 A。那么代理 y 将与代理 x 共享数据库 A 的数据库内存。(当然,代理 x 和代理 y 都有其自己的代理私有内存,这些代理私有内存不是共享的。)

  这样的逻辑同样适用于实例共享内存和应用程序组共享内存。

  下图展示了当两个 DB2 代理(代理 x 和代理 y)连接到数据库 A 时分配的 DB2 内存集。假设:

  • 数据库 A 属于实例 db2inst1。
  • 数据库 A 为应用程序组 1 启用了 intra-parallel。
  • 代理 x 和 代理 y 都属于应用程序组 1。

  图 5 - DB2 代理进程内存地址空间

 

  图 5 展示了在 RAM 中分配的以下内存集:

  • 用于实例 db2inst1 的实例共享内存集。
  • 用于 数据库 A 的数据库共享内存集。
  • 用于 应用程序组 1 的应用程序组共享内存。
  • 用于代理 x 的代理私有内存集。
  • 用于代理 y 的代理私有内存集。
  • 为内核和库之类的东西预留的内存。

  代理 x 和代理 y 共享相同的实例内存、数据库内存和应用程序组内存,因为它们属于相同的实例、相同的数据库和相同的应用程序组。此外,它们有其自己的代理私有内存。

  每个 DB2 代理进程都有其自己的内存地址空间。在内存空间中的内存地址允许代理访问物理 RAM 中的内存。我们可以把这些地址看作指向 RAM 的指针,如 图 5所示。对于任何 DB2 进程,这个地址空间必须能够容纳上述所有 4 种内存集。

  前面已提到,ESTORE 是用于扩展缓冲池的大小。那么您可能要问,为什么不创建一个更大的缓冲池呢。答案是:因为地址空间受到限制,地址空间可能容不下一个更大的缓冲池!在此情况下,需要定义一个较小的地址空间能够容纳的缓冲池。如果有过量的物理内存,那么可以用该内存来配置 ESTORE。

  那么,我们怎么知道一个 DB2 代理的地址空间是多大呢?地址空间的大小取决于当前的实例是 32 位的实例还是 64 位的实例。我们将在下一节对此进行解释。

  32 位体系结构与 64 位体系结构中的可寻址内存

如果有一个 64 位的 DB2 实例,则意味着 DB2 使用的是 64 位的内存体系结构。在这种体系结构中,对于所有平台,每个进程的地址空间都是 2 的 64 次方,或者 18,446,744,073 GB。这是一个相当巨大的内存。将所有 DB2 内存集放入这个地址空间应该没有问题。

  另一方面,如果有一个 32 位 DB2 实例,则对于所有平台,地址空间只有 2 的 32 次方,或者 4 GB(Linux/390 平台除外,在此平台下地址空间实际上只有 2 的 31 次方。不过,在本文中我们不讨论 Linux/390 中的 DB2)。所以,不管物理 RAM 有多大,要使一个 DB2 进程能够访问它所需的所有资源,包括实例共享内存、数据库共享内存、应用程序组共享内存、它自己的代理私有内存以及用于内核的内存等,所有这些资源必须能放入到 4GB 的地址空间内。

  这就导致了两个非常重要的问题:

  • 应该为实例内存、数据库内存和应用程序共享内存分配多少的内存,以使它们能放入到 4GB 的可寻址空间?
  • 应该如何配置 图 1中列出的每个参数,以最有效地利用可用的内存?

  虽然 4GB 的地址空间限制适用于所有平台,但是对于上述问题的回答却与平台有关。例如,在 AIX 系统上可以分配给 DB2 数据库的最大数据库内存数就与 Solaris 系统上的数据库不同。接下来的几节将讨论不同的平台对 DB2 中的内存配置有何影响。

  注意: 本文的后续部分只针对 32 位内存体系结构。我们即将讨论的问题不适用于 64 位的体系结构。

  32 位 AIX 中的 DB2 内存配置

在 32 位的 AIX 上,4GB 的可寻址内存空间被拆分为 16 个段,每段 256MB。 图 6展示了用于一个 DB2 代理进程的 32位 内存地址空间。(假设 DB2_MMAP_READ 和 DB2_MMA_WRITE 这两个 DB2 注册表变量都被设为 NO。如果这两个变量没有设为 NO,则表示方法会有点不同。我们将在后面解释。)

  图 6 - AIX 中的 DB2 32 位内存地址空间

 

  段 0 - 预留给 AIX 内核。

  段 1 - 预留给 db2sysc 进程。

  段 2 - 预留给代理私有内存。

  段 3 - 预留给实例共享内存。

  段 4 到段 B - 数据库共享内存始于段 4,这些段必须紧挨在一起。所有这 8 个段(2GB)可能都被用于数据库共享内存。但是,下面的每种配置都会从数据库共享内存中拿出一个段(256MB)。

  注意: 对于下面的每种配置,DB2 将从数据库共享内存中拿出一个段,这个段始于段 B。

  

  • 如果数据库是分区的,或者启用了 intra-parallel 或连接集中器,那么数据库共享内存中有一个段被预留给应用程序组共享内存。
  • Fast Communication Manager (FCM):FCM 用于系统物理节点上不同分区之间的通信。默认情况下,这种通信是通过 UNIX socket 进行的。如果 DB2_FORCE_FCM_BP 被设为 YES,那么 FCM 通信发生在共享内存内。这意味着数据库共享内存中有一个段被预留给 FCM 通信。虽然 FCM 通信变得更快,但是它也令数据库共享内存减少了一个段。
  • fenced UDF 和存储过程:如果数据库上运行着一个 fenced 函数或过程,那么数据库共享内存中有一个段要预留给 fenced 模式的通信。
  • 如果数据库允许任何本地连接,那么数据库共享内存中有一个段要预留给代理/本地应用程序通信。如果将所有本地连接配置为 loopback 连接,那么就可以为这些连接使用 TCP/IP,而不需要共享内存(即使数据库就在服务器本地)。这样就有效地为数据库共享内存空出一个段来。

      

    然而,如果您不想使用 loopback 解决方案,还有一种方法可以迫使 DB2 选择段 E 来用于代理/本地应用程序通信,这样数据库共享内存就不受影响(即不会减少)。请参阅后面的解释。

  

  • 如果启用了 ESTORE,那么还要从数据库共享内存中拿出另一个段。因此,如果启用 ESTORE,则应确保它至少是 256MB,否则就不起作用,因为要从数据库共享内存中拿出一个 256 MB 的段来仅用于管理这个 ESTORE。建议将 estore 段的大小( estore_seg_sz)设为 256MB,然后根据可用的内存更改段的数目( num_estore_segs)。

  

  段 C - 预留给 DB2 跟踪使用程序。

  段 D 和 F- 预留给 DB2 共享库

  段 E - 在默认情况下,这个段是不用的。不过,如果设置 DB2_MMAP_READ=NO 和 DB2_MMAP_WRITE=NO,那么该段用于 DB2 代理以及本地应用程序之间的通信(如 图 6所示)。这将有效地为数据库共享内存一个段。

  注意: 为了最大化数据库共享内存的空间,应使用以下注册表变量设置:DB2_FORCE_FCM_BP=NO (该值是默认值),DB2_MMAP_READ=NO,DB2_MMAP_WRITE=NO。

0
相关文章