- Low coupling
- Improves modularity
- Promotes parallel development
- Promotes scalability
- Infrastructure costs are usually higher
- Integration testing complexity
- Service management and deployment
- Nanoservice anti pattern i.e where a service is too fine-grained
Why do many microservice projects fail?
- Lack of
How to prevent your projects from failing?
- Determine applicability
- Prioritise automation
- Have a clear plan
- Avoid common pitfalls
This is a code project that can be used to start off from when developing a new microservice to save time.
Why is important?
- A significant amount of time setting up
- Similar code for each microservice setup
What should the template contain?
- Cross-cutting concerns
- Connection setup and configuration to databases and message brokers
- Project structure
Code Repository Setup
- Mono: where all code will be in a single repository
- Discrete: where codebase is split into a seperate repository
- Easier to keep input/output contracts in sync
- Can version the entire repo with a build number
- Different teams working in the same repo can break the build, disrupting CI/CD for other teams
- Easier to create tight coupling
- Long build times, large code repo to download
- Different teams can ‘own’ different repositories
- The scope of a single repo is more clear
- Contract versioning becomes more complex
- Unless managed properly, discrete repositories can easily become monoliths
- More up front cost in setting up repos and CI/CD pipeline
They should be loosely coupled from each other but should have high cohesion i.e each microservice will contain only things that are strongly related to each other. Remember the common closure principle which states that things that often change together should often close together. The most widely used tactics is through business cases, technical capabilities or function objective to make sure a suitable microservice has a level of granularity eg. Order Management, Shopping Cart Management Order Management can be decomposed into the following microservices :
- Order history
- Order tracking
- Order placement
- Order dispute
Shopping Cart Management can be decomposed into the following microservices :
- Cart Upselling
- Cart Promotions
- Cart Cost Calculator
- Cart Recovery
- Remote Procedure Invocation: is simple and easy to understand and can be used using REST and Apache Thrift. It follows the Request/Response pattern ie. synchronous
- Asynchronous Message-Based Communication: in a scenario where the response is not immediately required eg using Messaging, a microservice can publish a message on the message bus for other services to consume. It follows publish/subscribe pattern. This can, however, lead to over complexity. It is always advisable to stick to synchronous communication except for in-cases where the communication must be asynchronous
This is an extremely important component required in microservice architecture in order to be able to support dynamic scaling. If one microservice needs to send a request to another microservice it needs to be aware of the available instances and their network. The number of instances of each microservice maybe scaled dynamically to adjust changed in a node, therefore, other services communicating with these services must be aware of these changes. To solve this problem, we introduce a service registry component that holds the currently available instances of the microservice and their network location.
How it works When a microservice starts it registers itself with the service registry which will add this microservice to its database same in a shutdown instance which triggers a remove from the service registry. Then at regular intervals, we can introduce a health check API which performs a health check at regular intervals. When a microservice is required the service registry is queried for the available instances and the network location.
This talks about how services are able to query the service registry either directly or indirectly.
Client Side Discovery This is when a service directly queries the service registry to obtain network location for an instance of the required service and the service registry replies back the network location information and the caller uses this information to call the instance Server Side Discovery Here the microservice performing this request have no knowledge of the service registry , it simply send the request to a load balanced endpoint and the load balancer will query the service registry for an instance and network location of the required microservice endpoint.
The Server Side has an advantage over the Client Side discovery because clients do not need to query the service registry while the disadvantage is that there are more network hops involved before the request arrives at the microservice destination this can be mitigated against by building the service registry directly in the load balancer
DataBase Patterns Shared Database
Order Placement Microservice
Customer Details Microservice Product Details Microservice all using the same database in this case DB transaction is used to guarantee data consistency and integrity. There is a possibility of performance issue due to deadlocks also schema change too by another team.
Database Per Service Order Placement Microservice
Customer Details Microservice Product Details Microservice all have their own separate databases. Different service can have different database technologies that base suit their requirement eg. using SQL database, NOSQL
It is difficult getting aggregate data across services however this can be achieved by API composition or event store
A Service referred to as the API composer queries data from the multiple services and then performs an in-memory join
It helps services keep track of state changes of an object in a reliable way. The difference between event sourcing and using a database directly is that we use an EventStore and persist objects to it. Services are able to subscribe to the different events handled by the event store in this way the event store acts as a message broker.
A distributed transaction implies altering data on multiple databases which arises mostly on database per service pattern, as a result, this becomes complex as the commit/rollback of data must be coordinated in a transaction as a self-contained unit, as a result, the entire transaction commits or rollback.
Phase 1 : Commit Request - Coordinator service sends a query to commit message - Services execute the transaction but do not commit - Reply Yes/No depending on if they were successful Phase 2 : Commit -if all services replied yes - coordinator sends a commit message - Services commit the transaction - Reply with an acknowledgement - If at least one service replied with no - Coordinator sends a rollback message - Services rollback the transaction
The disadvantage is that this is a synchronous operation which might result in the blocking because the services will have to wait for the coordinator on instructions to proceed also if the coordinator goes down the services hang indefinitely
is an alternative to 2 phase commit to managing distributed transactions, it is a sequence of local transactions in different microservices each local transaction updates the database of that microservice and then publishes an event or a message to trigger the next local transaction in the saga. If one local transaction fails the saga execute a series of compensating transactions that rollback changes of local transaction forming part of the distributed transaction that has already been executed. There are 2 main different types of Saga implementation
- Choreography-based sagas Were each local transaction publishes domain event that will trigger local transaction in other services until the saga is completed
- Orchestrator-based sagas An orchestrator which is usually created for each saga. It coordinates the whole saga. This orchestrator is also a microservice on its own. It lets each microservice in the saga known when to be called or to be rollback if any of the microservice fails.
Fault Tolerance and Monitoring
It is important to have redundancy and high availability. We must also have a redundant service registry and the redundant microservice hosted on another server entirely. If a service tries to connect to a service and it is unable to connect it should immediately connect to the redundant service and also create a log issue when the failover resource has been used so that the main service can be fixed..
Circuit breaker pattern
this helps prevent failures in some part of the network or in a microservice from bringing down the system. For more information on Circuit Breaker Pattern It should be a cross-cutting module in the microservice architecture
Health Check API
Used to get status of a service. This is usually used by the service registry to check on register services to check if they are up and running frequently.
Always tag a request with a GUID for logging on the different microservices or better to use a log aggregation technology eg elastic, logstash , kibana stack, aws cloud watch, Splunk.