Chapter 7. Message Cursors

Abstract

Red Hat JBoss A-MQ uses message cursors to improve the scalability of the persistent message store. By default, a hybrid approach that uses an in memory dispatch queue for fast consumers and message cursors for slower consumers is used. JBoss A-MQ also supports two alternative cursor implementations. The type of cursor can be configured on a per-destination basis.
Message data is cached in the broker using message cursors, where a cursor instance is associated with each destination. A message cursor represents a batch of messages cached in memory. When necessary, a message cursor will retrieve persisted messages through the persistence adapter. But the key point you need to understand about message cursors is that the cursors are essentially independent of the persistence layer.
Message cursors provide a means for optimizing a persistent message store. They allow the persistent store to maintain a pointer to the next batch of messages to pull from the persistent message store. Red Hat JBoss A-MQ has three types of cursors that can be used depending on the needs of your application:
  • Store-based cursors are used by default to handle persistent messages.
  • VM cursors are very fast, but cannot handle slow message consumers.
  • File-based cursors are used by default to handle non-persistent messages. They are useful when the message store is slow and message consumers are relatively fast.

7.1. Types of Cursors

Store-based cursors

Store-based cursors are used, by default, for processing persistent messages. Store-based cursors are a hybrid implementation that offers the robustness of typical cursor implementations and the speed of in-memory message reference implementations.
Typically messaging systems will pull persistent messages from long-term storage in a batch when a client is ready to consume them. A cursor will be used to maintain the position for the next batch of messages. While this approach scales well and provides excellent robustness, it does not perform well when message consumers keep pace with message producers.
As shown in Figure 7.1, “Store-based Cursors for a Fast Consumer”, the store-based cursor addresses the fast consumer case just like the VM cursor. Messages are written to the persistent store and are also directly stored in the pending cursor, which is held completely in memory. The pending cursor then feeds the messages into the dispatch queue. However, since the store cursor can hold only a limited number of messages in memory, it is a mapping of only a fraction of the persistent message store.

Figure 7.1. Store-based Cursors for a Fast Consumer

Store-based Cursors for a Fast Consumer
When a consumer starts with a back log of messages or falls behind its message producers, JBoss A-MQ changes the strategy used to dispatch messages. As shown in Figure 7.2, “Store-based Cursors for a Slow Consumer”, messages are held in the message store and fed into the consumer's dispatch queue using the pending cursor.

Figure 7.2. Store-based Cursors for a Slow Consumer

Store-based Cursors for a Slow Consumer

VM cursors

When speed is the top priority and the consumers can definitely keep pace with the message producers, VM cursors could be the best approach. In this approach, shown in Figure 7.3, “VM Cursors”, messages are written to the persistent store and are also stored in the pending cursor, which is held completely in memory. The messages are fed into the dispatch queue from the pending cursor. Since it needs to hold all messages in memory, the VM cursor is a snapshot of the entire persistent message store.

Figure 7.3. VM Cursors

VM Cursors
Because the messages are dispatched from active memory when using VM cursors, this method is exceptionally fast. However, if the number of unconsumed messages grows large, the producers are throttled to avoid exceeding available memory.

File-based cursors

File-based cursors are a variation of VM cursors that provides a buffer against running out of memory when a consumer falls behind. As shown in Figure 7.4, “File-based Cursors”, the broker pages messages out to a temporary file when the broker's memory limit is reached.

Figure 7.4. File-based Cursors

File-based Cursors
Using a temporary file cushions the broker against situations where a consumer occasionally falls behind or messages are produced in a burst. The broker uses the temporary file instead of resorting to using slower persistent storage.
File-based cursors do not scale well when consumers are frequently behind by a large margin. It is also not ideal when a fast long term message store is available.
File-based cursors are used, by default, to process non-persistent messages.