Integration schemes employed by modern enterprise-class service oriented architectures can generally be divided into two primary categories, Web Services and Message Driven Architecture (MDA). This document attempts a brief description of these schemes, a concise analysis of their respective strengths and weaknesses, and provides some basic guidelines for implementing each scheme in a scalable manner suitable for the enterprise.
Web Services are an implementation of a synchronous, request-response pattern leveraging standard web protocols (HTTP/HTTPS). Typical web service implementations are based on either SOAP, an XML-based encoding scheme which uses a specific XML envelope format to direct requests to specific operational endpoints, or REST, which leverages standard web URL addressing schemes and multiple HTTP operation types together with a variety of encodings (frequently JSON) to define service semantics.
Message Driven Architecture, in contrast, eschews the use of HTTP-based point-to-point service schemes in favor of service integration through a shared (broker-based) message bus infrastructure. Services are exposed through specific, named message broker endpoints, and a variety of message encodings can be used (including XML, JSON, or efficient binary encodings such as Google Protobuf or Swift). A variety of opens source and commercial messaging technologies can be used to wire together services in a MDA, including ActiveMQ, IBM MQ, RabbitMQ, QPid, Amazon SQS, Kafka, and ZeroMQ. Communication patterns in MDA are fundamentally asynchronous and non-blocking, although they can be used to emulate synchronous request/response behavior when appropriate, as described below.
Synchronous Semantics in MDA
Message Driven Architecture can provide synchronous request/response semantics similar to web services through the use of callback queues. In this pattern, the client instance creates or is bound to a specific queue used to receive responses. Requests are submitted with a header identifying this queue as well as a unique correlation or request ID. Service implementations publish responses to the identified callback queue and include the correlation ID header. Meanwhile, the client can block the requesting thread until a response is received on the callback queue with matching correlation ID. This pattern is illustrated below:
While this pattern may appear somewhat complex, in reality it is fairly easy to implement, and, in some cases message framework providers have baked direct support for the pattern into their client APIs (e.g. RabbitMQ and IBM MQ), making implementation trivial. Note that this pattern works best when the messaging technology provides an API that allows clients to create and manage callback queues with randomized ids as needed at runtime (this are known as anonymous callback queues). The ability for clients to manage their own anonymous callback queues at runtime simplifies scaling by allowing client instances to be added or removed as needed without additional explicit message endpoint configuration.
Note that this callback queue pattern can be extended to the server side in order to efficiently implement fully stateful services when necessary.
As we shall see, using this MDA approach, even for simple blocking request/response calls has several significant advantages over more “traditional” web service based implementations in spite of the perceived increase in complexity.
Web Services versus MDA
Here we provide a brief summary of the respective advantages and disadvantages of the Web Service and MDA pattern
- Simple and well understood pattern for synchronous request/response
- Abundant and mature developer tooling available for a variety of platforms
- Easy for developers to implement, debug, and understand.
- Synchronous blocking request/response patterns are easy to implement.
- Numerous point-to-point integrations can be difficult to manage at enterprise scale.
- Potential firewall and DNS configuration issues can cause disruptions.
- No single point to manage access security. Every service instance must be secured and monitored individually.
- Service discovery can be difficult/complex
- Encourages use of synchronous/blocking communication patterns, which can cause scalability issues at high volume.
- Requires additional deployment of load balancing infrastructure for horizontal scaling.
- Only scales well when services are nearly or completely stateless.
- Managing test environments, which may require access to multiple versions of the same service, is challenging
- DNS or port-assignment schemes typically used to manage services in an enterprise test & staging environment are complex.
- High availability features can be challenging to implement
- Need to explicitly manage retries, failover etc. at the client application level.
- Connectionless architecture, coupled with the cost of setting up SSL connections, means that secure services can encounter scalability issues at high request volumes.
- SSL resumption ameliorates this problem but can be difficult to configure (particularly cross-platform).