Microservices and the Saga Pattern, Part 1
In this first part of this three-part series, we explore the basics of microservice-based architectures, and how the role they serve in application development.
Join the DZone community and get the full member experience.Join For Free
Microservices are not new in the market, they have been a part of our day to day life for a while now, so here in this post, I would like to share with you my understanding of what microservices are and what the Saga Pattern is, which is widely used with the microservices. We will start with what exactly we mean when we say: (i) we need a microservice, (ii) what it means to be reactive, and then (iii) dig into the concept of Saga patterns, with respect to a distributed system along with an easy to understand real-life example.
So let’s get started.
I hope that most of us have heard the term microservices. If not, then, in layman terms, I would define a microservice as something which, alone, can perform a specific functionality within a larger system and is independent of other things around it; i.e., it is only concerned about the functionality for which it was created and should only deal with that functionality. For example, if we are preparing a product like a Restaurant application, then we would be creating several small microservices like the Orders, Customers, Reservations, etc., which would perform specific tasks around a specific functionality of the Restaurant application, and would be interacting if and only if we need to have the functionalities come together and that, to, only through their exposed APIs. For now, we can think of an API as endpoints of a service which are exposed for use to the outside world (outside of the microservice itself). I would like to mention some key characteristics of a microservice here:
- Easy Deployment: Each microservice is independently deployed, this is what makes a microservice different from what we call a Service Oriented Architecture (SOA).
- Data Ownership: Each service should own its data, meaning that no external entity/component/service should ever be able to access (read) this data directly or do an update (write) to this data.
- Data Flow: Communication between reactive microservices or within a reactive microservice must only be in the form of asynchronous messaging (Note: Synchronous communication tends to move the service away from the notion of being reactive).
- Isolation of failure: Isolation of failures, meaning that out of n services in your application the service that has a problem/failure should only be the one to suffer and other microservices should remain responsive. This would mean that serious failures are isolated to a single service so that the complete application doesn’t go down. Failures should not propagate to dependent services and thus should not cause the other service to fail as well.
Here’s a top-level view of how our Restaurant application would look in a microservices architecture:
Now with the help of the above mentioned characteristics of microservices, let us see why the services in a Restaurant application should be called microservices. We have three services in our application: 1. Orders, 2. Customers, and 3. Reservations. So let’s analyze and see their behavior and answer the question of whether they should be classified as microservices or not:
- Independent Deployments: All these services work independently of one another and are deployed independently, for example, an improvement in the Orders service doesn’t wait for the Customer service to implement this enhancement in it, instead the Order service is deployed with the enhancement (of course supporting the previous version as well so that we don’t break any chain of usability) and when the Customer service feels like using this enhancement they switch to the enhanced version of the Order service.
- Data Rights/Ownership: The data which is used by the Orders microservice is conceptually related to the functionality for which the microservice was created in the first place, it may contain information like the placedOrders, rejectedOrders, waitingOrders, etc. Similarly, the Customer service would have data specific to its use case, and we do not allow the Customer service to interact with the database tied to the Orders service directly. If Customer service needs some information about a particular order then it could get that only by requesting the Order service to provide it by calling the Order service’s exposed endpoint/API.
- Asynchronous Communication: Asynchronous communication between the services and within a service avoids problems of contention, for example, sitting idle/blocked while waiting for a response/resource. Internals of the services have to be implemented in such a way that they don’t wait for a response from some other part. Instead, when a response comes, we do the processing on that at that time only. So it’s something like: if I go to a stationery to get my documents printed and I see that the printer is already busy then I should not wait there and sit idle, rather, I should ask the attendant to get the documents printed and inform me when it’s done; meanwhile, I would go to some other store/section and get a folder to keep those documents in.
- Isolation of Failures: Let's suppose our Reservations service is down. That does not mean that a Customer should not be able to see his details from the customer service or not see what their previous orders from the Order service were, only that the reservations should be affected by the failure of the Reservations service (we try to keep the impact of a failure as minimal as possible.)
So do these services qualify for being called microservices?, I would say yes since they all possess the characteristics of a microservice.
Tune in tomorrow when we continue our look into microservices architecture and responsive design.
This article was first published on the Knoldus blog.
Published at DZone with permission of Prashant Sharma, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.