In this article, senior architect Matt Bishop reviews the benefits and difficulties with a microservice architecture. While avoiding the "anti-patterns" and horror stories that are prevalent while sticking to the architecture qualities themselves.
Quick recap on considering microservices
In the first installment of the microservices series it laid out the definition of microservices from their qualities – loosely coupled, service-oriented and bounded contexts. These qualities enable a lot of things, but they also suffer some challenges.
A well-built microservices system delivers fundamental implementation independence. The services in the system are largely independent of each other and free to develop at their own pace. The system release changes often, without much coordination between the components. Over time the system acts more like an ecosystem where the whole business is supported by the coordination and ever-improving capabilities found therein.
An ecosystem like this has some observable characteristics:
- Small Teams: Amazon calls these "2-pizza" teams, where the entire team could be fed dinner on two pizzas. This small size reduces the need for process and management as they communicate with each other and share the goals and work internally. The team knows their bounded context and the shared identifiers they must work with. They understand their service's orientation in the system.
- Self-Contained Technology Choices: Developers find this aspect of microservices the most appealing because they have the freedom to make the "right" choice for a service given its requirements. The language, the database, the libraries, and other implementation technologies are owned by the team. They do not have to share these with other components because they are loosely coupled.
- Independently Scalable: Each service must manage their own quality-of-service requirements and is free to find the most suitable way to do so. For some services, horizontal scaling is the best answer. For others, it might be caching, especially if they proxy from an external system. Similarly, microservices that coordinate with other services can mitigate problematic QoS with patterns like circuit breaker to keep their own QoS intact. The system can deal with service outages without bringing down the entire business.
- Replaceable: Every business system must respond to change, and with a microservices architecture, one response is replacement. Perhaps the bounded context was incorrectly-defined and a service needs to be split into multiple services. It might be that the external service being proxied has been changed and it is faster to replace the service with a new one, rather than versioning the code itself. In some cases, the service codebase cannot be reliably recovered and redeployed due to staff changes or technology failures. A single microservice is small enough that completely replacing it with another is an inexpensive and fast option.
Every architectural style has its challenges, and microservices are no different. These challenges are hard to mitigate and may spell doom for the ecosystem.
- Governance: While the teams are small and independent, the requirements for each service must be governed effectively. Someone has to decide the shape of the bounded contexts, the shared identifiers and QoS for each service. The overall architecture must fulfil the business mission successfully.
- Consumption: The various services are consumed in a variety of ways, from web sites and mobile apps to external systems. How do these consumers discover the relevant services that vend a needed capability? How do they coordinate the services when multiple services are required to complete a user journey? Often a consumer team will have to build their own microservices to accomplish their goals. These patterns, like backend-for-frontend, add more complexity and coupling between components.
- Cross-Cutting Concerns: Many aspects of a system go through many, even all, parts of the microservices. A cross-cutting concern is driven by business requirements and must be satisfied by all the relevant microservices. Most concerns are solved with centralized monitoring and logging capabilities that every service must participate in. Performance analysis, state change traceability, user authorization, data security, GDPR, security, licensing and many other concerns flow through the ecosystem and must be reliably addressed by all the microservices.
- Cost: A well-designed microservice that scales well, maintains its own data persistence and participates in cross-cutting observability systems may, in itself, be inexpensive. Infrastructure technology like virtualization, containerization, serverless functions and on-demand data storage have made microservices possible yet are often more expensive than realized at the outset. Companies are often surprised by how extensive (and expensive) their AWS and Azure invoices are. A single microservice can cost several hundred dollars per month in service fees just to idle. Multiplying this out to all the microservices in an ecosystem, including the multiple regions required to run a global service, and the bill can be staggering, even ruinous. A business will be sorely tempted to combine the expensive parts like databases to reduce costs. Naturally the now-shared infrastructure violates the microservice independence qualities.
A large-scale microservice ecosystem is truly a challenge for any business to undertake. One must have significant talent and resources to take this path and follow it properly, without shortcuts or deviations. Although this article did not address the anti-patterns, they do exist and they lead to system failure.
Check out Matt’s last installment of the microservices series where he puts it all together for addressing challenges while reaping the benefits of microservices.