Chapter 15. 持久化

本章我们将描述HornetQ的持久化技术,包括持久化的工作原理和配置方法。

HornetQ拥有一个高性能的日志(journal)模块来处理持久化。因此它并不依赖一个外部的数据库或第三方持久化产品。这个 日志模块针对消息的处理进行了高度的优化。

所谓HornetQ日志是一个只添加系统。它由一组磁盘文件构成。每个文件都是预先创建好的并且 大小是固定的。文件在创建时都进行了格式化。随着HornetQ不断地处理消息,如消息的增加、更新、删除等,一个个记录被添加 到日志中。当一个日志文件写满时,新记录就会写到下一个文件。

由于对日志的写入只是对文件的添加,这样有效减少了随机寻道的操作。而随机寻道的操作是磁盘操作中最耗时的操作。 所以这种设计可以使磁头的运动降到最低,效率最高。

而文件的大小是可以配置的。这使我们可以将文件大小配置为刚好占满一个磁盘柱面。不过现代的磁盘技术是复杂多样的, 我们并不能控制文件与磁盘柱面的对应关系。尽管如此,我们通过最大限度地降低文件对磁盘柱面的占用,来降低磁头的运动。 这是因为在同一个柱面的存取只需要盘面的转动而不需要磁头的运动。

当被删除的记录越来越多时,有的文件最終会变成一个没有有效记录的文件。这样的文件就可以回收再利用。HornetQ有 一套复杂的文件回收算法来判断一个日志文件是否可以被回收。

HornetQ还有一套文件整理的算法,它用来将日志文件中不用的空隙移除以达到更高的存贮效率。

这个日志系统全面支持事务功能。根据需要它可以支持本地事务或XA型事务。

日志系统的大部分是用Java实现的,但是HornetQ在其中实现了一层抽象的文件系统,这样就使得其它的语言实现能 方便地“插入”到日志模块中。实际上HornetQ自带有两种实现:

标准的HornetQ核心服务器使用了两种日志:

对于超大消息,Hornet将它们保存在消息日志之外的地方。详见Chapter 23, 大消息.

HornetQ还可以在内存不够用时将消息暂存到磁盘上。相关的配置和说明参见Chapter 24, 分页转存

如果不需要持久功能,HornetQ还可以配置成非持久的消息系统。参见Section 15.6, “配置HornetQ不使用持久化”

15.1. 配置绑定日志

绑定日志的配置参数在 hornetq-configuration.xml文件中。

  • bindings-directory

    这是绑定日志的位置。默认值是data/bindings

  • create-bindings-dir

    如果设置为true,那么在 bindings-directory 所设定的位置不存在的情况下会自动创建它。默认值是true

15.2. 配置JMS日志

JMS日志的配置与绑定日志共用配置。

15.3. 配置消息日志

