本章我们将描述HornetQ的持久化技术,包括持久化的工作原理和配置方法。
HornetQ拥有一个高性能的日志(journal)模块来处理持久化。因此它并不依赖一个外部的数据库或第三方持久化产品。这个 日志模块针对消息的处理进行了高度的优化。
所谓HornetQ日志是一个只添加系统。它由一组磁盘文件构成。每个文件都是预先创建好的并且 大小是固定的。文件在创建时都进行了格式化。随着HornetQ不断地处理消息,如消息的增加、更新、删除等,一个个记录被添加 到日志中。当一个日志文件写满时,新记录就会写到下一个文件。
由于对日志的写入只是对文件的添加,这样有效减少了随机寻道的操作。而随机寻道的操作是磁盘操作中最耗时的操作。 所以这种设计可以使磁头的运动降到最低,效率最高。
而文件的大小是可以配置的。这使我们可以将文件大小配置为刚好占满一个磁盘柱面。不过现代的磁盘技术是复杂多样的, 我们并不能控制文件与磁盘柱面的对应关系。尽管如此,我们通过最大限度地降低文件对磁盘柱面的占用,来降低磁头的运动。 这是因为在同一个柱面的存取只需要盘面的转动而不需要磁头的运动。
当被删除的记录越来越多时,有的文件最終会变成一个没有有效记录的文件。这样的文件就可以回收再利用。HornetQ有 一套复杂的文件回收算法来判断一个日志文件是否可以被回收。
HornetQ还有一套文件整理的算法,它用来将日志文件中不用的空隙移除以达到更高的存贮效率。
这个日志系统全面支持事务功能。根据需要它可以支持本地事务或XA型事务。
日志系统的大部分是用Java实现的,但是HornetQ在其中实现了一层抽象的文件系统,这样就使得其它的语言实现能 方便地“插入”到日志模块中。实际上HornetQ自带有两种实现:
Java NIO。
第一种采用的是标准的Java NIO接口来进行文件的操作。它可以在任何安装有Java 1.6或以上的系统中运行。 NIO的性能是很高的。
第二种是采用的Linux系统中的异步IO技术(AIO)。它包括了少量的平台相关的代码(native code)来 调用AIO的接口。当数据被保存到磁盘上后,AIO会回调HornetQ进行通知。这样,HornetQ就避免了磁盘写 的同步操作。
使用AIO通常可以有比NIO更高的性能。
采用AIO的日志只能在运行 Linux kernel 2.6 或以上版本的内核的系统中才有。另外你需要安装libaio。 有关如何安装libaio请参见 Section 15.5, “安装AIO”。
另外请注意AIO只在以下文件系统上能正确工作:ext2, ext3, ext4, jfs, xfs。其他文件系统如NFS,虽然 AIO看上去可以工作,实际上是以较慢的同步的方式在运行。所以不要在NFS上使用日志。
有关libaio的更多介绍参见 Chapter 40, Libaio平台专有库。
libaio是Linux内核项目的一部分。
标准的HornetQ核心服务器使用了两种日志:
绑定日志
这个日志用来保存与绑定有关的数据。其中包括在HornetQ上部署的队列及其属性,还有ID序列计数器。
绑定日志是一个NIO型日志。与消息日志相比它的呑吐量是比较低的。
JMS日志
这个日志保存所有JMS相关的数据,包括JMS队列,话题及连接工厂,以及它们的JNDI绑定信息。
通过管理接口创建的JMS资源将被保存在这个日志中。但是通过配置文件配置的资源则不保存。只有使用JMS时JMS的日志 才被创建。
消息日志
这个日志用来存贮所有消息相关的数据,包括消息本身和重复ID缓存。
默认情况下HornetQ总是优先使用AIO型日志。如果AIO型日志不可用(比如在非Linux平台上运行,或系统内核版本不同) 它将自动使用NIO型日志。
对于超大消息,Hornet将它们保存在消息日志之外的地方。详见Chapter 23, 大消息.
HornetQ还可以在内存不够用时将消息暂存到磁盘上。相关的配置和说明参见Chapter 24, 分页转存。
如果不需要持久功能,HornetQ还可以配置成非持久的消息系统。参见Section 15.6, “配置HornetQ不使用持久化”。
绑定日志的配置参数在 hornetq-configuration.xml文件中。
bindings-directory
这是绑定日志的位置。默认值是data/bindings。
create-bindings-dir
如果设置为true,那么在 bindings-directory 所设定的位置不存在的情况下会自动创建它。默认值是true。
消息日志的配置在hornetq-configuration.xml文件中。
这是消息日志文件所在的目录。默认值是 data/journal。
为以达到最佳性能,我们建议将日志设定到属于它自己的物理卷中以减少磁头运动。如果日志的位置与 其它进程共用(如数据库,绑定日志或事务的日志等)则磁头的运动显然要增加很多。性能也就没有保证了。
如果消息日志是贮存在SAN中,我们建议每个日志都拥有自己的LUN(逻辑单元)。
如果设为true,则当journal-directory所指定的日志目录不存在时,会自动创建它。默认值是true。
有效值是NIO 或者 ASYNCIO。
Choosing NIO chooses the Java NIO journal. Choosing AIO 选择作用异步IO型日志。如果你的平台不是Linux或者你没有安装 libaio,HornetQ会自动检测到并使用NIO。
如果设为true,HornetQ会保证在事务的边界操作时(commit, prepare和rollback)将事务数据 写到磁盘上。默认的值是 true。
journal-sync-non-transactional
如果设为true HornetQ将保证每次都将非事务性消息数据(发送和通知)保存到磁盘上。默认值是 true。
每个日志文件的大于。单位为字节。默认值是 10485760 bytes (10MiB)。
最少日志文件数。当HornetQ启动时会创建这一数量的文件。
创建并初始化日志文件是一项费时的操作,通常不希望这些操作在服务运行时执行。预先创建并初始化这些 日志文件将会使HornetQ在工作时避免浪费不必要的时间。
根据你的应用中队列中消息量的实际要求可以适当调节这一参数。
写请求被放到一个队列中,然后再被发送到系统中执行。这个参数限制了在任一时间队列中可以存放的最大数量 的写请求。如果队列达到这个限制,任何新的写请求都将被阻塞,直到队列中有空位为止。
当使用NIO时,这个参数必须为 1。
当使用AIO时,它的默认值是500。
系统根据不同类型的日志提供不同的默认值。(NIO 为 1, AIO 为 500)。
如果是AIO,这个参数的上限不能超过操作系统的限制(/proc/sys/fs/aio-max-nr),这个值通常为65536.
日志模块中有一个内部缓冲。每次写的内容并不是都立即写到磁盘上,而是先放到这个内部缓存中。当这个缓存已满时,或 者超过了一定的时间(timeout),才将缓存的数据存到硬盘上。NIO和AIO都有这一特点。采用缓存的方式可以很好地满足 大量并发写数据的需要。
这一参数规定了缓存的失效时间,如果过了这个时间,即使缓存还没有满,也将数据写入磁盘中。AIO的写入 能力通常要比NIO强。因此系统对于不同类型的日志有着不同的默认值。( NIO的默认值是 3333333 纳秒,即每秒300次。 而AIO则是500000纳秒,即每秒2000次。)
加在这个参数有可能会增加系统的呑吐量,但可能会降低系统的响应能力。通常情况下默认值应该是比较理想的折中选择。
AIO的定时缓冲的大小,默认值为490KiB。
进行整理压缩日志操作的最少文件数。当日志文件少于这个数时,系统不会进行文件的整理压缩。
默认值是 10。
开始整理压缩的界限值。当有效数据的比例少于这个值时系统开始整理压缩日志。注意是否进行压缩还要 受到、journal-compact-min-files参数的控制。
这一参数的默认值是 30。
大多数磁盘产品都有硬件的写缓冲。写缓冲可以明显提高写的效率。
这样的写缓冲与调用fsync()这样的系统函数无关,也与在Java程序中进行的同步调用无关!
默认情况下许多磁盘的写缓冲是打开的。这样的情况下,即使你在程序中调用了同步操作也不能保证你的数据 就真正写到磁盘介质中了。因此如果故障发生时,关键的数据是有可能丢失的。
有些昂贵的磁盘采用非挥发性的介质或有电源的缓冲来保证故障情况下不丢失数据。但是你仍需要对这些硬盘进行测试!
如果你的磁盘没有非挥发性或有电源的缓存,也不是某种冗余盘阵(如RAID)。要想保证关键数据不丢失,你需要 关闭磁盘的写缓冲。
需要知道的是关闭磁盘的写缓冲会显著降低磁盘的性能。如果平时你在使用磁盘时都打开写缓冲,那么当你为了 保护你的数据而关闭它时,你可能感到两种情况下的明显差异。
Linux可以用hdparm (IDE硬盘) 或 sdparm 或 sginfo (SDSI/SATA 硬盘)工具来查看并修改磁盘的写缓冲。
在Windows平台上你可以右键点击硬盘图标,并选择“属性”菜单项来操作。
Java NIO日志的性能是很好的。但是如果你是在Linux 内核2.6版本以上的系统中运行HornetQ,我们强烈建议 你使用 AIO日志,以获得更佳的性能。
在早期的Linux版本中或其它操作系统中不可以使用 AIO日志。
如果你的Linux内核是2.6版本或以上但没有安装 libaio,按照下列步骤可以很容易地安装它:
使用 yum,(如 Fedora 或 Red Hat Enterprise Linux):
yum install libaio
使用 aptitude, (如 Ubuntu 或 Debian):
apt-get install libaio