Microservices Architectures

As part of API development, there are a lot of patterns or architecture that will be available. We can't stick with one pattern as part of large distributed application development. Applications can be developed with multiple patterns based on the use cases as well as application performance also.

I have created multiple services with multiple architectures or patterns based on the multiple-use case in order to achieve the best results.

I have started creating microservices for my application. Because my application involves multiple entities, each entity plays a major role in the corresponding services. Based on my need I can scale, extend, and migrate the corresponding service. I have created multiple services. I need to provide my services to the consumers. Here my consumers are web applications and native applications.

API gateway

All the consumers need to consume the services via endpoints or URLs. As part of services development, we can add or update a number of endpoints based on the business. Because of that consumers don't need to change API endpoints as well as the resource path. The client can stick with endpoints. The client doesn't need to know each and every service endpoint. In this case, they need a simple URL for the request and response.

Using Apigateway we can provide the resource URL. In the background we can point to any service based on our need. I need to forward the client request to the corresponding service. So I need some passthrough layer to map the consumer request to services, so I have chosen the API gateway. It will maintain all the services we want to expose to the consumers and resources path also. It will do the authentication. All my requests will be authenticated in my API gateway itself. Authorization we can do it in API gateway or corresponding service based on our need. It's a one-way in and out. Consumers can consume all their services using the gateway alone.

DB Per Service

Once the gateway redirects the consumer requests to the corresponding services, individual service needs to get the data from the DB. My DB will belong to current services or all other services. All my data will belong to a particular set of tables. Other services will not consume those tables. It will be used only by these services. But in real-time it will not be. One or more tables will be used to maintain the relationship between the entity. Then corresponding services also will use those tables. In this case, we need to decide whether we need to keep the table inside or move to the common one. It will be purely based on how frequently we are making the request and the rest of the services to consume this table. Sometimes I have moved the cross table to other entities or commonly based on the performance, load, and business.

Sometimes I have a chance to have all the tables relevant to the entity. In this case, this DB and tables will belong to this service alone. I have created a separate DB or schema for those tables alone. Db and service are fully interconnected with each other. The corresponding tables fully disconnected from the rest of the entities. So scalability will be very easy. I can move my service and my DB to anywhere based on my need.

Event Sourcing

All my services are running fine. For some of my services, I am doing ceraint operations, and based on that I need to do some other operations on other services. I can call those operations from the current service using API calls but it leads to an increase in the API response time. Because I need to know whether the API call is a success or not. Current API doesn't require waiting until the other operations need to complete.

This is where we need to publish the events. The list of entities that need to perform the operations will listen to those events and complete the subsequent operations. It will reduce the service dependencies but will increase the application complexity.

We can publish the methods using different service providers like RabbiMq, Kaffka. It's called Pub/Sub.

SAGA

All my transactions have been completed successfully on different services. Suppose one of my operations is getting failed. Even after the number of retries, those operations are still getting failed. Without this operation, the entire transaction will not be completed. It will question the application's reliability. In this case, we need to revert to the operation we have done at different services. We can revert the transaction either via events or API calls based on our need. This is called SAGA. It will have a binary state, either success or failure. Success, all transactions have been completed on a different distributed system.

Failure, all transactions have reverted successfully on a different distributed system. It will increase application reliability. But it will increase application complexity. Based on our business we need to check whether it will be applicable or not. In some cases, it doesn't require reverting the entire transaction in case of failure in one entity. We can find some other ways like fall back mechanism on the backend or notify the end-user to do some action against it. But it will surely be based on the business.

CQRS

All services are working fine. When more customers will use the application I can scale my services. How about MY DB. We need to scale it vertically or we can add one more replica of my DB, so the read and write operation will be handled by separate DBS. In my scenarios, I have added Redis for my read operation, which will be called very frequently.

So all my requests will be handled by Redis itself; it doesn't require the DB call. It's up to you can decide which kind of DB, either SQL or NoSQL, based on the performance and business. But deciding on multiple DBS should depend on the load on the database.

STRANGLER

Services are working fine based on the customer load. I have migrated my application from monolithic to microservices. Either I can do a complete replacement or I can roll out a set of APIs. I have decided to move a set of API that will be used by a set of customers instead of a complete replacement.

Even if there will be a problem set of customers that will get affected by that particular feature alone, still my services and application will run without any issues. I can migrate API to microservices in incremental order. This is called the Strangler pattern.

Retry or Circuit Breaker

I have added retry and circuit breaker in all the patterns based on the need. It's kind of add ons from my point of view. It will increase application reliability.

Conclusion

I have designed these patterns based on my need. If you have any suggestions or improvements on this please let me know. Comments are always welcome.