## 13.2 优化消息生产者

### 13.2 优化消息生产者

The rate at which producers send  messages to an ActiveMQ message broker  before they’re dispatched to consumers is a fundamental element of overall application performance. We’ll now cover some tuning parameters that affect the  throughput and latency of messages sent from a message producer to an ActiveMQ broker.

#### 13.2.1 异步发送

We’ve already covered  the performance gains  that can be  achieved if you  use nonpersistent  delivery  for  messages. In  ActiveMQ  nonpersistent  delivery is reliable, in that delivery of  messages will survive network outages  and system crashes (as long as the producer is active—it holds messages for redelivery  in its failover transport cache).  But you can also  get the same performance  gain for persistent  messages by  setting the  useAsyncSend property  on the  message producer’s connection factory, as shown next.
Listing 13.8 Enabling asynchronous sends

  ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory();
cf.setUseAsyncSend(true);

This will set a property that tells the MessageProducer not to expect a  receipt for messages it sends  to the ActiveMQ broker.  This means that a  producer will not wait until the message is on disk before sending another message.

If your application requires guaranteed delivery, it’s recommend that you use the default delivery mode, persistent delivery, and preferably use transactions too.

The  reasons for  using asynchronous  message delivery  for gaining  performance should be  well understood,  and setting  a property  on the ActiveMQ connection factory is a straightforward way of achieving that. Next we’ll cover a commonly misunderstood  feature in  ActiveMQ: producer  flow control.  We see  a lot  of questions  about  producers  slowing down  or  pausing,  and understanding  flow control will allow you to mitigate this situation in your applications.

#### 13.2.2 生产者流控制

Producer flow control  allows the message  broker to slow  the rate of  messages that  are passed  through it  when resources  are running  low. This  typically happens when  consumers are  slower than  the producers,  and messages are using memory in the broker awaiting dispatch.

A producer will wait until it receives a notification from the broker that it has space for more messages, as shown in figure 13.3. Producer flow control is necessary to prevent a broker’s usage limits for memory and temporary store space from being overrun, especially for wide area networks.

Producer flow control is enabled by default for persistent messages but must be explicitly enabled for asynchronous publishing (persistent messages, or for connections configured to always send asynchronously). You can enable flow control for asynchronous publishing by setting the producerWindowSize property on the connection factory.
Listing 13.9 Setting the producer window size

  ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory();
cf.setProducerWindowSize(1024000);

The producerWindowSize property is used to specify the number of bytes allowed in the producer’s send buffer before it’ll be forced to wait for a receipt from the broker that it’s still within its usage limits. If this isn’t enabled for an asynchronous publisher, the broker will still pause message flow, which defaults to blocking the message producer’s transport. Blocking the transport will block all users of the connection, which can lead to deadlock if the message consumers are sharing the connection. Producer flow control allows blocking only the producer rather than the entire connection.

producerWindowSize属性用于设置生产者在收到代理的存储空间未超过限制值回执之前可以用来缓存消息的字节大小,超过这个设置的值,生产者将等待代理回执(译注:而不再生产和发送消息).对于一个异步发送消息的生产者来说,如果这个属性未开启,则代理仍然会暂停消息流动,这种情况下,默认会阻塞消息生产者的传输连接器.阻塞传输连接器会阻塞所有使用该连接器连接的用户,如果消息消费者也使用同样的连接,则会导致死锁.生产者流控制运行仅阻塞消息生产者而不是整个消息生产者使用的传输连接.

Although protecting the  broker from running  low on memory  is a noble  aim, it doesn’t aid our cause for performance when everything slows down to the slowest consumer! So let’s see what happens when you disable producer flow control,  as shown in bold in the following code. You can do this in the broker configuration on a destination policy.
Listing 13.10 How to disable flow control

<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry
topic="FOO.>"
producerFlowControl="false"
memoryLimit="10mb" />
</policyEntries>
</policyMap>
</destinationPolicy>

With producer flow control disabled, messages for slow consumers will be off-lined to temporary storage by default, enabling the producers and the rest of the consumers to run at a much faster rate as outlined in figure 13.4. Additionally, the system usage memory limit determines the point at which messages are offloaded to disk by the pending message cursors. The system usage memory limit setting is applied across the broker. This limit needs to be lower than the destination memory limits so that they can kick in before producer flow control.

Disabling producer flow control enables messaging applications to run at a pace independent of the slowest consumer, though there’s a slight performance hit in offlining messages. In an ideal world, consumers would always be running as fast as the fastest producer, which neatly brings us to the next section on optimizing message consumers.
TUNING PRODUCER FLOW CONTROL

By default, when producer flow control is enabled and there’s not enough space in the broker for more messages, the producer’s send operation will block until space becomes available on the broker. There are two ways to tune this parameter so that it doesn’t block indefinitely and essentially hang the producer until space becomes available.
The first tuning option for producer flow control is named sendFailIfNoSpace:

<systemUsage>
<systemUsage sendFailIfNoSpace="true">
<memoryUsage>
<memoryUsage limit="128 mb"/>
</memoryUsage>
</systemUsage>
</systemUsage>

The sendFailIfNoSpace property puts control back into the hands of the producer by throwing an exception on the client side when a send operation is attempted and space isn’t available, instead of blocking the send operation indefinitely. This allows the producer to catch the exception, wait a bit, and attempt the send the operation again.

sendFailIfNoSpace属性将控制权返还给消息生产者,在代理的消息存储已经不足而生产者仍然尝试发送操作时,通过在生产者客户端抛出异常来代替永久性的阻塞生产者的发送操作.这就允许生产者可以捕捉这个异常,然后等待 一段时间后,继续尝试发送操作.

The second tuning option for producer flow control was made available in ActiveMQ 5.4.1. This property is named sendFailIfNoSpaceAfterTimeout:

<systemUsage>
<systemUsage sendFailIfNoSpaceAfterTimeout="5000">
<memoryUsage>
<memoryUsage limit="128 mb"/>
</memoryUsage>
</systemUsage>
</systemUsage>

The sendFailIfNoSpaceAfterTimeout property provides a slightly different kind of control. This property causes the send operation to fail with an exception on the client side, but only after waiting the given amount of time for space to become available.

sendFailIfNoSpaceAfterTimeout与前面那个属性稍有不同.配置了该属性后,在等待配置的时间后,如果代理端 依然没有足够的空间存储消息,则会在客户端客户端发送消息时抛出异常.

微信赞赏  支付宝赞赏