服务器 频道

DB2如何使用内存(下篇)

  例 3

  考虑如下配置: (所有页的大小都为 4K)

  服务器:

  • 服务器上的物理 RAM 6GB
  • Instance 1 (3 个数据库)

  数据库 A:

  • IBMDEFAULTBP 140,000 页
  • UTILHEAP 7,500 页
  • DBHEAP 20,000 页
  • LOCKLIST 10,000 页
  • PCKCACHE 5000 页
  • CATALOGCACHE 2500 页
  • APPGROUP_MEM_SZ 20,000 页

  数据库 B:

  • IBMDEFAULTBP 80,000 页
  • UTILHEAP 2500 页
  • DBHEAP 10,000 页
  • LOCKLIST 20,000 页
  • PCKCACHE 5000 页
  • CATALOGCACHE 2500 页
  • APPGROUP_MEM_SZ 20,000 页

  数据库 C:

  • IBMDEFAULTBP 130,000 页
  • UTILHEAP 7,500 页
  • DBHEAP 20,000 页
  • LOCKLIST 10,000 页
  • PCKCACHE 5000 页
  • CATALOGCACHE 2500 页
  • APPGROUP_MEM_SZ 20,000 页

  限制: 由于物理 RAM 只有 1GB,数据库共享内存集只能映射到它在物理上可以使用的那些空间,即 1GB + 交换空间。

  计算:

  • 数据库 A 共享内存 = (185,000 页 x 4KB/页) x 1.1% = ~814MB
  • 数据库 A 应用程序组内存 = 20,000 页 x 4KB/页 = 80MB
  • 数据库 B 共享内存 = (120,000 页 x 4KB/页) x 1.1% = ~528MB
  • 数据库 B 应用程序组内存 = 20,000 页 x 4KB/页 = 80MB
  • 数据库 C 共享内存 = (175,000 页 x 4KB/页) x 1.1% = ~770MB
  • 数据库 C 应用程序组内存 = 20,000 页 x 4KB/页 = 80MB
  • 要启动数据库 A,要求: 816MB + 80MB = ~894MB
  • 要启动数据库 B,要求: 530MB + 80MB = ~608MB
  • 要启动数据库 C,要求: 772MB + 80MB = ~850MB

  问题: 启动数据库 A 和数据库 B 成功。但是启动数据库 C 时失败,并返回如下错误:
SQL1478W The defined buffer pools could not be started. Instead, one small buffer pool for each page size supported by DB2 has been started. SQLSTATE=01626

  在这里,物理内存不是问题,因为我们有足够多的 RAM(6GB)。进一步的测试得处了以下启动组合:

  • 启动 A + B ->成功
  • 启动 B + C ->成功
  • 启动 A + C ->不成功
  • 启动 (A + B) + C ->不成功
  • 启动 (B + C) + A ->不成功

  组合 (A + B) 和组合 (B + C) 获得成功,因为它们初始化数据库所需的共享内存总量分别是 1.5GB (894 + 608) 和 1.46GB (608+850)。这低于 1.75GB 的共享内存限制,并且每个数据库共享内存段可以安全地连续映射到一个象限。而其他组合将失败于 SQL1478W,因为它们要么超出了 1.75GB 共享内存限制,要么不能在一个象限内为一个数据库分配连续的共享内存段。

  要解决这一问题:

  • 实现内存窗。最好的解决方案是定义 3 个 DB2 实例。将一个数据库恢复到每个实例。并为每个实例创建一个内存窗。这样一来,每个实例都可以完全访问它自己的 1GB 内存窗共享内存空间。注意: max_mem_windows 内核参数必须设为 2 (实例数 -1)。

  32-位 Linux/Intel 中的 DB2 内存配置

  图 12中展示了 32 位 Linux/Intel 上的 4GB 可寻址内存。

  图 12 - Linux/Intel 中的 DB2 32 位内存地址空间

 

  从 0x08048000 到 0x0FFFFFFF 的段是预留给 db2sysc 可执行程序的。

  从 0x10000000 到 0x3FFFFFFF 的段是实例共享内存,总共是 0.75GB。

  在默认情况下,DB2 共享库始于 0x40000000。

  在低地址装载共享库,而将更多的空间留给数据库共享内存,这是可行的。(这也意味着用于实例共享内存的空间将更少。但是由于实例内存与数据库内存相比通常比较小,因此这样可以获得好处。)例如,如果在低于 0x40000000 的地址装载共享库,那么就可以在 0x38000000 装载数据库共享内存。如果在低于 0x2a000000 的地址装载共享库,那么就可以在 0x30000000 装载数据库共享内存,这样就有超过 2GB 的空间留给数据库共享内存。这些更改要求重新编译内核,我们在本文中不会对此加以讨论。请参考 Linux 手册中内核重编译那一节,以了解更多信息。

  不过,对于 Redhat Advanced Server 和 SuSE SLES 8 上的 v8.1 FP2,DB2 将尝试自动将共享库重新分配到一个较低的地址,这样就不需要重新编译内核。在这些企业发行版中,有一个叫做 /proc/ pid/mapped_base 的文件包含了一个地址,共享库将从该地址装载到内存。在默认情况下,该地址是 0x40000000,但是我们可以把它降低一些(降到 0x20000000)。当 db2sysc 启动时,我们检查 mapped_base 文件是否存在。如果存在,则使用新的值并重新执行。然后,mapped_base 值发生了改变的进程中产生的每个进程都使用这个新值。

  数据库共享内存(包括缓冲池)始于 0x50000000 (默认值)。它从 0x50000000 开始朝着堆栈方向向下增长。堆栈包含要执行的指令。堆栈从 0xC0000000 开始向上增长。

  使数据库共享内存和堆栈不发生冲突,这一点很重要。我建议为堆栈使用 16MB 这么大的空间。在这样的情况下,我们有 ~1.73GB 用于数据库共享内存(从 0x50000000 到 0xC0000000,减去 16MB 的堆栈)。

  在使用 "ulimit -a" 或 "ulimit -s" 显示限制时,这些值是以 1K 字节为单位显示的。
Stack = 16384

  设置这个限制,使堆栈和共享内存地址空间不会相互冲突,这一点很重要。如果它们之间有冲突,那么实例就会崩溃,并发出信号 4 或信号 11。

  最后 1GB 的内存 被预留给 Linux 内核。

  您可能已经注意到,没有用于代理私有内存的段。这就对了,在 32 位的 Linux/Intel 中,没有预留特定的段给私有内存。代理私有内存是从共享库之间的任意空闲空间中分配的。

  为了看一看这里是如何使用内存的,请参阅叫作 /proc/ PID/maps 的文件,其中 PID 是 db2agent 进程的进程 ID。 图 12展示了 maps 文件的示例输出。

  图 13 - db2sysc 进程的 maps 文件

 

  从 图 13 中可以观察到下面一些情况:

  • 从 0x10000000 开始的绿色的段是实例共享内存。
  • 共享库从 0x40000000 开始装载。在共享库之间,橙色的段是代理私有内存。
  • 绿色是数据库共享内存,始于 0x50000000。
  • 最后一个紫色的段是堆栈。
0
相关文章