Microservices and Best Patterns
Big problems require big solutions. Achieving the best result for a solution is always what every engineer, architect and developer wants in their resolutions.
A very efficient solution throughout history is too map your problems and know how to divide them so that each part has the best efficiency when reaching the final result.
Speaking of technology for many years this kind of thinking was a way to solve certain problems of software architecture. When looking at the past, we are faced with theories that always aimed to partition to reduce software complexity, examples such as: Modularity and Service Oriented Architecture are interesting examples to be cited.
At the beginning of the last decade, many engineers and architects ended up resorting to this principle of dividing the problems. With the birth of increasingly robust businesses, ever-increasing demands for availability, service and social related integration moving more and more digitally, high scalability has become an approach we need to address.
Given this scenario, the Microservices architecture was born, a very different resolution from modularity and SOA, but with a similarity, the division of problems as a solution.
In the past decade, technologies emerged that propelled the world to our experience and iteration today with services and products, which completely changed the way we communicate and act. Devops, Container and Cloud Computing have brought new perspectives for companies to be born, grow and also die. At some point this digital cataclysm hit you in some circumstance. New languages emerged: Go, Swift and Typescript for example. Other simpler and more productive syntax languages deserve to be mentioned as JavaScript and Python became popular and will not soon be forgotten.
Development became an art and the command and control of the waterfall lost total space and we were faced with the so interactive and incremental, the agile methodology. Databases are no longer relational and terms such as NoSQL and NewSQL have given a new horizon and made it possible to advance in the data universe.
Consolidating all this disruptive engineering needed something new. In 2012, what we now know as Microservice Architecture appears.
Following the same problem division logic, this architecture is premised on dividing into many microservices that communicate through external APIs interfaces, loose coupling is a vital feature, so the independent lifecycle of each microservice is something that allows much more freedom due to the technological characteristics that the moment allowed companies to readapt, whether at the time of development, delivery in a production environment or operational support.
Systems that use monolithic architecture are premised on a single unit that determines how everything works. Systems that follow the modular monolithic concept are already more fragmented, in which we can have small modules, but the modules cannot be separated because all the modules together manage to reach the final objective that is to compose the system.
Microservice Architecture Features
- Microservices must have separate processes
- Microservices are divided vertically
- Microservices are deployed independently
- Microservices communicate in a simple and lightweight way, which can be via RPC or Message
Microservice Architecture advantages
- Scalability
- Development speed
- Robust ecosystem (Container, Cloud Computing, DevSecOps and Serverless).
- Less complexity in applications, due to separation ofcresponsibility and its reduced size
Microservice Architecture disadvantages
- Larger number of components and integrations (Database, Services, Container and Processes)
- Infrastructure complexity
- Multiple Rest/RPC calls
- Increase in network traffic
- Security management becomes more complex
- Complexity of distributed systems
Now that we have contextualized the reader in relation to the Microservices architecture, we will address the Design Patterns of this architecture and the importance of following these recommendations.
Design Pattern for Microservice Architecture
Database per Microservice
After carrying out the division of services by business entities, domains and subdomains, we apply the Domain Driven Design. We need to define the data store and the best way to deal with data in a distributed architecture is for each microservice to have its own data store. They can even share the same physical database, but they must use separate schema and tables.
Strong
- Weak coupling between the teams that develop the services.
Weak
- Sharing data between services becomes a challenge.
When to use Database per Microservice
- In large-scale enterprise applications
When not to use Database per Microservice
- In small-scale applications.
Circuit Breaker
Great for preventing a service failure that could lead to cascading failures throughout the application. A Microservice must request another Microservice through a proxy that works similarly to an Electrical Circuit Breaker. The proxy should count the number of recent failures that have occurred and use that to decide whether to allow the operation to continue or simply return an exception immediately.
The circuit have three states: Closed, Open and Half-Open
Closed
The Circuit Breaker forwards requests to the Microservice and counts the number of failures in a given period of time. If the number of failures in a given period of time exceeds a threshold, it trips and goes into the open state.
Open
the microservice request fails immediately and an exception is returned. After a timeout, the circuit breaker goes into a half-open state.
Half-Open
Only a limited number of Microservice requests are allowed to pass and invoke the operation. If these requests are successful, the circuit breaker will enter the Closed state. If any request fails, the circuit breaker goes into the Open state.
Strong
- Improve fault tolerance and resilience of microservices architecture.
- Stops the cascade of failures for other microservices.
Weak
- Needs sophisticated exception handling.
When to use Circuit Breaker
- Incremental migration of a large Backend Monolithic application to Microservices.
- In large corporations, API Gateway is mandatory to centralize cross-cutting and security concerns.
When not to use Circuit Breaker
- Loosely coupled, event-driven microservices architecture.
API Gateway
API Gateway sits between the Client APP and the backend microservices and acts as a facade. It can act as a reverse proxy, routing the client's request to the appropriate backend microservice. It can also support distributing the client's request to multiple microservices and then returning the aggregated responses to the client.
Strong
- Reduce the number of round trip calls between Customer and Microservices.
- High security through SSL termination, authentication and authorization.
- Centrally managed cross-cutting concerns, eg Logging and Monitoring, Throttling, Load Balancing.
Weak
- It can lead to a single point of failure in the Microservices Architecture.
- If not scaled up, they can easily become the bottleneck for the entire Company.
When to use Gateway
- In complex Microservices Architecture, it is almost mandatory.
- In large corporations, API Gateway is mandatory to centralize cross-cutting and security concerns.
When not to use Gateway
- Number of microservices is quite small.
Strangler
Strangler means incrementally migrating a monolithic application to microservices architecture, gradually replacing specific functionality with new microservices.
Strong
- Safe migration of Monolithic application to Microservices.
- The migration and new functionality development can go in parallel.
Weak
- Sharing Data Store between the existing Monolith and new microservices becomes challenging.
- Adding a Facade (API Gateway) will increase the system latency.
When to use Gateway
- Incremental migration of a large Backend Monolithic application to Microservices.
- In large corporations, API Gateway is mandatory to centralize cross-cutting and security concerns.
When not to use Gateway
- The Backend Monolith is small, then wholesale replacement is a better option.
Event Sourcing
For resilient, highly scalable and fault-tolerant systems, they must communicate asynchronously via event exchange. Because data is stored as a series of events rather than direct updates to the data stores, various services can replay events from the event store to calculate the proper state of their respective data stores.
Strong
Loosely coupled, event-driven microservices.
Weak
Reading entities from the event store becomes challenging and often requires additional data storage
When to use Event Sourcing
- Highly scalable and resilient Microservice Architecture.
- Typical Message Driven or Event-Driven systems (e-commerce, booking, and reservation systems).
When not to use Event Sourcing
- In simple Microservice Architecture where Microservices can exchange data synchronously
CQRS(Command Query Responsibility Segregation)
In the CQRS standard, the modifying data part of the system (Command) is separate from the reading data part (Query). This pattern applies the SOLID principle, Single Responsibility Principle.
Strong
- Faster data reading in event-driven microservices.
- High data availability.
- The read and write systems can scale independently.
Weak
- The overall complexity of the system increases
When to use CQRS
- In a complex domain model where reading data needs to query multiple Data Store.
- On systems where read and write operations have a different load.
When not to use CQRS
- On systems where read and write operations have a similar load.
Saga
Saga is a local transaction sequence where each transaction updates data in the Data Store in a single Microservice and publishes an Event or Message. The first transaction in a saga is initiated by an external request (Event or Action). Once the local transaction completes (the data is stored in the Data Store and the message or event is published), the published message/event triggers the next local transaction
Choreography
Decentralised co-ordinations where each Microservice produces and listen to other Microservice’s events/messages and decides if an action should be taken or not.
Orchestration
Centralised co-ordinations where an Orchestrator tells the participating Microservices which local transaction needs to be executed.
Strong
- Provide consistency across transactions in a highly scalable or loosely coupled, event-driven microservices architecture.
Weak
- Difficult to debug and complexity grows as the number of microservices increases.
When to use Saga
- In systems where distributed NoSQL databases are used.
When not to use Saga
- Lowly scalable transactional systems with SQL Databases.
Top comments (1)
Insightful!