分页转存 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的分页转发功能的例子。