Doing microservices the right way
We hear about microservices, we inquire into them, we read posts and articles on the subject. They seem to be only about benefits and super easy. Well, they do have lots of benefits, but only if you do them well. I will try to explain some topics you should mind, based on our experience, to succeed with a microservices architecture.
- (Sidebar) Google Trends, search of Microservices Architecture over the last 7 years: https://trends.google.com/trends/explore?date=2014-01-01%202021-06-15&q=microservices%20architecture
What are microservices?
A simple definition could be:
It is an architectural approach where an application is designed as a collection of small bounded-concern, loosely coupled services that communicate with each other. It Is about decomposing a software system into autonomous modules which are independently deployable, and which communicate via a lightweight, language-agnostic way, and together they fulfill their business goal.
They say definitions are presented at the beginning but understood at the end. If you explore some of their challenges and how to approach them, the definition will quickly make more sense. But, if you want to read a more detailed definition, and characteristics, this is a great article from James Lewis and Martin Fowler: https://martinfowler.com/articles/microservices.html
Microservice Development Life Cycle
The first thing to mention is something that has an impact on your organization: the way your teams develop software with a microservices architecture. Building microservices means breaking the business problem into smaller, more manageable pieces. Divide and conquer. This is due to the empirical evidence that larger teams produce results with less efficiency than smaller ones. There is a diminishing returns curve associated with the size of a team. As the team grows, there is geometrically more overhead in coordination, communication, revision; it is more difficult to lead and motivate. So, each microservice should be developed, and maintained by a single, small team, between 2 to 8 developers max. That is, each microservice should be something small and divided from a business point of view, not by technological characteristics, and that is what we mean by “bounded context”: each microservice should be concerned with a single, narrow mission within the whole business problem that the application solves.
But how small is small? Well, it depends, as usual: here is an article to help you decide about microservice size during design, https://medium.com/@ggonchar/deciding-on-size-of-microservices-dbb2a8d8f7e5
Where should I put my attention when dealing with Microservices?
Now it is time to talk about areas you should pay attention to when using microservices to build business applications:
- Dependencies: In a microservice architecture, services are modeled as isolated units that manage a reduced set of problems. This approach of dedicated business concern is also called “domain-driven” or, we say that microservices have a “bounded context”; they are limited as to what each handle. However, fully functional systems rely on the cooperation of their parts, and microservices are not an exception. So, although domain-specific, microservices are independent of each other, they still expose and consume data between each other, in specific formats and structures. This means that any change in communication features of a microservice needs to happen sometimes in consideration of other microservices using such features. Clever design is most critical to minimize dependencies between microservices and, careful change strategies need to exist not to disrupt the system and to maintain the autonomy principle of microservices; that we can deploy them independently of each other. In general, communication, and orchestration of microservices need their own dedicated strategies to control this dependencies problem. To this effect, we usually involve lightweight mechanisms, such as REST APIs, or JSON message streams, with the publish-subscribe pattern, and we apply them in several ways to make microservices less coupled between each other.
In this article, this topic is explained in detail:
- Consistency: Once we realize the dependency problem of “almost independent” microservices, we quickly discover another inconvenience of the “bounded context” approach. That some microservices replicate aggregated data from other microservices. How do we make sure that for example, if a Service Charge microservice gets a new service charge transaction data, the Service Accounts microservice that reflects the total balance for the account updates as quickly as possible and is consistent with the charges, most of the time? This is especially tricky for distributed transactions, and for aggregated data spread out among many microservices. There are special design patterns, like message streams, and sagas, that you will need to consider for your system to work as intended.
- Performance: You might think that you can simply use the same techniques you have always used to address speed and reliability problems. Yes, some of these techniques do work with microservices, but after creating the microservice, there are some special twists to consider when working with it as well.
With microservices you decompose or decouple your business concern into smaller pieces, so each microservice grows autonomously and performs the best for the business, and it is less resource-intensive. But the performance of an entire system is as good as its weakest element. So, it is critical to monitor the performance of each microservice while under various environments, loads, and business scenarios. To achieve this goal, you better rely on cloud-native components that handle this problem, like Prometheus for performance monitoring, Redis for cache, Fluentd for logging, and Open Tracing and Jaeger for tracing transactions across microservices. Are you particularly interested in performance management of microservice architecture?
Look at this link: https://jaxenter.com/microservices-performance-problems-172291.html
- Scalability: Because microservices were born in the cloud, where resources are virtualized and elastic, they can scale on demand. Applications built on microservices can be scaled in multiple ways. We can scale them out horizontally to add more instances of it, or we can scale them up vertically to add more resources to the current instances. These scalability considerations should be part of your scalability plan and included in your deploy image configuration scripts. The best way to scale your microservices depends on careful design and architecture criteria, and on how your microservice works on its own and interacting with others. Load balancing layers and API gateways help to this effect. Here is more about this topic: https://thenewstack.io/scaling-microservices-on-kubernetes/ and https://www.oreilly.com/library/view/production-ready-microservices/9781491965962/ch04.html
- Security: Finally, these are the best practices for securing microservices we need to consider in a microservices architecture. In general, it is best to rely on cloud-native open technologies to handle the basic aspects of security. Although we are dealing with a distributed architecture, or because of it, we should centralize the responsibility of user authentication (determining that you are who you say you are) and authorizations (managing what you should be able to do and not to do given your role and authority in the system), using standard protocols like OpenID Connect, Multi-Factor authentication, and Role-based Access authorizations to microservice functions and data.
At a minimum, we should standardize a security schema across microservices and require that all operations, API calls, access, transactions, and transport happen in the context of an authentication token that is centrally managed. Security is a topic on its own but here goes a list of common basic best practices to secure microservices, from https://geekflare.com/securing-microservices/ :
- Always build security from the start
- Use Defense in Depth Mechanism
- Deploy security at container level
- Deploy a Multi-Factor authentication
- Use User Identity and Access tokens
- Create an API Gateway
- Profile APIs based on the deployment zone
- Secure the service-to-service communications
- Rate limit client traffic
- Use orchestration managers
- Monitor all your systems and services
- Automate security activities
- Protect data at all times
- Choosing Technology: One of the advantages of microservices architecture is that each microservice can be developed and deployed in a different, most adequate technology for its purpose and business context. This is great flexibility because, as your application evolves, you could also change how one microservice is built, without affecting the rest. On the other hand, it may require that we employ teams with specialized knowledge for some microservices as well. Here are some pros and cons about technologies to use in microservices: https://www.clariontech.com/blog/5-best-technologies-to-build-microservices-architecture