Essential microservices integration patterns

Real-world microservices implementations typically rely on both active and reactive communication patterns; here’s how they work

A microservices architecture fosters the building of software applications as a suite of independent, fine-grained, and autonomous services. Therefore, when we build a real-world business use case, the microservices that comprise the application have to communicate with each other. With the proliferation of fine-grained services, integrating microservices and building inter-service communication has become one of the most challenging tasks in the realization of microservices architectures.

To understand the challenges of a microservices architecture, let’s first look at the very near past. In the pre-microservices era of service-oriented architecture (SOA) and web services, we would use a central enterprise service bus (ESB) architecture, where all of the service composition and integrations were implemented.

For example, as shown in Figure 1, all of the services were integrated with an ESB, and selected business functions were exposed to the consumers via an API management layer. The ESB provided all of the capabilities required to integrate disparate APIs, data, and systems. 

wso2 microservices fig1 WSO2

Figure 1: A centralized integration architecture using an enterprise service bus.

However, when we move into a microservices architecture, having a monolithic integration layer with a large pile of business logic makes it really hard to achieve the fundamental concepts of microservices, such as being autonomous and oriented toward a narrow set of business capabilities. Therefore, it is not practical to use a central ESB as the integration bus.

A microservices architecture fosters the building of software applications as a suite of independent, fine-grained, and autonomous services. Therefore, when we build a real-world business use case, the microservices that comprise the application have to communicate with each other. With the proliferation of fine-grained services, integrating microservices and building inter-service communication has become one of the most challenging tasks in the realization of microservices architectures.

To understand the challenges of a microservices architecture, let’s first look at the very near past. In the pre-microservices era of service-oriented architecture (SOA) and web services, we would use a central enterprise service bus (ESB) architecture, where all of the service composition and integrations were implemented.

For example, as shown in Figure 1, all of the services were integrated with an ESB, and selected business functions were exposed to the consumers via an API management layer. The ESB provided all of the capabilities required to integrate disparate APIs, data, and systems. 

wso2 microservices fig1 WSO2

Figure 1: A centralized integration architecture using an enterprise service bus.

However, when we move into a microservices architecture, having a monolithic integration layer with a large pile of business logic makes it really hard to achieve the fundamental concepts of microservices, such as being autonomous and oriented toward a narrow set of business capabilities. Therefore, it is not practical to use a central ESB as the integration bus.

Instead, with a microservices architecture, microservices are integrated using the smart endpoints and dumb pipe style, where all of the intelligence lives at the endpoints, which are interconnected via a dumb messaging infrastructure. As shown in Figure 2, we can design microservices for the business capabilities that we have identified, and they have to communicate with each other to realize various business use cases.

wso2 microservices fig2 WSO2

Figure 2: A microservices architecture is characterized by smart endpoints and dumb pipes.

Although it sounds quite simple to break up a monolithic app and central ESB and offload those functions to each service, there are quite a few challenges that we face. So, it’s quite important to understand the common microservices integration patterns and select the suitable technologies and frameworks for implementing them. Let’s look at two of these key microservice integration patterns, active composition and reactive composition. 

Active composition pattern for microservices architecture

In an active composition pattern, microservices communicate using request-response style communication, where a given microservice can invoke one or more other microservices using synchronous messaging protocols such as REST/HTTP, gRPC remote procedure call, and the GraphQL API query language, among others. Figure 3 illustrates such a microservices integration scenario where services are organized based on different interaction types.

In an active composition microservice implementation, we can identify the core or atomic services. These are fine-grained, self-contained services, with no or minimal external service dependencies, that consist mostly of business logic and little or no network communication logic.

wso2 microservices fig3 WSO2

Figure 3: In the active composition pattern, microservices communicate using synchronous messaging protocols.

Atomic microservices often cannot be directly mapped to a business function as they are too fine-grained. Hence a specific business function may require a composition of multiple atomic or core services. The middle layer comprises such composite or integration microservices. These services often have to support a significant portion of the ESB functions such as routing, transformations, orchestration, resiliency, and stability.

By contrast, composite or integration services are coarse-grained relative to atomic services. They are independent from each other and contain business logic (e.g. routing, what services to call, and how to do data type mapping) and network communication logic (e.g. inter-service communication through various protocols and resiliency behaviors such as circuit breakers).

You will expose a selected set of your composite services—or even some atomic services—as managed APIs using API services and/or edge services. These are special types of composite services that apply basic routing capabilities, versioning of APIs, API security patterns, throttling, and monetization, as well as create API compositions. As shown in Figure 3, these APIs are centrally managed by a control plane or API management layer.

