Chapter 24. 分页转存

HornetQ可以在有限的内存下支持包含百万消息的超大规模的队列。

当有限的内存无法装得下如此多的消息时,HornetQ将它们分页转存到磁盘中,在内存 有空闲时再将消息分页装载到内存。通过这样的处理,不需要服务器有很大的内存就可以支持大容量的队列。

通过配置可以给一个地址设置一个最大消息值。当这个地址消息数在内存中超过了这个值时,HornetQ开始将多余的消息 转存到磁盘中。

默认情况下HornetQ不转存任何消息。这一功能必须显式地通过配置来激活。

24.1. 分页文件

消息按照所属的地址分别保存在不同的文件中。每一个地址有一个单独的文件夹,每个文件夹内消息被保存在 数个文件中(分页文件)。每个文件保存固定数量的消息(由参数page-size-bytes 设定)。当从分页文件中读取消息时,一个文件的所有消息被读到内存并被路由。当所有消息处理后,该文件就 被删除。

24.2. 配置

你可以配置分页转存文件夹的位置。

在主配置文件hornetq-configuration.xml)中 可以定义全局的分页转发参数。

<configuration xmlns="urn:hornetq"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd">
            
            ...
            
            <paging-directory>/somewhere/paging-directory</paging-directory>
            
            ...        

Table 24.1. 分页转存的配置参数

参数名说明默认值
paging-directory分页转存文件的位置。HornetQ在这个位置下为每个地址建立一个文件夹。data/paging

24.3. 分页转存模式

一个地址只要消息的数量超过定义的值,它就转到分页转存的模式。

Note

分页转存是针对每个地址设置的。如果你为一个地址配置了一个max-size-bytes,那么每个匹配的地址 都有一个最大值的限制。但是这并不表示所有匹配的地址的大小总和受这个参数的限制。

24.3.1. 配置

有关分页转存的配置在主要配置文件(hornetq-configuration.xml) 的地址设置的部分内。

  <address-settings>
      <address-setting match="jms.someaddress">
         <max-size-bytes>104857600</max-size-bytes>
         <page-size-bytes>10485760</page-size-bytes>
         <address-full-policy>PAGE</address-full-policy>
      </address-setting>
   </address-settings>
        

下面列出了可用的参数:

Table 24.2. 分页转存参数设置

参数名称说明默认值
max-size-bytes地址的最大内存值。当消息占用内存超过此值时,进入分页转存模式。-1 (关闭分页转存功能)
page-size-bytes每个分页文件的大小。10MiB (10 * 1024 * 1024 字节)
address-full-policy要使用分页转存,这个参数必须设为PAGE。PAGE表示多余的消息会被保存到磁盘。 如果设为DROP,那么多余的消息将会被丢弃。如果设为BLOCK,当消息占满设定的最大 内存时,在客户端消息的发送者将被阻塞,不能向服务器发送更多的消息。PAGE

24.4. 丢弃消息

一个地址除了可以分页转存多余的消息外,还可以配置为丢弃多余消息。

只要将address-full-policy设为DROP即可。

24.5. 阻塞发送者(producer)

一个地址除了可以分页转存多余的消息外,还可以通过配置使得消息的发送者在消息达到最大值时阻塞消息 的发送,以防止服务器由于消息过多而耗尽内存。

随着服务器的内存被释放,发送者自动解除阻塞,继续发送消息。

这种方式需要将address-full-policy设为BLOCK

在默认的配置中,所有的地址在消息的量达到10MiB后将阻塞发送者。

24.6. 对于有多个队列绑定的地址的配置注意事项

当一个消息被路由到一个绑定了多个队列(queue)的地址时(比如JMS的订阅),在内存中仍然只有一分消息的拷贝。每个 队列所持有的不过是它的一个引用。因此,只有所有队列中的消息都成功地传递出去后,这个消息才会从内存中清除。也就是说 只要有一个队列没有传递这个消息,那么就会造成这个消息处于未被传递的状态。

例如:

  • 一个地址绑定了10个队列(queue)。

  • 其中一个队列没有传递它的消息(也许因为接收者很慢)。

  • 消息不断增加,触发了分页转存模式。

  • 而其它9个队列尽管发送了消息,但由于地址将多余的消息转存到磁盘,所以它们都是空的。

在这个例子中,必须要等到最后一个队列传递了一些消息后,那些转存的消息被装载回内存,其它队列才有机会得到更多的消息。

24.7. 分页转存与消息的选择器(selector)

Note

请注意消息选择器只对内存的消息进行操作。如果大量的消息被转存在磁盘中,而其中有些消息与选择器是相匹配的, 那么只有内存的消息被传递,这些消息被重新装载入内存后才有可能被传递出去。 HornetQ不会扫描在磁盘中的消息来找出与选择器匹配的消息。这样做的话需要实现并管理一种索引机制才能使扫描有效地进行,另外 需要其它额外的工作。所有这些如果去完成的话,相当于实现一个关系型数据库!这并不是消息系统的主要任务。如果你要完成的任务是 从海量的消息中选择少数消息,那么你很可能需要使用的是一个关系型数据库,不是消息系统。因为这相当于表的查询。

24.8. 分页转存与浏览器

Note

请注意浏览器只对内存中的消息进行操作,它不对转存到磁盘中的消息进行操作。 消息是在被路由到任何队列之前进行转存的,所以在转存时刻,它们还没有进入到任何队列中, 自然也就不可能出现在对某个队列浏览的結果中。

24.9. 分页转存与未通知的消息

Note

请注意如果消息没有被通知,它会一直留在服务器的内存中,占用着内存资源。只要消息在被接收者收到并通知后,它才 会在服务器端被清除,空出内存空间以便转存在磁盘上的消息被装载到内存进行传递。如果没有通知,消息不会被清除, 也就不会空出内存空间,转存到磁盘上的消息也就无法装载到内存进行传递。于是在接收端就会呈现出死机的现象。 如果消息的通知是依靠ack-batch-size的设定进行的批量通知,那么一定要注意不要将 分页转存的消息临界值设得小于ack-batch-size,否则你的系统可能会发生死机现象!

24.10. 例子

Section 11.1.34, “分页(paging)”是一个说明如何使用HornetQ的分页转发功能的例子。