Step 6: Explore Consumer Scaling Patterns

You've now completed Step 5: Try a Request-Reply Message Exchange Pattern.

In step 6, you'll expand your understanding by setting up three common messaging patterns used for consumer scaling.

As you've learned in the previous steps, Solace topics give you the flexibility to implement different message exchange patterns, such as publish-subscribe and request-reply, while also allowing each consumer to subscribe to the topics that give them exactly the events they want to receive. In this step, we'll learn how Solace allows you to further decouple your consumers from your producers by enabling consumer applications to scale in various ways, depending on their individual requirements. For more information about consumer patterns and consumer scalability patterns, see the Solace Ultimate Guide to Event-Driven Architecture Patterns.

In this step, we'll focus on three patterns that show consumer scalability options and use the Solace Try-Me CLI tool to demonstrate each of these patterns:

  • Competing consumers
  • High availability
  • Partitioning

The most common way to implement these patterns is using Guaranteed message delivery with a queue. When using queues to implement these scaling patterns, producers still publish events to topics, and consumers bind to queues that are configured to meet their specific scaling requirements. The queues subscibe to the topics that the consumers want to receive events for.

Competing Consumers

Competing consumers is a scalability pattern in event-driven architecture that involves distributing the workload of processing events among multiple instances of the same application to improve throughput and reduce processing time.

Diagram illustrating the concepts described in the surrounding text.

In this mode, the queue has a non-exclusive access type, which facilitates the delivery of messages to all bound consumer flows in a round-robin fashion. This pattern is commonly used when message order is not important and you need to scale consumers to keep up with the message throughput.

Set Up Competing Consumers

In this exercise, we'll set up three competing consumer applications to share the message processing load. After you complete these steps, you'll have a consumer scaling pattern like the following animation:

Animation showing scaling using competing consumers.

To set up competing consumer instances, perform these steps:

  1. Open a command-line terminal window and create a non-exclusive queue with a topic subscription for coffeeshop/>. Enter the following command:
  2. stm manage queue --create NonExclusiveQ --access-type NON-EXCLUSIVE --add-subscriptions "coffeeshop/>"

    You should see the following result:

    ℹ  info      info: loading 'queue' command from configuration 'stm-cli-config.json'
    ✔  success   success: queue 'NonExclusiveQ' created successfully
    ✔  success   success: subscription to topic 'coffeeshop/>' added successfully
    ✔  success   success: 1 subscription(s) found on queue NonExclusiveQ -coffeeshop/>
    ✔  success   success: exiting...
  3. Open three additional command-line terminal windows and in each one, start a receiver with the following command:
  4. stm receive --queue NonExclusiveQ
  5. In another command-line terminal window, start a sender that publishes 100 events with an interval of 1 second between each publish using the following command:
  6. stm send --count 100 --topic 'coffeeshop/order/new/v1'

    You should see the messages being received by your 3 receivers in a round-robin, competing consumers fashion. Using a non-exclusive queue allows you to implement the competing consumers pattern and load balance events across different instances of your consumer.

  7. You can verify the behavior in PubSub+ Broker Manager by going to your queue and viewing the Consumers tab. If all of your receivers were bound to the queue before you began sending messages, you’ll see the messages evenly distributed across the receivers.

    Screenshot showing the consumers described in the preceding text.

High Availability

When you implement a high availability (HA) consumer scaling pattern, you have multiple instances of the same consumer application available to process events. One instance of the consumer is chosen to be active and receives all events, while the other instances are on standby. If the active instance crashes or goes down, the broker automatically elects another instance to activate and starts sending all events to the new consumer. This pattern ensures that event processing continues as long as you have one instance connected and processing. This pattern is also sometimes referred to as Primary / Secondary or Primary / Secondary / Tertiary depending on how many levels of redundancy are required.

Diagram illustrating the concepts described in the surrounding text.

To implement this pattern, the queue has the exclusive access type. This access type allows multiple consumers to connect, but the event broker delivers events to only one of them. If the active consumer disconnects, the next consumer to receive events is randomly selected from the waiting pool of consumers. This pattern is commonly used when all messages in a queue must be processed in order.

Set Up Consumers for High Availability

In this exercise we'll set up three consumer applications for HA. Two of the consumers are in standby mode and don't receive messages unless the active consumer application becomes unavailable. After you complete these steps you'll have a consumer scaling pattern like the following animation:

Animation showing high availablity consumers.

