Towards Microservices Architecture
It’s 2017, no one uses SOA/ESB/Monoliths anymore. You should try Microservices!
Microservices is a trending topic among software engineers today. Let’s understand how you can start building truly modular systems with Microservices architecture.
Microservices architecture consists of collections of light-weight, loosely-coupled services. Each service implements a single business capability. Ideally, these services should be cohesive enough to develop, test, relese, deploy, scale, integrate, and maintain independently.
Defining Characteristics of Microservices
- Each service is a light-weight, independent, and loosely-couple business unit.
- Each service has its own codebase, managed and developed by a small team (mostly in an agile environment).
- Each service is responsible for a single part of the functionality (business capability), and does it well.
- Each service can pick the best technology stack for its use cases (no need to stick into one framework throughout the entire application).
- Each service has its own DevOp plan (test, release, deploy, scale, integrate, and maintain independently).
- Each service is deployed in a self-contained environment.
- Services communicate with each other by using well-defined APIs (smart endpoints) and simple protocols like REST over HTTP (dumb pipes).
- Each service is responsible for persisting its own data and keeping external state (Only if multiple services consume the same data, such situations are handled in a common data layer).
Benefits of Microservices
Microservice are made to scale large systems. They are great enables for continuous integration and delivery too.
- Independent scaling — Microservices architecture supports Scale Cube concept described in the excellent book The Art of Scalability. When developing microservices to achieve functional decomposition, the application automatically scales via Y axis. When the consumption is high, microservices can scale via X axis by cloning with more CPU and memory. For distributing data across multiple machines, large databases can be separated (sharding) into smaller, faster, more easily managed parts enabling Z axis scaling.
- Independent releases and deployments — Bug fixes and feature releases are more manageable and less risky, with microservices. You can update a service without redeploying the entire application, and roll back or roll forward an update if something goes wrong.
- Independent development — Each service has its own codebase, which is developed, tested, and deployed by a small focused team. Developers can focus on one service and relatively-small scope only. This results in enhanced productivity, project velocity, continuous innovation, and quality at source.
- Graceful degradation — If a service goes down, its impact won’t propagate to the rest of application and result in a catastrophic failure of the system, allowing a certain degree of anti-fragility to manifest.
- Decentralized governance — Developers are free to pick the technology stacks and make design standards and implementation decisions that are best suited for their service. Teams do not have to get penalized due to past technology decisions.
Independent services alone cannot form a system. For the true success of microservices architecture, significant investments are required to handle cross-system concerns like:
- Service replication — a mechanism by which services can easily scale based upon metadata
- Service registration and discovery — a mechanism to enables service lookup and finds the endpoint for each service
- Service monitoring and logging — a mechanism to aggregate logs from different microservices and provide a consistent reporting
- Resiliency — a mechanism for services to automatically take corrective actions during failures
- DevOps — a mechanism for handling continuous integration and deployment (CI and CD)
- API gateway — a mechanism for for providing an entry point for clients
Microservices in Practice
When to use Microservices
Microservices architecture best fits for:
- Applications with high scalability needs
- Projects with high release velocity
- Business cases with rich domains or many subdomains
- Agile environments with small development teams developing large products collaboratively
- Model services around the business domain.
- Avoid shared databases — To avoid tight coupling with the data layer, each service should have its own data storage. The development team is free to pick the data persistence method which best fit to each service and nature of data.
- Smart endpoints and dumb pipes — Each service owns a well-defined API for external communication. Avoid leaking implementation details. For communication, always use simple protocols such as REST over HTTP.
- Avoid coupling between services — Causes of coupling include shared database schemas and rigid communication protocols.
- Decentralize development — Avoid sharing codebases, data schemas, or development team members among multiple services/projects. Let developers focus on innovation and quality at source.
- Let the gateway handle routing and cross-cutting concerns (authentication, SSL termination). But keep domain knowledge out of the gateway.
- Services should have loose coupling and high functional cohesion.
- Authentication — Instead of implementing security components at each microservices level which is talking to a centralized/shared user repository and retrieve the authentication information, consider implementing authentication at API Gateway level with widely-used API security standards such as OAuth2 and OpenID Connect.
- Popular microservices frameworks to evaluate: Vert.x, SpringBoot, Akka, DropWizard, Go