Microservices architecture offers various advantages over Monolithic Architecture, some of which are listed below:
- Loosely coupled architecture.
- Easy to scale based on demand.
- Small individual services based on business functionality.
- The technology stack of each microservice can be different.
However, when transforming from a traditional monolithic architecture to microservices, the common bottleneck is performance. According to Perforce Developer (Perforce Survey) Survey:
“The survey found that 33% of Java development professionals consider combined application performance to be the biggest challenge in microservices development. An additional 29% of respondents reported troubleshooting microservice-to-microservice performance as their biggest challenge.”
In this blog, I will list out the performance recommendations for developers of microservices:
- Reduce memory footprint of a microservice: Microservices footprint and business logic should be small. This way the performance will increase.
- Design Microservice Architecture for Performance and Security: A Microservice should be designed for a specific business requirement and should be designed for performance and security from start.
- Cache OAuth Tokens: OAuth tokens are costly, and time-consuming to generate and are used to secure microservices. Therefore, OAuth tokens should be cached by calling systems to avoid hitting the OAuth token generating API frequently.
- Use Asynchronous Non-Blocking Requests wherever possible: Asynchronous requests are non-blocking. Synchronous requests are blocking and can cause serious performance bottlenecks for other services. Asynchronous requests are non-blocking in nature and improve concurrency.
- Cache Database queries: Database queries and responses should be cached for non frequently changing data in the Database. This will reduce hits to Database and prevent the Database from getting overloaded. Use Indexing in Database RDBMS tables.
- Use Database connect pooling: Database connection pooling allows to use same Database connection for several requests. Making a new database connection is costly. Therefore, using database connection pools is recommended.
- Use Server-side caching: It is recommended to use cache for caching the response of microservices depending on request parameters. For example, for a microservice giving out product details as a response, the response of the microservice can be cached based on input parameters passed. This will help in reducing the business logic inside a microservice from being executed and will give a response from the cache.
- Use best practices for the technology behind microservice business logic: Design and build optimized code for technology stack chosen for business logic behind microservices.
- Use the right data source: Microservices response time depends on Data source response time. Moreover, there are Data like structured(eg. Product name, description) and unstructured data(eg. Images, videos), which need to be stored in different data sources. Structured data should be stored in RDBMS systems, whereas unstructured data should be stored in No SQL data store like Cassandra.
- Use Search Engines like Solr/Endeca: Search engines give optimized and fast responses to requests. Therefore, use search engines to index and query data like products, prices, etc.
- Throttling the services: Throttling or fixing the number of requests that hit a service at a certain point in time helps in the availability of service. There are load balancing applications that handle this use case well.
- Scaling: Scaling up and scaling out are two recommendations to handle the increased load on microservice. Scaling up refers to increasing the memory of a single node. Scaling out refers to increasing a new node to service the requests. The above approach in combination with load balancing handles loads well.
- Use Database clustering: Database clustering with load balancing allows the database to give a faster response to queries.
- Reduce background processes: Certain microservices are required to perform some background logic. This logic should be kept separate from microservice nodes and should be performed asynchronously.
To summarize, if the approach of designing keeping performance in mind, it would yield better performing and available microservices.