DB2 9.5 中多线程架构的工作原理概述 |
|
级别: 中级
Shashank Kharche, 专职软件工程师, IBM
2008 年 11 月 06 日
DB2® 9.5 for Linux®, UNIX®, and Windows®(代号为 “Viper 2”)中引入了新的多线程功能。了解当您需要经常性地监视进程或线程、需要理解数据库正在使用多少内存,或者当您需要简化备份、恢复和前滚等任务关键型工作时,DB2 9.5 中的新功能如何提供帮助。您将了解到这些新特性如何影响配置参数,并学习 DB2 9.5 中的新技术。
为了理解 DB2 9.5 中新的多线程功能,本文首先讨论 DB2 进程模型。整个 DB2 进程模型是由 Base System Utilities(BSUs)控制的。BSU 为实例和数据库分配内存,拦截和处理信号,并处理发送到 DB2 的异常。图 1显示了用于 Linux 和 UNIX 平台的旧的 DB2 进程模型。
图 1. Linux 和 UNIX 上旧的 DB2 进程模型
图 2 显示了 Linux 和 UNIX 上新的进程模型。
图 2. Linux 和 UNIX 上新的 DB2 进程模型
数据库服务器、客户机与应用程序之间的通信由一个框架来处理。这种框架正是所有 DB2 服务器都使用的进程模型。它确保内部使用的数据库文件不会干扰用户或数据库应用程序。
引擎分派单元(engine dispatchable units,EDU)负责执行各种任务,例如处理数据库应用程序请求、读取数据库日志文件以及将日志记录从日志缓冲区刷新到磁盘上的日志文件。通常,DB2 服务器将每个任务作为一个单独的 EDU 进行处理。在 DB2 9.5 之前,大多数这样的 EDU 在 UNIX 和 Linux 环境中是进程,而在 Windows 环境中是线程。而在 9.5 中,DB2 的进程模型得到统一,现在 EDU 在 Linux、 UNIX 和 Windows 环境中都是线程。
下面是这种新的内存模型的一些优点:
- 这种新的内存模型更加简单,而且更易于配置。请参阅 DB2 Information Center 中的以下内容:
- 这种模型可以节省资源:
使用的系统文件描述符明显减少。进程与线程之间最明显的区别就是,一个进程的所有线程都共享相同的内存空间和系统定义的设施。这些设施包括打开文件句柄(文件描述符)、共享内存、进程同步原语和当前目录。一个进程中的所有线程可以共享相同的文件描述符。这里不需要让每个代理维护它自己的文件描述符表。 - 性能得到提高:
操作系统通常可以在相同进程中的不同线程之间更快速地切换(上下文切换),而不是在不同进程之间切换。这种切换不需要切换地址空间。由于全局内存是共享的,几乎不必分配新的内存,因此创建一个线程比创建一个进程更简单、更快捷。就处理器周期和使用的内存而言,创建进程的代价较高。 - 有更高的自动化程度和动态的可配置参数,因此 DBA 更轻松。
本文的 进程模型配置简化 小节中将对此加以阐述。 - 现在,进程模型在所有三个平台上是一样的:Linux、UNIX 和 Windows。
在 DB2 9.5 之前,在 UNIX 和 Linux 环境中,通过 ps 系统命令或 db2_local_ps 命令,可以列出所有活动的 DB2 EDU。然而,在 DB2 9.5 中,这些命令不再列出 db2sysc 进程中的任何 EDU 线程。因此,当 DB2 用户和 DBA 使用一个 OS 命令查看系统上正在运行的进程时,一个变化是,他们只能看到一个进程,而不是多个进程。从 DBA 的角度来看,这正是您期望的管理方面的变化。
$ ps -fu db2ins10 UID PID PPID C STIME TTY TIME CMD db2ins10 1237176 2109662 0 Feb 28 - 0:12 db2acd 0 db2ins10 1921136 2109662 0 Feb 28 - 0:14 db2sysc 0 db2ins10 2101494 1941686 0 14:22:34 pts/1 0:00 -ksh db2ins10 2420958 2101494 0 15:25:33 pts/1 0:00 ps -fu db2ins10 |
在 AIX 上:
查看 db2sysc 进程(PID = 1921136)中的所有线程:
清单 1. 在 AIX 系统上查看 db2sysc 进程的所有线程
$ ps -mo THREAD -p 1921136
USER PID PPID TID ST CP PRI SC WCHAN F TT BND COMMAND
db2ins10 1921136 2109662 - A 0 60 26 * 40401 - - db2sysc 0
- - - 1273899 S 0 60 1 f1000100403674b0 410400 - - -
- - - 1327331 Z 0 60 1 - c00001 - - -
- - - 1392805 Z 0 60 1 - c00001 - - -
- - - 1601705 Z 0 60 1 - c00001 - - -
- - - 1814627 Z 0 60 1 - c00001 - - -
- - - 1851457 S 0 60 1 f1000004f010de00 410400 - - -
- - - 1961987 Z 0 60 1 - c00001 - - -
- - - 1974311 Z 0 60 1 - c00001 - - -
- - - 2023571 S 0 60 1 f100010041b401b0 410400 - - -
- - - 2068591 Z 0 60 1 - c00001 - - -
- - - 2179161 Z 0 60 1 - c00001 - - -
- - - 2187515 Z 0 60 1 - c00001 - - -
- - - 2216003 S 0 60 1 - 400400 - - -
- - - 2412647 Z 0 60 1 - c00001 - - -
- - - 2551911 Z 0 60 1 - c00001 - - -
- - - 2592969 Z 0 60 1 - c00001 - - -
- - - 2621455 S 0 60 1 f1000100407f7e30 410400 - - -
- - - 2658531 S 0 60 1 - 418400 - - -
- - - 3031171 Z 0 60 1 - c00001 - - -
- - - 3457047 Z 0 60 1 - c00001 - - -
- - - 3899477 Z 0 60 1 - c00001 - - -
- - - 4157609 Z 0 60 1 - c00001 - - -
- - - 4390991 S 0 60 1 - 400400 - - -
- - - 4636819 Z 0 60 1 - c00001 - - -
- - - 5628153 S 0 60 1 - 400400 - - -
- - - 6783009 Z 0 60 1 - c00001 - - -
|
在 Linux 上:
查看 db2sysc 进程(PID = 1921136)的所有线程: ps -lLfp 1921136
DBA 现在变得更轻松了。db2pd 也得到增强,可以列出进程和线程。现在可以使用 db2pd 命令和 -edu 选项列出所有活动的 EDU 线程。该命令在 UNIX、Linux 和 Windows 系统上都可以使用。
清单 2. 在 Linux 系统上查看 db2sysc 进程的所有线程
$ db2pd -edu
Database Partition 0 -- Active -- Up 1 days 01:05:54
List of all EDUs for database partition 0
db2sysc PID: 1921136
db2wdog PID: 2109662
db2acd PID: 1237176
EDU ID TID Kernel TID EDU Name USR SYS
===================================================================================
1801 1801 2216003 db2agent (idle) 0 0.706935 1.071737
1543 1543 5628153 db2resync 0 0.002641 0.004271
1286 1286 1851457 db2ipccm 0 0.082388 0.044037
1029 1029 2023571 db2licc 0 0.000211 0.001055
772 772 4390991 db2thcln 0 0.000244 0.000105
515 515 2621455 db2aiothr 0 2.740874 6.287562
2 2 1273899 db2alarm 0 0.274076 0.408226
258 258 2658531 db2sysc 0 2.085981 1.379128
|
|
下面是查看内存使用情况的一些方法:
- db2pd -dbptnmem
- 使用 db2 get 按样获得应用程序快照
- select * from table(admin_get_dbp_mem_usage())
- db2mtrk -a 和 db2mtrk -p
注意以下信息:
- db2pd 显示共享内存分级结构的准确表示
- db2pd 仍不能报告私有内存的分配情况
- db2mtrk 可以报告私有内存的分配情况,但在其他方面比较弱
- 私有内存的使用情况不再那么值得关心
- db2pd -dbpntmem 高级报告可能已经足够
清单 3. db2pd 示例
$ db2pd -dbptnmem Database Partition 0 -- Active -- Up 1 days 01:11:27 Database Partition Memory Controller Statistics Controller Automatic: Y Memory Limit: 13994636 KB Current usage: 76608 KB HWM usage: 332736 KB Cached memory: 16064 KB Individual Memory Consumers: Name Mem Used(KB) HWM Used(KB) Cached(KB) ======================================================== DBMS-db2ins10 46784 46784 10048 FMP_RESOURCES 22528 22528 0 PRIVATE 7296 7296 6016 |
字段信息:
如果 INSTANCE_MEMORY 配置参数被设为 AUTOMATIC,则 Controller Automatic 被设为 Y。这意味着数据库管理器自动确定内存使用的上限。
Memory Limit 是 DB2 服务器可使用内存的上限。它是 INSTANCE_MEMORY 配置参数的值。
Current usage 是服务器当前使用的内存量。
HWM usage 是当 db2start 命令在运行时,自数据库分区激活以来的最高水位标记(high water mark,HWM)或峰值内存使用量。
Cached memory 是当前使用量(current usage)当中目前没有被使用,而是由于性能原因缓存起来用于将来的内存请求的内存。
Individual Memory Consumers 部分:
- 列出了 DB2 服务器中所有注册的内存 “消耗者”,以及它们消耗的总内存量。
- Name:内存 “消耗者” 的一个简洁、易于辨别的名称。例如:
- 对于用于数据库 <dbname> 的应用程序内存,名称为:APPL-<dbname>
- 对于全局数据库管理器内存需求,名称为:DBMS-xxx
- 对于与 db2fmps 通信所需的内存,名称为 FMP_RESOURCES
- 对于各种私有内存需求,名称为 PRIVATE
- 对于 Fast Communication Manager 资源,名称为 FCM_RESOURCES
- 对于用于与本地应用程序通信的内存段,名称为:LCL-<pid>
- 对于用于数据库 <dbname> 的数据库内存,名称为 DB-<dbname>
- Mem Used(KB):当前有多少内存被分配给某个消耗者。
- HWM Used(KB):该消耗者曾使用的内存的高水位标记或峰值。
- Cached(KB):在 Mem Used(KB)当中,当前没有使用,而是备用于将来内存分配的内存量。
清单 4. db2 get 快照示例
$ db2 get snapshot for applications on sample Memory usage for application: Memory Pool Type = Application Heap Current size (bytes) = 65536 High water mark (bytes) = 65536 Configured size (bytes) = 1048576 Agent process/thread ID = 6463 Agent Lock timeout (seconds) = -1 Memory usage for agent: Memory Pool Type = Other Memory Current size (bytes) = 196608 High water mark (bytes) = 196608 Configured size (bytes) = 16710107136 |
清单 5. 使用 SQL 示例
$ db2 "select * from table(admin_get_dbp_mem_usage())" DBPARTITIONNUM MAX_PARTITION_MEM CURRENT_PARTITION_MEM PEAK_PARTITION_MEM -------------- -------------------- --------------------- -------------------- 0 14330507264 340590592 340852736 1 record(s) selected. |
清单 6. db2mtrk -a 示例
$ db2mtrk -a Tracking Memory on: 2008/02/29 at 15:51:00 Application Memory for database: SAMPLE appshrh 128.0K Memory for application 546 apph other 64.0K 192.0K Memory for application 545 apph other 64.0K 192.0K Memory for application 544 apph other 64.0K 320.0K Memory for application 543 apph other 64.0K 576.0K Memory for application 547 apph other 64.0K 192.0K |
清单 7. db2mtrk -p 示例
$ db2mtrk -p Tracking Memory on: 2008/02/29 at 15:51:37 Memory for agent 6463 other 192.0K Memory for agent 6206 other 192.0K Memory for agent 5949 other 320.0K Memory for agent 2094 other 576.0K Memory for agent 6720 other 192.0K |
注意:默认情况下,INSTANCE_MEMORY 被设为 AUTOMATIC,这意味着实例被允许使用 RAM 的一个最大百分值(对于较小的系统,范围是 75%,对于较大的系统,范围是 95%)。这包括一个单独的实例的所有本地分区。
db2 get dbm cfg show detail|grep INSTANCE_MEMORY Size of instance shared memory(4KB)(INSTANCE_MEMORY)=AUTOMATIC(3498659)AUTOMATIC(3498659) |
不能永久地为不同的数据库分区设置不同的 INSTANCE_MEMORY 值。对于一个 DB2 Express 许可,INSTANCE_MEMORY 的上限被进一步限制为至多 4GB 内存(1,048,576 * 4KB 页)。DB2 Workgroup 许可被限制为至多 16GB 内存(4,194,304 * 4KB 页)。如果尝试将 INSTANCE_MEMORY 配置参数更新为大于这些限制的值,那么会遭到失败,并收到 SQL5130N 返回码,指定该许可允许的限制范围。其他许可类型没有附加的限制。不能将 INSTANCE_MEMORY 设为大于 RAM。
|
在之前的 DB2 版本上:
$ db2_all " db2 backup db test" Backup successful. The timestamp for this backup image is : 20080304124529 eva88: db2 backup db test completed ok Backup successful. The timestamp for this backup image is : 20080304124544 eva88: db2 backup db test completed ok Backup successful. The timestamp for this backup image is : 20080304124554 eva88: db2 backup db test completed ok |
然而,在 DB2 9.5 中,BACKUP 命令得到增强,现在可以接收一组数据库分区,并提供一个单独的系统视图。
$ db2 backup db test on all dbpartitionnums Part Result ---- ------------------------------- 0000 DB20000I The BACKUP DATABASE command completed successfully. 0010 DB20000I The BACKUP DATABASE command completed successfully. Backup successful. The timestamp for this backup image is : 20080304135942 |
$ db2 rollforward db test to 2008-03-01 and stop SQL1275N The stoptime passed to roll-forward must be greater than or equal to "2008-03-04-12.45.54.000000 UTC", because database "TEST" on node(s) "0,1" contains information later than the specified time. $ db2 rollforward db test to 2008-03-04-12.45.54.000000 and stop DB20000I The ROLLFORWARD command completed successfully. |
以上例子表明,在前滚期间,如果命令中指定的时间点(PIT)过早,那么会收到错误消息(SQL1275N)。该错误消息告诉您正确的 PIT。可以考虑使用 BACKUP 和 INCLUDE 日志。但是,在 DPF 数据库中,BACKUP 和 INCLUDE 日志会生成错误消息(SQL2032N)。因此,不能使用该方法。
然而,在 DB2 9.5 中,可以使用 “TO END OF BACKUP” 子句和 ROLLFORWARD 命令将一个分区数据库中的所有分区前滚到最小恢复时间。这个最小恢复时间是前滚期间数据库处于一致状态(数据库编目中列出的对象与磁盘上物理存在的对象相匹配)的最早时间点。手动地确定前滚一个数据库的正确时间点比较困难,对于分区数据库更是如此。而 “END OF BACKUP” 选项可以使这件事变得容易起来。
$ db2 rollforward db test to end of backup and stop DB20000I The ROLLFORWARD command completed successfully |
|
用户限制(User limits)设置或显示一个 shell 在资源使用方面的不同限制。它是一个很好的实践,可用于设置一些限制,防止诸如一个有错误的 shell 脚本开始无限制的自我复制之类的问题,或者防止系统上的用户启动永远运行的进程。但是,将它设置成什么呢?下面是对于资源的不同限制的一些考虑:
- 在 db2 启动时,数据和 nofile 是无限制的。
- 栈限制不重要,因为 DB2 创建它自己的栈空间(AGENT_STACK_SZ dbm cfg)
在 64 位 UNIX 上
Default : 4 MB
Minimum : 1 MB
Maximum : 128 MB
在 32 位 LINUX 上
Default : 1MB
Minimum : 64 KB
Maximum : 4MB
- MAXFILOP 是每数据库每分区的最大值。对于 32 位,新的默认最大值是 ~32K,对于 64 位,新的默认最大值是 ~64K。
- 当前 ulimit 设置(或者,在 AIX 上,如果 ulimit 被设为 unlimited,则为 8GB)。DB2 改写了一个 unlimited 的内核限制。为了得到一个大于 8GB 的内核,必须显式地将内核限制设为大于 8GB 的值,而不是设为 unlimited。
|
在本节中,您将看到在 DB2 9.5 中配置参数有什么不同的行为。注意默认值和范围,因为它们与之前不同。
图 3. 配置参数
如果有性能关键型、非隔离的(unfenced)外部存储过程(SP)或用户定义函数(UDF),那么应确保它们是线程安全的。在迁移时,所有外部的、非隔离 SP 和 UDF 都将变为有隔离(fenced)。
按照惯例,为确保数据完整性,非隔离 SP 和 UDF 应该已经是线程安全的,但是,这不是强制性的。在一个多线程的进程中运行一个非线程安全的 SP 或 UDF 会导致不可预测的问题。因此,在迁移过程中,应创建一个脚本,以便实现对非隔离的转换。
在开始使用之前,先快速查看一下新引入的线程和进程:
- db2thcln(线程栈清理):当一个 EDU 终止时回收资源(仅在 UNIX 上)。
- db2aiothr(aio 收集器线程):管理数据库分区的异步 I/O 请求(仅在 UNIX 上)。
- db2alarm(报警线程):当 EDU 请求的计时器到期时通知 EDU(仅在 UNIX 上)。
- db2vend(隔离的供应商进程):代表一个 EDU 执行供应商代码,使实例执行用户退出程序,以便进行日志归档(仅在 UNIX 上)。
- db2extev(外部事件处理程序线程):与 SIGUSR2 相同。
- db2acd:一个健康监视器进程。
最后,如果升级到 DB2 9.5,会影响当前已有的应用程序吗?
答案是不会,完全不会。这个内部变化根本不会影响应用程序。实际上,从管理和应用程序编程的角度来看,它很大程度上是透明的。