分页转存
HornetQ可以在有限的内存下支持包含百万消息的超大规模的队列。
当有限的内存无法装得下如此多的消息时,HornetQ将它们分页转存到磁盘中,在内存
有空闲时再将消息分页装载到内存。通过这样的处理,不需要服务器有很大的内存就可以支持大容量的队列。
通过配置可以给一个地址设置一个最大消息值。当这个地址消息数在内存中超过了这个值时,HornetQ开始将多余的消息
转存到磁盘中。
默认情况下HornetQ不转存任何消息。这一功能必须显式地通过配置来激活。
分页文件
消息按照所属的地址分别保存在不同的文件中。每一个地址有一个单独的文件夹,每个文件夹内消息被保存在
数个文件中(分页文件)。每个文件保存固定数量的消息(由参数page-size-bytes
设定)。当从分页文件中读取消息时,一个文件的所有消息被读到内存并被路由。当所有消息处理后,该文件就
被删除。
配置
你可以配置分页转存文件夹的位置。
在主配置文件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>
...
分页转存的配置参数
参数名
说明
默认值
paging-directory
分页转存文件的位置。HornetQ在这个位置下为每个地址建立一个文件夹。
data/paging
分页转存模式
一个地址只要消息的数量超过定义的值,它就转到分页转存的模式。
分页转存是针对每个地址设置的。如果你为一个地址配置了一个max-size-bytes,那么每个匹配的地址
都有一个最大值的限制。但是这并不表示所有匹配的地址的大小总和受这个参数的限制。
配置
有关分页转存的配置在主要配置文件(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>
下面列出了可用的参数:
分页转存参数设置
参数名称
说明
默认值
max-size-bytes
地址的最大内存值。当消息占用内存超过此值时,进入分页转存模式。
-1 (关闭分页转存功能)
page-size-bytes
每个分页文件的大小。
10MiB (10 * 1024 * 1024 字节)
address-full-policy
要使用分页转存,这个参数必须设为PAGE。PAGE表示多余的消息会被保存到磁盘。
如果设为DROP,那么多余的消息将会被丢弃。如果设为BLOCK,当消息占满设定的最大
内存时,在客户端消息的发送者将被阻塞,不能向服务器发送更多的消息。
PAGE
丢弃消息
一个地址除了可以分页转存多余的消息外,还可以配置为丢弃多余消息。
只要将address-full-policy设为DROP即可。
阻塞发送者(producer)
一个地址除了可以分页转存多余的消息外,还可以通过配置使得消息的发送者在消息达到最大值时阻塞消息
的发送,以防止服务器由于消息过多而耗尽内存。
随着服务器的内存被释放,发送者自动解除阻塞,继续发送消息。
这种方式需要将address-full-policy设为BLOCK。
在默认的配置中,所有的地址在消息的量达到10MiB后将阻塞发送者。
对于有多个队列绑定的地址的配置注意事项
当一个消息被路由到一个绑定了多个队列(queue)的地址时(比如JMS的订阅),在内存中仍然只有一分消息的拷贝。每个
队列所持有的不过是它的一个引用。因此,只有所有队列中的消息都成功地传递出去后,这个消息才会从内存中清除。也就是说
只要有一个队列没有传递这个消息,那么就会造成这个消息处于未被传递的状态。
例如:
一个地址绑定了10个队列(queue)。
其中一个队列没有传递它的消息(也许因为接收者很慢)。
消息不断增加,触发了分页转存模式。
而其它9个队列尽管发送了消息,但由于地址将多余的消息转存到磁盘,所以它们都是空的。
在这个例子中,必须要等到最后一个队列传递了一些消息后,那些转存的消息被装载回内存,其它队列才有机会得到更多的消息。
分页转存与消息的选择器(selector)
请注意消息选择器只对内存的消息进行操作。如果大量的消息被转存在磁盘中,而其中有些消息与选择器是相匹配的,
那么只有内存的消息被传递,这些消息被重新装载入内存后才有可能被传递出去。
HornetQ不会扫描在磁盘中的消息来找出与选择器匹配的消息。这样做的话需要实现并管理一种索引机制才能使扫描有效地进行,另外
需要其它额外的工作。所有这些如果去完成的话,相当于实现一个关系型数据库!这并不是消息系统的主要任务。如果你要完成的任务是
从海量的消息中选择少数消息,那么你很可能需要使用的是一个关系型数据库,不是消息系统。因为这相当于表的查询。
分页转存与浏览器
请注意浏览器只对内存中的消息进行操作,它不对转存到磁盘中的消息进行操作。
消息是在被路由到任何队列之前进行转存的,所以在转存时刻,它们还没有进入到任何队列中,
自然也就不可能出现在对某个队列浏览的結果中。
分页转存与未通知的消息
请注意如果消息没有被通知,它会一直留在服务器的内存中,占用着内存资源。只要消息在被接收者收到并通知后,它才
会在服务器端被清除,空出内存空间以便转存在磁盘上的消息被装载到内存进行传递。如果没有通知,消息不会被清除,
也就不会空出内存空间,转存到磁盘上的消息也就无法装载到内存进行传递。于是在接收端就会呈现出死机的现象。
如果消息的通知是依靠ack-batch-size的设定进行的批量通知,那么一定要注意不要将
分页转存的消息临界值设得小于ack-batch-size,否则你的系统可能会发生死机现象!
例子
是一个说明如何使用HornetQ的分页转发功能的例子。