http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0806xulong/
使用 OLTP (在线联机事务处理)的用户,高度关注数据库的并发能力和相应速度,同时他们也关注数据库的高可用性,但他们的数据库一般都比较小,完全能够全部放到内存中。本文介绍如何使用 Linux 内存盘 ( Ramdisk ) ,配置高性能、高可用性的 DB2 数据库服务器,从而提高企业自身的商业价值和核心竞争力。
本文提供了使用内存盘配置 DB2 数据库服务器的循序渐进的指南。其中包括:
- 如何配置 Linux 内存盘。
- 如何使用内存盘保存数据和日志。
- 如何使用归档日志和日志镜像。
- 相关的参数配置。
- 内存盘和 Buffer Pool 的比较。
本文假设您熟悉 DB2 Universal Database™( DB2 UDB)引擎,并且系统满足下列要求:
- 安装了 DB2 UDB 版本 9.1.3 或 9.5;
- 操作系统是 Linux 2.6 内核;
- 机器上具有足够的内存(2G 以上);
- 提高可用性需要 2 台或多台机器。
![]() ![]() |
![]()
|
Linux 系统可以将一部分内存虚拟成一个驱动器设备。应用程序可以象访问普通的硬盘分区一样访问内存盘。不同的是,写入内存盘的数据在关机时会全部丢失。因此,使用内存盘必须有完整的备份和恢复方案。
内存盘可以明显的提高数据访问速度,特别对需要频繁读写多个不连续扇区的操作,速度提高更明显。
内存盘的驱动程序可以直接编译进内核,也可以编译成模块在需要的时候加载。笔者使用的 Red Hat Enterprise Linux AS release 4 (Nahant Update 5) 默认已经加载了内存盘的驱动程序。( 关于如何加载内存盘驱动程序,读者可以参考 Linux 相关文档。)
Linux 内存盘的硬件接口文件在 /dev 目录下,ram0 到 ram15 共 16 个文件。每一个文件都可以初始成一个内存盘。未初始化之前,不占用内存空间。
用户可以使用下面的命令初始化一个内存盘 ( 该命令需要使用 root 用户运行 ):
/sbin/mkfs -t ext3 -b 1024 /dev/ram0
在上面的命令中,-b 1024 指定使用 1024 字节作为单个 block 块的大小,在不同版本的 linux 上,可以尝试修改该值,以保证初始化以后可以挂接 (mount) 到文件系统上。-t ext3 指定使用 ext3 格式初始化内存盘,用户可以根据自己的喜好选用不同的文件系统格式。
以上命令在笔者系统上运行的输出结果是:
默认的内存盘大小是 4M( 不同系统上,这个值可能会不同 )。可以通过修改 /etc/grub.conf 文件修改内存盘的大小。使用 root 用户,修改 grub.conf 文件中 kernel 开头的行,在最后添加 ramdisk_size=< 内存盘的大小 >:
kernel /boot/vmlinuz-2.6.9-55.ELsmp ro root=LABEL=/ rhgb quiet ramdisk_size=4194304
内存盘的大小以 K(1024 字节 ) 为单位,转化为 M 时需要除以 1024。另外,文件系统本身还要占用 2% 左右的空间。修改该文件以后,重启机器,并重新初始化内存盘。此时,可以看到内存盘已经修改为新的大小。
为避免内存盘占用太多内存,造成系统运行困难,内存盘的大小不应超过物理内存的 3/4。在内存比较小的机器上,要保证操作系统、数据库和其他应用程序至少有 1G 的可用物理内存。
建立内存盘要挂接的目录 ( 可能需要使用 root 用户执行 ):
mkdir /db2data
用户可以使用 mount 命令将初始化之后的内存盘挂接到文件系统中,命令是 ( 该命令需要使用 root 用户运行 ):
mount –t ext3 /dev/ram0 /db2data
在上面的命令中,-t ext3 说明内存盘的格式是 ext3,用户可以选择不同的格式,该格式需要和初始化内存盘时使用的格式相同。/dev/ram0 是经过初始化的内存盘设备,/db2data 是挂接的文件系统目录。
修改目录的权限 ( 需要使用 root 用户执行 ):
chmod –R 777 /db2data
修改内存盘设备的权限 ( 需要使用 root 用户执行 ):
chmod 660 /dev/ram0
另外,使用内存盘的用户,还应在 disk 组中。可以使用以下命令,将特定用户添加到 disk 组中 ( 需要使用 root 用户执行 ):
/usr/sbin/usermod –a –G disk <login>
挂接到文件系统以后,可以使用 df 命令查看挂接的状态:
df –k /db2data
以上命令在笔者系统上运行的输出结果是:
其中,Filesystem 项指出挂接的设备是 /dev/ram0;1K-blocks 项指出该目录下有多少个 1K 字节大小的块;Used 指出已经使用的块数;Available 指出用户可用的块数;Use% 指出使用百分比;Mounted on 指出挂接到目录的位置 /db2data。
![]() ![]() |
![]()
|
DB2 UDB 数据库的数据存放在表空间中,日志存放在日志文件中。通常,表空间的所有容器、所有的日志文件,都存放在磁盘 ( 或磁盘构成的存储设备 ) 上。这样,访问数据时需要大量的磁盘 IO。磁盘 IO 往往成为高负载数据库的瓶颈。本章探讨通过将数据容器和日志文件存放到内存盘中,从而提高数据库的性能。
创建 DB2 数据库时,可以指定将数据库创建在哪个目录上。此时,数据库的容器和日志文件都在指定的目录下。如果该目录实际上是内存盘的挂接点,或挂接点的子目录,那么数据库实际上就是建立在内存盘上。所有的数据库操作都不会引起磁盘 IO。
用户可以使用如下命令将数据库建立在特定目录上 ( 该命令需要具有 DBA 权限的用户执行 ):
db2 “create db testdb on /db2data”
运行上面的命令,会在 /db2data 目录上,建立一个名为 testdb 的数据库。关于 create db 更详细的用法和参数,用户可以参考 DB2 Information Center。
如果用户已按照上文的描述建立了内存盘,并挂接到 /db2data 上,那么新建立的 testdb 数据库就在内存盘上。只要不重启机器,不 umount 内存盘,那么就可以象操作在磁盘上数据库的一样,对 testdb 数据库进行各种操作。
但当用户需要重启机器,或者 umount 内存盘。用户有两种方法保存内存盘上的数据。
使用数据库的 backup/restore,保存内存盘上的数据
DB2 数据库可以在脱机或联机状态下对数据库进行备份。这些数据库备份文件,可以用于恢复数据库。用户如果使用这种方式保存内存盘上的数据,在重启或 umount 内存盘前,应进行如下操作:
1. 关闭所有数据库连接
db2 “force application all”
2. Backup 数据库
db2 “backup db testdb to /db2backup”
3. 备份日志文件 ( 可以通过 db2 get db cfg 查看日志所在目录,并将日志文件拷贝到磁盘上 )
db2 “get db cfg for testdb”
4. 停止数据库服务器
db2stop
重启或重新 mount 内存盘后,可以使用数据库的备份文件恢复内存盘上的数据库。具体操作如下:
1. 启动数据库服务器
db2start
2. Restore 数据库
db2 “restore db testdb from /db2backup”
3. 恢复日志文件 ( 可以通过 db2 get db cfg 查看日志所在目录,并把日志文件从备份处拷贝到日志目录 ) 前滚
db2 “rollforward db testdb to end of logs”
db2 “rollforward db testdb complete”
通过数据库的 backup/restore 保存内存盘的数据。DB2 数据库生成的备份文件的大小和备份前表空间占用的大小几乎相同。备份文件可以在脱机或联机的状态下生成。该文件除了用来保存数据库数据外,还是支持高可用性配置的基础。( 本文将在后面介绍使用内存盘提高数据库的高可用性。)
用户还可以选择使用操作系统的命令备份内存盘中的数据。如果选用这种方式备份数据,在重启或 umount 内存盘前,用户应进行如下操作:
1. 停止数据库服务器
db2stop
2. 使用操作系统命令备份数据 ( 示例:使用 tar 备份数据库 )
tar –cvzf /db2backup/testdb.tar.gz /db2data
重启或重新 mount 内存盘后,使用备份的文件恢复内存盘上的数据。具体操作如下:
1. 首先确认数据库服务器是关闭的,清空数据库所在目录
rm –fr /db2data/*
2. 使用操作系统命令恢复数据
cd /db2data
tar –xvzf /db2backup/testdb.tar.gz
3. 启动数据库
db2start
使用 tar –cvzf 可以生成压缩后的打包文件。采用这种方法生成的打包文件的大小比数据库的备份文件的大小要小的多。生成也比数据库的 backup 要快,操作相对简单。缺点是,这个命令只能在数据库服务器停止或暂挂的时候运行,并且缺乏对高可用性配置的支持。另外,使用 tar 命令是需要特别注意数据库目录的权限。
注:在一些版本的 linux 上,重启或重现 mount 内存盘,可能改变挂接点的权限。mount 以后,需要把挂接点的权限,修改为正常值。
在一些大型的应用系统上,数据库的数据可能会达到几百个 G 甚至更多。此时,使用内存盘保存整个数据库不太可行。但是,把读写频繁的日志文件建立在内存盘上,不但可以提高数据库的访问速度、增加磁盘寿命,还可以为高可用性配置提供便利。本部分描述,如何把日志文件单独存放在内存盘上。
用户在决定将日志文件存放在内存盘之前,首先需要计算日志文件的大小。运行时,当所有的活动日志文件被写满,尚未完成的事务就会失败,并被 rollback。因此,用户应保证日志的大小满足日常操作的要求。这需要考虑在通常情况下需要的日志大小,以及在两种极端情况需要的日志大小。这两种极端情况是:
- 在应用程序最繁忙的时候,这时并发的应用最多,但是每个应用占用的日志大小相对较小。此时,应通过实验,得出平均每个事务占用的日志数,并乘以并发的应用的个数。
- 在执行批量操作时,此时往往是业务不太繁忙的时候,但是执行批量操作的应用,往往会在一个事务中执行较多的操作。因此,往往需要占用相当大的日志文件。这种情况下,可以通过修改应用程序,强制应用在每执行几万到几十万个操作就执行一次 commit 或 rollback。这种控制一次提交数量的方法,还可以同时提高应用程序的效率。
在 DB2 数据库中,活动日志分为主要日志 (primary) 和次要日志 (second)。DB2 数据库的主要日志文件,会在数据库被“激活”的同时建立。这通常发生于第一次 connect 时 ( 有时用户可能会被第一次链接的漫长时间折磨的发狂,内存盘有治疗这种狂躁症的功效 J
)。数据库运行时主要日志文件会被循环使用。通常设定主要日志文件的大小应满足绝大多数应用,在绝大多数时间的要求。
当未结束的事务将主要日志文件占满,数据库就会启用次要日志文件。次要日志文件也会被循环使用。所有的活动日志文件 ( 主要日志文件和次要日志文件 ) 一旦被分配就不会释放,直到数据库退出。因为,活动日志大小不够时,可能引起事务回滚,因此在实际业务系统上,次要文件往往被设置的足够大。但如果要使用内存盘作为活动日志目录,用户就要考虑在满足业务需求的前提下,尽量减小次要日志文件的大小。即使配置了溢出日志路径 (overflowlogpath),也是如此。
根据主要和次要日志的大小,用户可以选择内存盘的大小,并通过修改 NEWLOGPATH 参数,为日志文件指定存放目录。( 修改这个参数后,需要重新启动数据库才能生效。)
db2 update db cfg using NEWLOGPATH /db2data/log
当用户把日志文件放在内存盘后,日志缓冲区的作用会减小。因此,用户可以通过将日志缓冲区设置为较小的值,以节约内存。
db2 update db cfg using LOGBUFSZ 256
在做过一些测试以后,用户可能会发现,单纯使用内存盘提高效率并不明显。这是因为许多数据库默认的参数,并不适合使用内存盘的情况,因此需要对许多参数进行配置,以提高性能,同时避免过度使用内存。
在了解如何进行配置前,用户首先需要了解 DB2 数据库的内存分配。下图描述了 DB2 如何进行内存分配。用户可以从 DB2 Information Center 中找到 DB2 进行内存分配的更详细的描述。
需要注意的是,在有的 Linux 系统上,内存盘占用的内存,不是在 mkfs 或 mount 时一次性分配的。在数据库运行期间,随着数据的写入,内存盘占用的内存会逐渐增大。此时,如果将 DB2 自动调整内存的功能打开,那么在业务高峰时,会导致内存盘和 DB2 数据库管理器争抢内存。因此,强烈建议用户关闭数据库的自调整内存功能,并对数据库的参数进行手动的调节。
db2 update db cfg using SELF_TUNING_MEM OFF
在进行参数调节时以下几个要点需要特别注意:
- 因为,内存盘的速度比磁盘的速度快很多,因此通过配置大 Bufferpool 来提高数据读写速度的方法,作用很小。但是,需要注意的是,数据库仍要把数据读入 Bufferpool,才能对其操作。因此,Bufferpool 至少要能容下所有未完成的事务和未完成的查询所要占用的数据页。用户应在业务高峰或进行最密集的批量操作时,通过实验确定 Bufferpool 的大小。
- 当数据库建立在磁盘上时,因为磁盘和内存速度的巨大差距,因此需要对 SQL 语句进行精致而复杂的优化。如果使用内存盘,这个优化过程就显的复杂而不必要。可以将 SQL 语句的优化等级降低为 3 或 2。( 对使用 XML 的用户,仍建议使用默认的优化级别 )
db2 update db cfg using DFT_QUERYOPT 3
- 使用内存盘创建的数据库,因为所有的读写操作,实际上都仅在内存中进行,所以建立多个 Index 对写入速度的影响,明显减小。但是,Index 对读操作的效率提升仍然有效。基于这个特性,用户可以考虑适当多建一些 Index。
- 考虑合适的 runstats 时机。使用内存盘以后,对 runstats 有 2 个方面的影响。一方面,因为读写速度加快,对 runstats 的要求减低,这样可以减少 runstats 的运行频率。另一方面,因为运行 runstats 的速度更快,因此用户可以更频繁的运行 runstats。因此,用户应重新考虑 runstats 运行的时机。
- 使用内存盘创建的数据库,其数据的读写速度,与其在内存盘上所在的位置无关。因此,使用 reorg 提升速度的效果非常微弱。但是,数据库仍需要使用 reorg 来释放被删除的数据占用的空间。因此,用户需要根据内存盘的大小和数据的多少决定 reorg 的时机,而不是为了提高速度进行 reorg。
- 使用内存盘以后,数据库同时并发的事务可以得到很大提高。但是,任何一个并发的应用都需要占用一定的内存。过多的并发还会使 locklist 占用的内存增加,并增加锁等待的概率。因此,用户需要谨慎的根据服务器内存的数量和业务的需要,来确定允许的并发访问的数量,防止因为过多的并发带来的各种问题。
- 使用内存盘以后,主要的瓶颈不再是磁盘 IO。因此根据 CPU 数目,建立多 partition 的数据库,将有效提高读写速度。同时,修改并行相关的参数,提高并行度,也有助于提高读写速度。
- 如果建立多 partition 的数据库,那么建立多个内存盘,保证每个 partition 都访问一个盘。同时也为日志指定单独的内存盘。这样对提高效率是有帮助的。
- 对仅使用内存盘保存日志的用户,写操作时的主要瓶颈会由日志,转化到对表空间的读写上。适当增加 Bufferpool 可以减少对表空间的读写频率。
- 应谨慎修改 sort 和 join 相关的参数,保证尽可能的使用 HASH join。