In Microservice Architecture, you will find several small independent services deployed on same/different machines talking with one another. Each service is defined to focus on a single responsibility/small functionality. Each service can be deployed independent of other deployment units. We focus our service boundaries on business boundaries, making it obvious where code lives for a given piece of functionality. We should avoid temptation to write big services and keep them as small as possible.
Philosophy behind micro services architecture is simple but implementing micro services architecture can be very challenging. This blog post talks about a few areas that require the implementation of quality Microservices Architecture.
Advantages of Microservices Architecture
- Scaling becomes easy. If there is some functionality which is used extensively we can deploy multiple copies of that service which represents given functionality.
- Eliminate long term commitment for technology stack and can implement new stack for new functionalities.
- Frequent deployments are allowed as an entire system is not brought down. This is not possible in monolithic architecture.
- Maintenance becomes easy as we can identify deployment units that are causing issues and can be rewritten easily.
- Fault tolerance is high as one service is down copy of same service is already there to support the load.
Microservices – Design Guidelines
Naming Convention for deployment units / services
In micro services architecture, functionality is spread across different services. Identifying which service holds require functionality can be very challenging. You can overcome this problem by establishing strong naming convention practices for your deployment units.
- Name of your deployment unit should explain clearly about the functionality that deployment unit holds.
- Deployment units should be designed to focus on single responsibility without naming your deployment unit. This can become challenging.
Identifying development practices for your service and agreeing on how things can be done is a good idea. However, spending time and making sure people are following the guidelines is less fun, as it is placing a burden on developers to implement all the standard things you expect each service to do. You can overcome these problems by creating a service template for your own set of development practices. That way teams can get going faster, and also that developers are forced to follow good practices which are already generated by templates. There are different ways to get these service templates. One recommended solution which we followed in our project is to use custom archetypes with a combination of velocity framework to generate template code.
One service calls upon another service, and another and so on. How can you figure out which particular request was transformed and what was called or not?
- One simple solution is to generate a Transaction ID per request. This Transaction ID that is transferred across calls allows you to track each request, ultimately simplifying routing. In the process of debugging an issue – your Transaction ID will be the key starting point for searching what went wrong along that request.
- On similar lines, every call to service should be identified with a unique number. I call this “Step ID”.
- Utilize a Design UI tool that allows you to search based on Transaction ID and Step ID. Searching with the Transaction ID should display all services that are invoked, along with the request and a reply from each service call. Such auditing tools become handy and very helpful in debugging issues.
Good auditing mechanisms are very important in Microservices Architecture. They enable views of all interactions between services and which services have problems. For example, a service that did not emit any calls at all.
General logging practices that are applicable to all enterprise applications are applicable here. There is one good practice that is more specific to Microservices Architecture. Every log that gets printed out from your service should print a Transaction ID and Step ID associated with that log. This is useful for debugging and can be achieved using advanced features in the logging framework called Mapped Diagnostic Context (MDC). MDC is simply a map managed on a thread-local basis. You can put any key-value pair in this map and since then every logging statement issued from this thread is going to have this value attached as part of the pattern. For more information on MDC usage look at: http://logback.qos.ch/manual/mdc.html
Defining good testing standards is crucial for your Microservices Architecture to be successful. Testing standards should involve automated testing along with manual testing by QA’s and business owners. Automated testing can be achieved using unit testing, integration testing and acceptance testing using tools like FIT and cucumber.
Automation is key for agile, flexible and productive Microservices development. Without continuous integration and delivery, Microservices concepts cannot be realized efficiently. Below are a few areas that require focus to establish quality deployment standards:
- One button deployment should be implemented. Establish automated way to continuously deploy, configure and manage your applications (redeploying, restarting….).
- Tools should offer automation and visibility via dashboards, monitoring the quality of the deployed application.
In monolithic architecture you will have dependency only on database and network. Designing for fault tolerance in monolithic architecture is simple and straight forward. When it comes to micro services this is very challenging. Design your application to handle the following scenarios:
- What to do if there is a timeout in one of the services that has been called?
- What to do if there is a fault reply from one the services that have been invoked?
- What to do if there is an oracle error code on invoking database?
- Which error codes should be retried and which should be ignored?
For the above scenarios, you can either retry (how many times?) or fail it gracefully. Whether to retry/fail depends on the type of error and design decisions.
Because each service talks to one another, it will be hard to pinpoint the source of the performance problem. Start using tools like App Dynamics which provides dashboards to monitor performance of your services. App Dynamics is very useful in analyzing performance related issues that come up in the production environment.
In micro services architecture, you will have a lot of services talking with one another, services talking with databases and ems or various other enterprise components talking with one another. It is important that these services and systems are up and running. One should establish a strong alerting system that would send out alerts in case of abnormal behavior in any of the services / systems like database and EMS. Below are references that will help you in understanding these alerting systems.
In Microservices Architecture there is a scope for a lot of manual and repetitive work due to the large number of deployment units / micro services. We need to get rid of this manual and repetitive work by developing some tools. Otherwise maintenance will become very complex. Below are some cases of repetitive work.
- It is common to upgrade services to new versions of java (Provided your services are in Java environment). Manually making changes to each service and deploying them is a tedious task. Can we think of automating this task?
- You want to update all your Microservices to use the latest version of some dependency. Do you have tools to do it in an automated way?