Skip to content

Commit

Permalink
SB Readme: include details of connection IO-thread bottleneck and upd…
Browse files Browse the repository at this point in the history
…ate (#39838)

changelog
  • Loading branch information
anuchandy authored Apr 22, 2024
1 parent 274dddd commit 5cfcc6d
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 12 deletions.
3 changes: 2 additions & 1 deletion sdk/servicebus/azure-messaging-servicebus/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Release History

## 7.16.0 (2024-04-19)
## 7.16.0 (2024-04-22)

### Features Added

Expand All @@ -9,6 +9,7 @@
### Bugs Fixed

- Fixes the ServiceBusProcessorClient to signal intermediate errors to the processor handler. ([#39669](https://github.com/Azure/azure-sdk-for-java/issues/39669))
- Fixes the issue of not creating default rule when creating subscription. ([37856](https://github.com/Azure/azure-sdk-for-java/issues/37856))

### Other Changes

Expand Down
28 changes: 17 additions & 11 deletions sdk/servicebus/azure-messaging-servicebus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,9 +399,24 @@ ServiceBusReceiverClient receiver = new ServiceBusClientBuilder()
receiver.close();
```

### When to use 'ServiceBusProcessorClient'.

When to use 'ServiceBusProcessorClient', 'ServiceBusReceiverClient' or ServiceBusReceiverAsyncClient?

The best option for receiving messages in most common cases is 'ServiceBusProcessorClient'. The processor can handle errors automatically and is designed to receive messages continuously. The processor has a simple API to set concurrency for processing messages in parallel.

The low-level client, 'ServiceBusReceiverAsyncClient', is for advanced users who want more control and flexibility over their Reactive application at the expense of more complexity in the application. Unlike the processor, the low-level 'ServiceBusReceiverAsyncClient' does not have automatic recovery built into it. The reactive application using this client needs to deal with terminal events and choose the operators (to add recovery, manage backpressure, threading) in the Reactor chain. As stated earlier, for common asynchronous receive situations, the 'ServiceBusProcessorClient' should be the first choice.

'ServiceBusReceiverClient' usage is discouraged unless you want to have pull semantics or want to migrate existing code base that uses synchronous receiver approach. For high-throughput and parallel message processing use cases, use 'ServiceBusProcessorClient'.

### Sharing of connection between clients
The creation of physical connection to Service Bus requires resources. An application should share the connection
between clients which can be achieved by sharing the top level builder as shown below.

All the clients created from a shared `ServiceBusClientBuilder` instance will share the same connection to the Service Bus namespace.


While using shared connection allows multiplexing operations among clients on one connection, sharing can also become a bottleneck if there are many clients, or the clients together generate high load. Each connection has one IO-Thread associated with it. The clients put their work on this shared IO-Thread's work-queue and the progress of each client depends on the timely completion of its work. The IO-Thread handles the enqueued work serially, which means, if the IO-Thread work-queue ends up with a lot of pending work to deal with, then it can be manifested as clients stalling, that leads to timeout, lost lock or slowdown in recovery path. Hence, if the application load to a Service Bus endpoint is reasonably high (in terms of overall number of sent-received messages or payload size), use a separate builder instance for each client you build. For example, for each entity (queue or topic and subscription), you can create a new `ServiceBusClientBuilder` and a build a client from it. In case of extremely high load to a specific entity, you might want to either create multiple client instances for that entity or run clients in multiple hosts (e.g., containers, VM) to load balance.

In the following example, a sender and receiver clients are built from a shared top-level builder, which means they use the same connection.

```java com.azure.messaging.servicebus.connection.sharing
TokenCredential credential = new DefaultAzureCredentialBuilder().build();
Expand Down Expand Up @@ -433,15 +448,6 @@ try {
receiver.close();
}
```
### When to use 'ServiceBusProcessorClient'.

When to use 'ServiceBusProcessorClient', 'ServiceBusReceiverClient' or ServiceBusReceiverAsyncClient?

The best option for receiving messages in most common cases is 'ServiceBusProcessorClient'. The processor can handle errors automatically and is designed to receive messages continuously. The processor has a simple API to set concurrency for processing messages in parallel.

The low-level client, 'ServiceBusReceiverAsyncClient', is for advanced users who want more control and flexibility over their Reactive application at the expense of more complexity in the application. Unlike the processor, the low-level 'ServiceBusReceiverAsyncClient' does not have automatic recovery built into it. The reactive application using this client needs to deal with terminal events and choose the operators (to add recovery, manage backpressure, threading) in the Reactor chain. As stated earlier, for common asynchronous receive situations, the 'ServiceBusProcessorClient' should be the first choice.

'ServiceBusReceiverClient' usage is discouraged unless you want to have pull semantics or want to migrate existing code base that uses synchronous receiver approach. For high-throughput and parallel message processing use cases, use 'ServiceBusProcessorClient'.

## Troubleshooting

Expand Down

0 comments on commit 5cfcc6d

Please sign in to comment.