DB2内存使用基础.docx
- 文档编号:10599146
- 上传时间:2023-02-21
- 格式:DOCX
- 页数:34
- 大小:679.39KB
DB2内存使用基础.docx
《DB2内存使用基础.docx》由会员分享,可在线阅读,更多相关《DB2内存使用基础.docx(34页珍藏版)》请在冰豆网上搜索。
DB2内存使用基础
【导读】本文将向您讲解DB2内存使用的基础,以及共享内存和私有内存的概念。
这些内容同时适用于32位和64位的系统。
简介
理解DB2如何使用内存,可以防止过度分配内存,并有助于对内存的使用进行调优,从而获得更好的性能。
本文将向您传授DB2内存使用的基础,以及共享内存和私有内存的概念。
这些内容同时适用于32位和64位的系统。
虽然对于64位系统有一些限制,但是在未来的一段时间内还不大可能触及这些限制。
因此,我们将焦点放在影响32位系统的内存限制,并对之进行详细的讨论。
我们首先讨论一般情况下DB2如何使用内存,接着讨论内存管理如何随着平台(AIX、Sun、HP、Linux和Windows)的不同而变化,以及它们对DB2的影响。
最后,我们将给出一些实际生活中客户处境/问题以及他们的解决方案的有意义的例子。
本文的内容适用于DB2version8。
DB2内存结构概述
图1中说明了DB2内存结构。
这种内存结构在所有平台上都是一致的。
注意:
在多分区环境中,下面的图适用于多分区实例中的每个分区。
图1-DB2内存结构
DB2在4种不同的内存集(memoryset)内拆分和管理内存。
这4种内存集分别是:
实例共享内存(instancesharedmemory)
数据库共享内存(databasesharedmemory)
应用程序组共享内存(applicationgroupsharedmemory)
代理私有内存(agentprivatememory)
每种内存集由各种不同的内存池(亦称堆)组成。
图1也给出了各内存池的名称。
例如,locklist是属于数据库共享内存集的一个内存池。
sortheap是属于代理私有内存集的一个内存池。
我们将详细讨论每一种内存集。
实例共享内存
每个DB2实例都有一个实例共享内存。
实例共享内存是在数据库管理器启动(db2start)时分配的,并随着数据库管理器的停止(db2stop)而释放。
这种内存集用于实例级的任务,例如监控、审计和节点间通信。
下面的数据库管理器配置(dbmcfg)参数控制着对实例共享内存以及其中个别内存池的限制:
实例内存(instance_memory)。
监视器堆(mon_heap_sz):
用于监控。
AuditBuffer(audit_buf_sz):
用于db2audit实用程序。
FastCommunicationbuffers(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,则可以使用下面的命令来确定它的值:
db2attachtoinstance_name(其中instance_name是实例的名称)
db2getdbmcfgshowdetail
下面的输出表明有42MB的内存被预留给实例共享内存集(10313页*4096字节/页):
Sizeofinstancesharedmemory(4KB)(INSTANCE_MEMORY)=AUTOMATIC(10313)AUTOMATIC(10313)
instance_memory参数只是设置了实例共享内存的限制。
它并没有说出当前使用了多少内存。
要查明一个实例的内存使用情况,可以使用DB2内存跟踪器工具db2mtrk。
例如,
db2start
db2mtrk-i-v
Memoryforinstance
FCMBPHeapisofsize17432576bytes
DatabaseMonitorHeapisofsize180224bytes
OtherMemoryisofsize3686400bytes
Total:
21299200bytes
上面的例子表明,虽然预留给实例共享内存集的内存有42MB,但在db2mtrk运行时只用到了大约21MB。
注意:
在某些情况下,db2mtrk显示的大小会大于指定给配置参数的值。
在这种情况下,赋予配置参数的值被作为一种软限制,内存池实际使用的内存可能会增长,从而超出配置的大小。
数据库共享内存
每个数据库有一个数据库共享内存集。
数据库共享内存是在数据库被激活或者第一次被连接上的时候分配的。
该内存集将在数据库处于非激活状态时释放(如果数据库先前是处于激活状态)或者最后一个连接被断开的时候释放。
这种内存用于数据库级的任务,例如备份/恢复、锁定和SQL的执行。
图2展示了数据库共享内存集内的各种内存池。
括号中显示了控制这些内存池大小的配置参数。
图2-DB2数据库共享内存
完整的绿色方框意味着,在数据库启动的时候,该内存池是完全分配的,否则,就只分配部分的内存。
例如,当一个数据库第一次启动时,不管util_heap_sz的值是多少,只有大约16KB的内存被分配给实用程序堆。
当一个数据库实用程序(例如备份、恢复、导出、导入和装载)启动时,才会按util_heap_sz指定的大小分配全额的内存。
主缓冲池
数据库缓冲池通常是数据库共享内存中最大的一块内存。
DB2在其中操纵所有常规数据和索引数据。
一个数据库必须至少有一个缓冲池,并且可以有多个缓冲池,这要视工作负载的特征、数据库中使用的数据库页面大小等因素而定。
例如,页面大小为8KB的表空间只能使用页面大小为8KB的缓冲池。
可以通过CREATEBUFFERPOOL语句中的EXTENDEDSTORAGE选项“扩展”缓冲池。
扩展的存储(ESTORE)充当的是从缓冲池中被逐出的页的辅助缓存,这样可以减少I/O。
ESTORE的大小由num_estore_segs和estore_seg_sz这两个数据库配置参数来控制。
如果使用ESTORE,那么就要从数据库共享内存中拿出一定的内存,用于管理ESTORE,这意味着用于其他内存池的内存将更少。
这时您可能要问,为什么要这么麻烦去使用ESTORE?
为什么不分配一个更大的缓冲池呢?
答案跟可寻址内存(而不是物理内存)的限制有关,我们在后面会加以讨论。
隐藏的缓冲池
当数据库启动时,要分配4个页宽分别为4K、8K、16K和32K的小型缓冲池。
这些缓冲池是“隐藏”的,因为在系统编目中看不到它们(通过SELECT*FROMSYSCAT.BUFFERPOOLS显示不出)。
如果主缓冲池配置得太大,则可能出现主缓冲池不适合可寻址内存空间的情况。
(我们在后面会谈到可寻址内存。
)这意味着DB2无法启动数据库,因为一个数据库至少必须有一个缓冲池。
如果数据库没有启动,那么就不能连接到数据库,也就不能更改缓冲池的大小。
由于这个原因,DB2预先分配了4个这样的小型缓冲池。
这样,一旦主缓冲池无法启动,DB2还可以使用这些小型的缓冲池来启动数据库。
(在此情况下,用户将收到一条警告(SQLSTATE01626))。
这时,应该连接到数据库,并减少主缓冲池的大小。
排序堆的阈值(sheapthres,sheapthres_shr)
如果没有索引满足所取的行的要求顺序,或者优化器断定排序的代价低于索引扫描,那么就需要进行排序。
DB2中有两种排序,一种是私有排序,一种是共享排序。
私有排序发生在代理的私有代理内存(在下一节讨论)中,而共享排序发生在数据库的数据库共享内存中。
对于私有排序,数据库管理器配置参数sheapthres指定了私有排序在任何时刻可以消耗的内存总量在实例范围内的软限制。
如果一个实例总共消耗的私有排序内存达到了这一限制,那么为额外传入的私有排序请求所分配的内存将大大减少。
这样就会在db2diag.log中看到如下消息:
"Notenoughmemoryavailablefora(private)sortheapofsizesizeofsortheap.Tryingsmallersize..."
如果启用了内部分区并行性(intra-partitionparallelism)或者集中器(concentrator),那么当DB2断定共享排序比私有排序更有效时,DB2就会选择执行共享排序。
如果执行共享排序,那么就会在数据库共享内存中分配用于这种排序的排序堆。
用于共享排序的最大内存量是由sheapthres_shr数据库参数指定的。
这是对共享排序在任何时刻可以消耗的内存总量在数据库范围内的硬限制。
当达到这个限制时,请求排序的应用程序将收到错误SQL0955(rc2)。
之后,在共享内存总消耗量回落到低于由sheapthres_shr指定的限制之前,任何共享排序内存的请求都得不到允许。
下面的公式可以计算出数据库共享内存集大致需要多少内存:
数据库共享内存=(主缓冲池+4个隐藏的缓冲池+数据库堆+实用程序堆+locklist+包缓存+编目缓存)+(estore的页数*100字节)+大约10%的开销
对于启用了intra_parallel或集中器情况下的数据库,共享排序内存必须作为数据库共享内存的一部分预先分配,因而上述公式变为:
数据库共享内存=(主缓冲池+4个隐藏的缓冲池+数据库堆+实用程序堆+locklist+包缓存+编目缓存+sheapthres_shr)+(estore的页数*100字节)+大约10%的开销
提示:
为了发现分配给主缓冲池的内存有多少,可以发出:
SELECT*FROMSYSCAT.BUFFERPOOLS
虽然大多数内存池的大小是由它们的配置参数预先确定的,但下面两种内存池的大小在默认情况下却是动态的:
包缓存:
pckcachesz=maxappls*8
编目缓存:
catalogcache_sz=maxappls*4
活动应用程序的最大数量:
maxappls=AUTOMATIC
将maxappls设为AUTOMATIC的效果是,允许任意数量的连接数据库的应用程序。
DB2将动态地分配所需资源,以支持新的应用程序。
因此,包缓存和编目的大小可以随着maxappls的值而变化。
除了上述参数以外,还有一个参数也会影响数据库共享内存的数量。
这个参数就是database_memory。
该参数的缺省值是AUTOMATIC。
这意味着DB2将根据以上列出的各内存池的大小来计算当前配置所需的数据库内存量。
此外,DB2还将为溢出缓冲区分配一些额外的内存。
每当某个堆超出了其配置的大小时,便可以使用溢出缓冲区来满足实例共享内存区内任何堆的峰值需求。
如果database_memory被设为某个数字,则采用database_memory与各内存池之和这两者之间的较大者。
如果database_memory被设为AUTOMATIC,则可以使用以下命令来显示它的值:
db2connecttodbnameuseruseridusingpwd
db2getdbcfgfordbnameshowdetail
使用db2mtrk工具显示当前使用的内存量:
db2mtrk-i-d-v(在Windows中,-i必须指定。
在UNIX中,-i是可选的。
)
Memoryfordatabase:
SAMPLE
Backup/Restore/UtilHeapisofsize16384bytes
PackageCacheisofsize81920bytes
CatalogCacheHeapisofsize65536bytes
BufferPoolHeapisofsize4341760bytes
BufferPoolHeapisofsize655360bytes
BufferPoolHeapisofsize393216bytes
BufferPoolHeapisofsize262144bytes
BufferPoolHeapisofsize196608bytes
LockManagerHeapisofsize491520bytes
DatabaseHeapisofsize3637248bytes
OtherMemoryisofsize16384bytes
ApplicationControlHeapisofsize327680bytes
ApplicationGroupSharedHeapisofsize57344000bytes
Total:
67829760bytes
应用程序组共享内存
这种共享内存集仅适用于以下环境。
(对于其他环境,这种内存集不存在。
)
多分区(multi-partitioned)数据库。
启用了内部并行(intra-parallel)处理的未分区(non-partitioned)数据库。
支持连接集中器的数据库。
注意:
当max_connections的值大于max_coordagents的值时,连接集中器便被启用。
这两个参数可以在数据库管理器配置中找到。
(使用GETDBMCFG显示数据库管理器配置。
)
在以上环境中,应用程序通常需要不止一个的代理来执行其任务。
允许这些代理之间能够彼此通信(相互发送/接收数据)很有必要。
为了实现这一点,我们将这些代理放入到一个称作应用程序组的组中。
属于相同应用程序组的所有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/页=160MB
应用程序组共享堆的大小是:
40000*70%=280004K页=114MB
该应用程序组内可容纳的应用程序数为:
40000/512=78
用于每个应用程序的应用程序控制堆为:
(100-70)%*512=1534K页=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的值,这指定了允许的最大代理数。
代理私有内存集由以下内存池组成。
这些内存池的大小由括号中的数据库配置参数指定:
ApplicationHeap(applheapsz)
SortHeap(sortheap)
StatementHeap(stmtheap)
StatisticsHeap(stat_heap_sz)
QueryHeap(query_heap_sz)
JavaInterpreterHeap(java_heap_sz)
AgentStackSize(agent_stack_sz)(仅适用于Windows)
我们曾提到,私有内存是在一个DB2代理被“指派”执行任务时分配给该代理的。
那么,私有内存何时释放呢?
答案取决于dbmcfg参数num_poolagents的值。
该参数的值指定任何时候可以保留的闲置代理的最大数目。
如果该值为0,那么就不允许有限制代理。
只要一个代理完成了它的工作,这个代理就要被销毁,它的内存也要返回给操作系统。
如果该参数被设为一个非零值,那么一个代理在完成其工作后不会被销毁。
相反,它将被返回到闲置代理池,直到闲置代理的数目到达num_poolagents指定的最大值。
当传入一个新的请求时,就要调用这些闲置代理来服务该新请求。
这样就减少了创建和销毁代理的开销。
当代理变成闲置代理时,它仍然保留了其代理的私有内存。
这样设计是为了提高性能,因为当代理被再次调用时,它便有准备好的私有内存。
如果有很多的闲置代理,并且所有这些闲置代理都保留了它们的私有内存,那么就可能导致系统耗尽内存。
为了避免这种情况,DB2使用一个注册表变量来限制每个闲置代理可以保留的内存量。
这个变量就是DB2MEMMAXFREE。
它的默认值是8388608字节。
这意味着每个闲置代理可以保留最多8MB的私有内存。
如果有100个闲置代理,那么这些代理将保留800MB的内存,因此它们很快就会耗尽RAM。
您可能希望降低或增加这一限制,这取决于RAM的大小。
图1展示了一个DB2实例的DB2内存结构。
图4将展示在同一个系统上有两个实例并发运行的情况。
虚拟内存包括物理RAM和调页空间(pagingspace)。
共享内存“倾向于”留在RAM中,因为对它们的访问更频繁。
如果代理闲置了较长的一段时间,则其代理私有内存将被调出。
图4-并发运行的两个DB2实例
[img]
[/img]
共享内存与私有内存
至此,我们已经讨论了实例共享内存、数据库共享内存和应用程序组共享内存以及代理私有内存。
但是共享内存和私有内存的意义是什么呢?
为了理解共享内存与私有内存之间的不同之处,首先让我们通过快速阅读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共享相同的实例内存、数据库内存和应用程序组内存,因为它们属于相同的实例、相同的数据库和相同的应用程序组
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- DB2 内存 使用 基础