消息日志的配置在hornetq-configuration.xml文件中。

  • journal-directory

    这是消息日志文件所在的目录。默认值是 data/journal

    为以达到最佳性能,我们建议将日志设定到属于它自己的物理卷中以减少磁头运动。如果日志的位置与 其它进程共用(如数据库,绑定日志或事务的日志等)则磁头的运动显然要增加很多。性能也就没有保证了。

    如果消息日志是贮存在SAN中,我们建议每个日志都拥有自己的LUN(逻辑单元)。

  • create-journal-dir

    如果设为true,则当journal-directory所指定的日志目录不存在时,会自动创建它。默认值是true

  • journal-type

    有效值是NIO 或者 ASYNCIO

    Choosing NIO chooses the Java NIO journal. Choosing AIO 选择作用异步IO型日志。如果你的平台不是Linux或者你没有安装 libaio,HornetQ会自动检测到并使用NIO

  • journal-sync-transactional

    如果设为true,HornetQ会保证在事务的边界操作时(commit, prepare和rollback)将事务数据 写到磁盘上。默认的值是 true

  • journal-sync-non-transactional

    如果设为true HornetQ将保证每次都将非事务性消息数据(发送和通知)保存到磁盘上。默认值是 true

  • journal-file-size

    每个日志文件的大于。单位为字节。默认值是 10485760 bytes (10MiB)。

  • journal-min-files

    最少日志文件数。当HornetQ启动时会创建这一数量的文件。

    创建并初始化日志文件是一项费时的操作,通常不希望这些操作在服务运行时执行。预先创建并初始化这些 日志文件将会使HornetQ在工作时避免浪费不必要的时间。

    根据你的应用中队列中消息量的实际要求可以适当调节这一参数。

  • journal-max-io

    写请求被放到一个队列中,然后再被发送到系统中执行。这个参数限制了在任一时间队列中可以存放的最大数量 的写请求。如果队列达到这个限制,任何新的写请求都将被阻塞,直到队列中有空位为止。

    当使用NIO时,这个参数必须为 1

    当使用AIO时,它的默认值是500

    系统根据不同类型的日志提供不同的默认值。(NIO 为 1, AIO 为 500)。

    如果是AIO,这个参数的上限不能超过操作系统的限制(/proc/sys/fs/aio-max-nr),这个值通常为65536.

  • journal-buffer-timeout

    日志模块中有一个内部缓冲。每次写的内容并不是都立即写到磁盘上,而是先放到这个内部缓存中。当这个缓存已满时,或 者超过了一定的时间(timeout),才将缓存的数据存到硬盘上。NIO和AIO都有这一特点。采用缓存的方式可以很好地满足 大量并发写数据的需要。

    这一参数规定了缓存的失效时间,如果过了这个时间,即使缓存还没有满,也将数据写入磁盘中。AIO的写入 能力通常要比NIO强。因此系统对于不同类型的日志有着不同的默认值。( NIO的默认值是 3333333 纳秒,即每秒300次。 而AIO则是500000纳秒,即每秒2000次。)

    Note

    加在这个参数有可能会增加系统的呑吐量,但可能会降低系统的响应能力。通常情况下默认值应该是比较理想的折中选择。

  • journal-buffer-size

    AIO的定时缓冲的大小,默认值为490KiB

  • journal-compact-min-files

    进行整理压缩日志操作的最少文件数。当日志文件少于这个数时,系统不会进行文件的整理压缩。

    默认值是 10

  • journal-compact-percentage

    开始整理压缩的界限值。当有效数据的比例少于这个值时系统开始整理压缩日志。注意是否进行压缩还要 受到、journal-compact-min-files参数的控制。

    这一参数的默认值是 30

15.4. 关于关闭磁盘写缓冲的重要说明

Warning

大多数磁盘产品都有硬件的写缓冲。写缓冲可以明显提高写的效率。

这样的写缓冲与调用fsync()这样的系统函数无关,也与在Java程序中进行的同步调用无关!

默认情况下许多磁盘的写缓冲是打开的。这样的情况下,即使你在程序中调用了同步操作也不能保证你的数据 就真正写到磁盘介质中了。因此如果故障发生时,关键的数据是有可能丢失的。

有些昂贵的磁盘采用非挥发性的介质或有电源的缓冲来保证故障情况下不丢失数据。但是你仍需要对这些硬盘进行测试!

如果你的磁盘没有非挥发性或有电源的缓存,也不是某种冗余盘阵(如RAID)。要想保证关键数据不丢失,你需要 关闭磁盘的写缓冲。

需要知道的是关闭磁盘的写缓冲会显著降低磁盘的性能。如果平时你在使用磁盘时都打开写缓冲,那么当你为了 保护你的数据而关闭它时,你可能感到两种情况下的明显差异。

Linux可以用hdparm (IDE硬盘) 或 sdparmsginfo (SDSI/SATA 硬盘)工具来查看并修改磁盘的写缓冲。

在Windows平台上你可以右键点击硬盘图标,并选择“属性”菜单项来操作。

15.5. 安装AIO

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

15.6. 配置HornetQ不使用持久化

在一些情况下消息系统并不需要持久化。这时可以配置HornetQ不使用持久层。只要将hornetq-configuration.xml文件中的persistence-enabled 参数设为false即可。

注意如果你将该参数设为 false来关闭持久化,就意味着所有的绑定数据、消息数据、超大消息数据、重复ID缓冲以及转移(paging)数据都将不会被持久。