The benefit of active composition is that you can select diverse implementation technologies to implement core, composite, and API services. However, a drawback of this pattern is the inter-service coupling and dependencies. A given service may depend on one or more downstream services. So, active composition is suitable only for certain microservices interactions where interactive request-response style is a key requirement. 

Reactive composition pattern for microservices architecture

With reactive composition, services can communicate and create compositions using asynchronous, event-driven messaging. We can use one of two techniques to implement reactive composition: publish-subscribe messaging for multiple consumers or queue-based messaging for a single consumer.

As illustrated in Figure 4, in the reactive composition pattern microservices do not talk directly to each other; rather they send and receive messages to and from a centralized event or message bus. The business logic of a given service is implemented in such a way that, upon the arrival of an event, the service business logic is applied and executed. Service business logic also may submit new events to the event bus. This bus acts as the dumb messaging infrastructure, and all of the business logic is implemented at the producer or consumer level. 

wso2 microservices fig4 WSO2

Figure 4: In the reactive composition pattern, microservices communicate indirectly through an event bus.

Messaging techniques commonly used in the reactive composition are the Apache Kafka messaging protocol, the NATS cloud-native messaging protocol, and the AMQP protocol found in messaging software such as RabbitMQ, ActiveMQ, and Artemis.

Reactive composition eliminates the tight coupling between the services and makes services more autonomous. The reactive composition is often used in other microservice patterns  such as event sourcing and command and query responsibility segregation (CQRS), among others.

Now let’s take a look at how these patterns are applied in real-world microservices implementations.

Active and reactive patterns in real-world microservices implementations

In most real-world microservices implementations, we have to use a hybrid of active and reactive composition. As shown in Figure 5, we can use synchronous messaging-based composition for most of the external facing services. Such functions are often exposed to the consumers via an API gateway layer, which is comprised of multiple API services, and these functions are managed centrally by the API control plane.

Usually, the communications between API services and consumers leverage RESTful messaging or the GraphQL API query language. API services and management layers can be implemented using open source technologies such as WSO2 API Manager, Kong, and Gluu or commercial alternatives such as Apigee, IBM, Software AG, and Tibco.

wso2 microservices fig5 WSO2

Figure 5: Real-world microservices implementations typically make use of both active and reactive composition.

Both active and reactive composition styles require a rich integration framework or programming language that can cater to various integration and composition needs. For example, these may include message transformations, connectors to different systems and services, synchronous or asynchronous event-driven messaging, or support for a variety of different message exchange patterns. There are a few open source integration frameworks that are microservices friendly including Camel-K, WSO2 Micro Integrator, and Micronaut.io. These capabilities also are supported in certain programming languages (e.g. Ballerina.io) and language frameworks (e.g. Spring Boot).

Rather than using conventional RESTful messaging, the internal synchronous communication between services can leverage gRPC as the communication technology, owing to its performance, type-safety-ness and contract-driven nature.

The asynchronous event-driven services interaction can utilize event bus technology, such as software leveraging the Apache Kafka, NATS, or AMQP protocols. The asynchronous services should have integration logic that can consume or produce messages and exchange them with the event bus. Most of the integration technologies that we have discussed in this article can be used, but these same messaging standards are often supported within the libraries of most standard programming languages as well. When using messaging infrastructure, it’s important not to isolate any business logic from the event bus.

In this article, we discussed the two main approaches to a pure microservices implementation. However, in most real-world scenarios, microservices-based applications have to be integrated with monolithic systems in the enterprise. Thus you might want to build a bridging layer, often known as the anti-corruption layer, between the microservices and monolithic subsystems. In most practical use cases, the microservices and monolithic subsystems co-exist side by side, with the anti-corruption layer allowing the two to be seamlessly integrated without changing either of those systems. Existing integration technologies, such as an ESB or integration bus, can be used to implement the anti-corruption layer.

You can find more details and sample use cases of the microservices patterns discussed here in a book that I co-wrote with my colleague, Prabath Siriwardena, “Microservices for the Enterprise: Designing, Developing, and Deploying.”

Kasun Indrasiri is the director of integration architecture at WSO2. He is a key member of WSO2’s architecture team that drives the development efforts of WSO2’s integration platform.

New Tech Forum provides a venue to explore and discuss emerging enterprise technology in unprecedented depth and breadth. The selection is subjective, based on our pick of the technologies we believe to be important and of greatest interest to InfoWorld readers. InfoWorld does not accept marketing collateral for publication and reserves the right to edit all contributed content. Send all inquiries to newtechforum@infoworld.com.

This story, "Essential microservices integration patterns" was originally published by InfoWorld.