To set up consumer instances for high availability, perform these steps:

  1. Open a command-line terminal window and create an exclusive queue with a topic subscription for coffeeshop/>. Enter the following command:
  2. stm manage queue --create ExclusiveQ --access-type EXCLUSIVE --add-subscriptions "coffeeshop/>"

    You should see the following result:

    ℹ  info      info: loading 'queue' command from configuration 'stm-cli-config.json'
    ✔  success   success: queue 'ExclusiveQ' created successfully
    ✔  success   success: subscription to topic 'coffeeshop/>' added successfully
    ✔  success   success: 1 subscription(s) found on queue ExclusiveQ -coffeeshop/>
    ✔  success   success: exiting...
  3. Open three additional command-line terminal windows, and in each one start a receiver with the following command:
  4. stm receive --queue ExclusiveQ
  5. In another command-line terminal window, start a sender that publishes 100 events with an interval of 1 second between each publish using the following command:
  6. stm send --count 100 --topic 'coffeeshop/order/new/v1'

    You should see the messages all being received by the first receiver that you started because you are using an exclusive queue.

  7. You can verify the behavior in PubSub+ Broker Manager by going to your queue and looking at the Consumers tab .You should see that one of the three consumers received all the messages.

    Screenshot showing the consumers described in the preceding text.

  8. If the currently active consumer disconnects from the queue, one of the remaining two consumers starts receiving events. If you want to see the change in action, restart the publisher and, while the publish is in progress, stop the currently active consumer by pressing Control+C (on Windows and Linux) or Command+C (on Mac). You can see that one pf the standby consumers starts receiving messages.

Partitioning

Partitioning is a design pattern in event-driven architecture that helps to improve scalability while also maintaining message order where it’s required. You effectively split up a stream of events into partitions, which can then be processed in parallel. Order is maintained by partition instead of across the entire event stream. This pattern is common when you need to scale your consumers, but you also care about message order.

In PubSub+, this pattern is implemented using partitioned queues. Partitioned queues are a type of non-exclusive queue that delivers to many consumers at once to enable scaling. Partitioned queues use a partition key to split ingress events into partitions. All events within a partition are always delivered to the same consumer, thus enabling scalability while maintaining the message order. For more information, see Partitioned Queues.

You can also watch our Solace Developer Advocate demonstrate partitioned queues.

Solace Partitioned Queues in Action!

Set Up a Partitioned Queue

For this exercise, we'll set up partition keys and create a partitioned queue. You can set partition keys using the Solace Try-Me CLI using these parameters:

  • Use --partition-key <KEY> to set keys based on the message publish time.
  • Use --partition-keys <KEY...> to specify a list of partition keys.

To set up a partitioned queue for the coffee shop, perform these steps:

  1. Open a command-line terminal window and create an non-exclusive queue with five partitions. Enter the following command:
  2. stm manage queue --create PartitionedQ --access-type NON-EXCLUSIVE --add-subscriptions "coffeeshop/>" --partition-count 5

    You should see the following result:

    ℹ  info      info: loading 'queue' command from configuration 'stm-cli-config.json'
    ✔  success   success: queue 'PartitionedQ' created successfully
    ✔  success   success: subscription to topic 'coffeeshop/>' added successfully
    ✔  success   success: 1 subscription(s) found on queue PartitionedQ -coffeeshop/>
    ✔  success   success: exiting...
  3. Open three additional command-line terminal windows and in each one, start a receiver with the following command:
  4. stm receive --queue PartitionedQ --output-mode props 
  5. Open an additional command-line terminal window and start a sender that publishes 100 events with an interval of 1 second between each publish and passes a list of partition keys using the --partition-keys parameter.
  6. stm send --partition-keys ESPRESSO DOPPIO AMERICANO LATTE CORTADO CAPPUCCINO MACCHIATO FLATWHITE BLACKEYE --count 100 --interval 1000 --topic 'coffeeshop/order/new/v1'

    You should now see the messages being received by your three receivers. Notice that messages with the same partition key, such as ESPRESSO, are always delivered to the same consumer. The partition key appears as the JMSXGroupId user-attribute, which is displayed in the Solace Try-Me CLI tool when you use --output-mode props.

  7. You can verify the behavior in PubSub+ Broker Manager by going to your queue and looking at the Consumers tab .You should see that one of the three consumers received all the messages.

    Screenshot showing the consumers described in the preceding text.

Tutorial Steps

You've completed the sixth step in the tutorial. Click Next Steps for suggestions to continue your Solace journey.

Step Description

Step 1

Set up Your First Event Broker - Complete

Step 2

Solace EDA Basics - Complete

Step 3

Set up the Solace Try-Me CLI Tool - Complete

Step 4

Try a Publish-Subscribe Message Exchange Pattern - Complete

Step 5

Try a Request-Reply Message Exchange Pattern - Complete

Step 6

Try Consumer Scaling Patterns - Complete

Next Steps

You can return to the main Tutorial page at any time.