Loose Coupling in a Service-Oriented Architecture - 4.2.1 Asynchronous Communication (Page 2 of 4 )
Probably the most well-known example of loose coupling is asynchronous communication (see Figure 4-1). Asynchronous communication usually means that the sender of a message and its receiver are not synchronized. Think of it like sending an email. After you send a message, you can continue your work while waiting for an answer. The recipient might not be available (online) when you send the message. When she comes online, the message gets delivered, and she can process it and send a response if necessary (again, with no requirement that you be available/online when she sends it).
Figure 4-1. Decoupling by asynchronous communication
One problem with asynchronous communication occurs when the sender needs a reply. With asynchronous communication, you don’t get replies to your messages immediately. Because you don’t know when (or whether) a reply will arrive, you continue your work and start to perform different tasks. Then, when the response arrives, you have to deal with it in an appropriate way. This means that you have to associate the answer with the original request (e.g., by processing something like a “correlation ID”). In addition, you have to process the reply, which usually requires knowledge of some of the initial state and context when the request was sent. Both correlating the response to the request, and transferring the state from the request to the response, require some effort.
See Chapter 10 for a discussion of different message exchange patterns (MEPs) and Section 15.3.3 for details about correlation IDs.
The situation gets worse when you send a lot of asynchronous messages. The order in which you receive responses might be different from the order in which you sent the messages, and some of the awaited responses might not arrive (or arrive in time). Programming, testing, and debugging all the possible eventualities can be very complicated and time consuming.
For this reason, one of my customers who has hundreds of services in production has the policy of avoiding asynchronicity whenever a request needs a reply. Having found that debugging race conditions (situations caused by different unexpected response times) was a nightmare, and knowing that maintainability was key in large distributed systems, the customer decided to minimize the risk of getting into these situations. This decision involved a tradeoff because performance was not as good as it might have been with more asynchronous communication.
As this discussion demonstrates, there are two sides to introducing asynchronous communication in SOA (or distributed systems in general):
The advantage is that the systems exchanging service messages do not have to be online at the same time. In addition, if a reply is required, long answering times don’t block the service consumer.
The drawback is that the logic of the service consumer gets (much) more complicated.
Note that when discussing asynchronicity, people do not always mean the same thing. For example, asynchronous communication from a consumer’s point of view might mean that the consumer doesn’t block to wait for an answer, while from an infrastructure’s (ESB’s) point of view, it might mean that a message queue is used to decouple the consumer and provider. Often, both concepts apply in practice, but this is not always the case.