Chapter 20. 发送与提交的保证

20.1. 事务保证

在提交或回滚事务时,HornetQ将提交或回滚的请求发送到服务器,客户端阻塞等待服务器的响应。

当服务器端收到提交或回滚的请求时,它将事务信息记录到日志(journal)中。然后向客户端发回 响应。参数journal-sync-transactional控制着如何向客户端发回响应。 如果它的值是false,服务器向客户端发回响应时事务的处理結果不一定已经被 保存到磁盘中。可能会在之后的某个时间保存。如果期间服务器发生故障那么事务的处理信息可能丢失。 当它的值是true时,服务器将保证在向客户端发回响应时,事务的处理信息 已经被保存到了磁盘中。默认值是true

显然将这个参数设为false可以提高性能,但是要以牺牲事务的持久性为代价。

这个参数在 hornetq-configuration.xml文件中。

20.2. 非事务性消息发送的保证

使用非事务性会话发送消息时,经过适当配置HornetQ,客户端在发送后以阻塞的方式等待,直到确认发出 的消息已经到达服务器后再返回。可以对持久化或非持久化的消息分别配置,具体参数如下:

  • BlockOnDurableSend。如果设为true则通过 非事务性会话发送持久消息时,每次发送都将阻塞直到消息到达服务器并返回通知为止。默认值是 true

  • BlockOnNonDurableSend。如果设为true, 则通过非事务性会话发送非持久消息时,每次发送都将阻塞直到消息到达服务器并返回通知为止。默认值是 false

将发送设置为阻塞方式会降低程序的效率。因为每次发送都需要一次网络往返的过程,然后才可以进行下次发送。 这样发送消息的速度将受网络往返时间(RTT)的限制。这样你的网络带宽就可能没有被充分利用。为了提高效率,我们 建议采用事务来批量发送消息。因为在事务中,只有在提交或回滚时阻塞。另外你还可以利用HornetQ高级的 异步发送通知功能。这一功能在Section 20.4, “异步发送通知” 进行了描述。

使用JMS时,如果JMS的连接工厂是在服务器端被注册到JNDI服务,你需要配置 hornetq-jms.xml文件中的block-on-durable-sendblock-on-non-durable-send。如果不使用JNDI,可以调用 HornetQConnectionFactory相应的设置方法进行配置。

如果你使用的是内核服务,你可以直接在ClientSessionFactory上用相关的方法设置相应的参数。

当服务器从一个非事务性的会话收到一个消息时,如果这个消息是持久的并且此消息被路由到至少一个持久的队列中, 则该消息会被持久化到永久存贮介质中。如果日志(journal)的参数journal-sync-non-transactional设为true,服务器在向客户 发送响应时,它能保证消息已经被持久化到磁盘中。默认值是true

20.3. 非事务性通知的保证

当客户端使用非事务性会话向服务器通知消息收到时,可以配置HornetQ使得客户端的通知阻塞直到服务器收到 了通知并返回为止。其相应的配置参数是BlockOnAcknowledge。如果该参数设为 true则所有的通过非事务会话的消息通知都是阻塞式的。如果你想要的消息传递策略是 最多一次的话,那么你需要将此参数设为。默认值是false

20.4. 异步发送通知

如果你使用的是非事务会话来发送消息,并且希望保证每个发送出去的消息都到达服务器的话,你可以将HornetQ配置 成阻塞的方式,如Section 20.2, “非事务性消息发送的保证”讨论的那样。这样做的一个缺点是性能的降低。 因为这样每发送一个消息就需要一次网络的往返通信。如果网络时延越长,消息发送的效率就越低。同时网络的带宽对消息 的发送没有影响。

我们来做一个简单的计算。假设有一个1Gib的网络,客户端与服务器间往返时间为0.25ms。

这样,在阻塞方式的情况下,客户端最大的消息发送速度为 1000/ 0.25 = 4000 消息每秒。

如果每个消息的大小< 1500字节,而且网络的最大传输单元(MTU)是1500字节。那么理论上1GiB的网络 最大的传输速率是 (1024 * 1024 * 1024 / 8) / 1500 = 89478 消息每秒!尽管这不是一个精确的工程计算但 你可以看出阻塞式的发送对性能的影响会有多大。

为了解决这个问题,HornetQ提供了一种新的功能,称为异步发送通知。 它允许消息以非阻塞的方式发送,同时从另一个连接流中异步地接收服务器的通知。这样就使得消息的发送与通知分开来, 避免了阻塞方式带来的缺点。在保证消息可行发送到服务器的同时提高了呑吐量。

参数用来定义消息发送通知的窗口大小。它属于连接工厂或客户会话工厂。参见Chapter 34, 客户端重新连接与会话恢复 以获取更多的相关信息。

20.4.1. 异步发送通知

如果使用核心API,你需要实现org.hornetq.api.core.client.SendAcknowledgementHandler接口并将一个实例设置到 ClientSession中。

然后使用这个ClientSession发送消息。当消息到达服务器后,服务器向客户端异步地发送通知, 并在客户端调用你的SendAcknowledgementHandler实例的sendAcknowledged(ClientMessage message)方法。其中传入的参数就是发送的消息的引用。

为了使异步发送通知正常工作你必须确保confirmation-window-size的值为一个正整数,例如 10MiB

相关的例子请参见 Section 11.1.45, “发送通知”