Hello friends, welcome! I hope that all of you are having a good time. Our previous article was on Service Discovery. We had discussed a bit about it in our introductory articles and then had a dedicated article for service discovery. Taking the next-step after discovering the service, it is time to enter the actual playground. Yes, this article is regarding inter-service communication. We have been successful in discovering services as per our requirement, so why not understand the inter-service communication!
We have discussed in our previous articles that in a monolithic application, the components invoke each other through language-level methods or function calls while in microservice based-application, it is a distributed system. It runs on multiple machines. Each and every service instance can be considered as a process. So there is a need for some inter-process communication mechanism.
Before selecting an IPC or inter-process communication mechanism, we need to understand how the services interact with each other. There are numerous interaction styles and they can be categorized with the help of two dimensions.
The first dimension includes two types of interaction styles. The first one is one-to-one type. Here, each client request is processed by a single service instance. The second one is one-to-many type. Here, each client request is processed by multiple service instances.
The second dimension also includes two types of styles. The first one is synchronous type.Here, the client expects a timely response from the service. The client might even block until it doesn’t receive a service. The second one is asynchronous type. Here, the client won’t block while waiting for a response. There is no emergency in this type.
Now let us understand these interactions in more detail.
Number 1: Request/Response – The cycle begins when the client makes a request for a service and then waits for the response. Once the request is done, the client expects a response in some amount of time. If it is a thread-based application, the thread is responsible for making the request and might even block it until the request is not received.
Number 2: Notification or a one-way request – By the name itself, you could imagine that the client sends a request to some service but there isn’t a reply expected or sent. So it is a type of one-way request.
Number 3: Request or asynchronous response – Here, the request is sent by the client to some service and the service replies asynchronously. The client doesn’t block while waiting because it assumes that the response might not arrive for a while.
Number 1: Publish or subscribe – The client publishes a notification message. It is consumed by zero or more services, depending on the relevance.
Number 2: Publish or asynchronous responses – The client publishes a request message. Then, the client waits for a certain period of time for receiving responses from the interested or relevant services.
Do you wonder how service interaction actually takes place? Each service uses a combination of the above-mentioned interaction styles. While for some services, a single mechanism is enough. But usually, most of them use a combination of the inter-process mechanisms.
For example, in a taxi-hailing application, the interaction shall begin with a user requesting for a trip. Just imagine the process when you book an Uber or some other taxi-hailing service. There would be a combination of notifications and requests/responses. You might also need to subscribe first. Your smartphone will send a notification for pickup to the trip management service. The service would then verify your account and then process the request accordingly. The trip is created and would also include publish/subscribe for further notifications like driver details, location, etc. So there are a lot of service interactions included in such applications.
For efficient service interactions, we need to define API’s. We have already gone through the API basics in our previous article. For friends who have directly visited this article, please go through the previous article to if you have any doubts regarding the API basics. So let us now understand, how to define the API’s?
Defining a precise service API is very important. One needs to define it using an interface definition language. Another option is to define the service using an API-first approach. The interface definition is written first and then it is reviewed by the client developers. The service implementation should be done after iterating the API definition. This procedure shall help you meet your client specifications.The nature of an API definition depends on the type of IPC mechanism being used. For example, a messaging application needs an API consisting of message channels. For HTTP, the API consists of URL’s and request/response formats.
There are numerous IPC technologies. There is synchronous request/response based communication mechanisms like HTTP-based REST or Thrift. An alternative to this is the asynchronous message-based communication mechanism like AMQP or STOMP. There are many message formats as well. The services can use human-readable text-based formats like JSON or XML. The binary format like Avro or Protocol Buffers are also available and a lot of people consider it as more efficient. So let us discuss these IPC technologies.
While using messaging, the processes communicate with each by exchanging messages asynchronously. The client makes a request for a service by sending a message. The service replies by sending a separate message to the client. As the communication is asynchronous, the client doesn’t block waiting for a reply. In fact, the client assumes that the reply won’t be immediate.
So what does the message consist of? It contains headers and a message body. The headers include metadata about the sender and some other details. The body includes the actual message. The messages are exchanged over channels and there is no limit to sending messages. The ones who send messages are called producers. On the other side, there is no limit to the number of consumers as well, the ones who receive messages through the channel. There are two types of channels: point to point channel and the publish-subscribe channel. The point to point channel delivers the message to one consumer. Many services use the point to point channel for one to one interaction style. The publish-subscribe channel delivers the message to many consumers, the ones who are attached to the channel. The publish-subscribe channels are used for one to many interaction styles.
There are numerous messaging systems and choosing one could be difficult. But always choose the one that supports more programming languages. Some services support standard protocols like AMQP and STOMP while other messaging systems have proprietary documented protocols. There are many open source messaging systems like RabbitMQ, Apache Kafka, Apache ActiveMQ, etc. All of them support some sort of messages and channels and are striving to be highly reliable. But they are also different in some aspects.
Like anything else in this world, there are advantages and disadvantages of messaging. There are advantages like it enables decoupling of the client from a service, message buffering, flexible client-service interactions, and explicit inter-process communication. The disadvantages include an increase in the additional operational complexity and the increase in the complexity of implementing request/response based interaction.
In this mechanism, the client sends a request to the service and the process initiates. The service processes the request and sends a response. Here, the request can be blocked while waiting for the response. Other clients can use asynchronous, event‑driven client code. Here, the client assumes or expects that the response will be received timely. There are numerous protocols and we will discuss the two most popular ones. These are known as REST and Thrift. Let us know them in detail.
A lot of developers are now developing API’s using the RESTful style. It uses HTTP. Here, the main concept is that there is a resource that represents a business object like customer/product or could also represent a collection of business objects. REST uses the HTTP verbs to manipulate the resources. These are referenced using URL.
REST emphasizes on the scalability of component interactions, the generality of interfaces, independent deployment of components, and intermediary components. All these help in reducing the interaction latency. HTTP based protocols are simple and familiar. Testing is also easy because it can be done within a browser using some extension. It supports request/response-style communications as well. The disadvantage of HTTP based protocols is that one can use HTTP notifications, but the server should always send an HTTP response. Also, the client must know the URL of each service instance.
Thrift or Apache Thrift is an alternative to REST. It is a framework and helps in writing cross-language RPC clients and servers. It provides a C-style IDL to define APIs. A Thrift compiler is used to generate the client-side stubs and server-side skeletons. The compiler supports numerous language such as C++, Java, Node.js, etc.
The thrift interface has one or more services. The definition is analogous to Java interface and is a collection of strongly typed methods. The methods can return a value which could be void or can be defined in one-way. The methods return a value to implement the request/response type of interaction. Here, the client waits for a response and can throw an exception as well. Here, the server doesn’t send a response. Thrift supports many message formats such as JSON, binary, etc.
As compared to JSON, binary is more efficient as it faster to decode. Binary is also a space-efficient format while JSON is browser friendly.
This article includes the basic aspects of inter-service communications. Definitely, there is more depth to this topic but at the introductory level, sharing the basic knowledge is sufficient. So after the introduction to inter-service communications, we discuss the interaction styles. Here, we understand the classification of interaction styles in two different dimensions. Knowing the interaction styles is not enough, understanding and implementing them is important.
So we move on to the next section that includes the IPC technologies. Here, we discuss the asynchronous and synchronous based communication technologies in detail. We also go through the asynchronous technology protocols like REST protocol and Thrift protocol. Overall, inter-process communication is quite important for the communication to occur. We already have the mechanism and the method through service discovery, but this article covers the major implementation part. So let us gather and implement our knowledge of inter-process communication until we meet in the next article. Good luck!
Here is the link to the previous article of this series.