Optimizing Microservices Communication: Peer Calls vs Asynchronous Messaging
Introduction to Microservices Peer Calls
When developing a microservices architecture, one often encounters the necessity for one microservice to access another. This is commonly referred to as a peer call. Generally, peer calls are performed by invoking the target microservice endpoint using the same protocol that the clients use. For example, GraphQL and associated libraries in your host language can be used for making GraphQL client calls. High-performance inter-process communication protocols like Google’s gRPC are also options.
However, it’s important to minimize the use of peer calls as much as possible. While peer calls are straightforward and seemingly simple, they can introduce undesirable coupling and dependencies between microservices, leading to complex and tightly coupled systems that are difficult to scale and maintain.
The Challenges of Peer Calls
Peer calls can significantly impact the performance and reliability of a microservices-based application. To illustrate, let's consider a scenario involving five microservices:
Microservice A needs data from Microservice B to process a request. When Microservice A makes an HTTP request to Microservice B, it incurs a 300ms latency. Microservice B then needs to retrieve data from Microservice C, adding another 300ms, and so on.
As you can see, a single request to Microservice A can trigger a chain of HTTP requests that significantly increase latencies and introduce bottlenecks in the system. This is especially problematic in high-traffic scenarios where the number of requests can explode the latency issues. Here are a few more points to consider:
Each HTTP request incurs additional network overhead. In a situation with 1000 requests to Microservice A, 4000 HTTP connections will be generated, significantly increasing the load on the network and potentially causing performance issues. The failure of any single microservice in the chain can bring down the entire process.These challenges highlight the need for an alternative approach to microservices communication.
Optimizing with Asynchronous Messaging
A far more efficient and resilient approach in the context of microservices is to use asynchronous messaging for data synchronization. Instead of directly invoking one microservice from another, each service maintains its own copy of the data it needs within its context. This way, services can react to events posted by other services. Let's explore this concept in some detail with a real-world example.
Case Study: An E-commerce Application
Consider an e-commerce application with three microservices: Customer, Product, and Order.
Customer handles customer entity operations like creation, editing, and deletion. It also retrieves customer data. Product handles product entity operations like creation, editing, and deletion. It also retrieves product data. Order combines data from the customer and product services to create and fulfill orders.Workflow
Here's how the services interact using asynchronous messaging:
When a Customer service receives a POST request to add a new customer, it inserts the customer into its own database and then emits a “customer created” event to an event bus. Similarly, when the Product service receives a POST request to add a new product, it inserts the product into its own database and emits a “product created” event to the same event bus. The same sequence of events applies when customer or product data is edited or deleted. The Order service subscribes to the event bus and listens for events from the Customer and Product services. When it receives a “customer created” or “customer edited” event, it updates its local copy of the customer data accordingly. The same process occurs when the Order service receives events from the Product service.This approach decouples the microservices and ensures that each service operates independently, improving the overall performance, scalability, and reliability of the system. The use of asynchronous messaging allows events to be processed in parallel, reducing the latency and avoiding the bottleneck issues found in peer calls.
Conclusion
In conclusion, while peer calls are a straightforward method of accessing one microservice from another, they can introduce significant challenges such as increased latencies, network overhead, and risk of failure. By leveraging asynchronous messaging and maintaining local copies of data, microservices can communicate more efficiently and effectively, leading to more resilient and performant systems.