Microservices Foundations
Before writing code, we must understand why we are building microservices.1. Monolith vs Microservices
The Monolith
A single deployment unit containing all business logic, UI, and data access. Pros:- Simple to develop, test, and deploy (initially).
- No network latency between calls.
- Easy to debug (single stack trace).
- Scaling: Can only scale the whole app (X-axis scaling), not specific bottlenecks.
- Technology Lock-in: Hard to switch languages/frameworks.
- Complexity: Over time, “Big Ball of Mud” anti-pattern emerges.
- Reliability: If one module causes an OOM error, the whole system crashes.
Microservices
Architectural style where an application is a collection of loosely coupled services. Pros:- Technological Freedom: Each service can use the best tool for the job.
- Independent Deployment: Deploy
User Servicewithout redeployingOrder Service. - Fault Isolation: If
Payment Servicefails, users can still browse products. - Scaling: Scale only the popular services independently.
- Distributed Complexity: Network failures, latency, consistency issues (CAP Theorem).
- Operational Overhead: Need sophisticated monitoring, logging, and deployment pipelines.
2. Domain Driven Design (DDD) Basics
DDD is crucial for identifying service boundaries. A microservice should correspond to a Bounded Context.- Ubiquitous Language: Common language shared by developers and domain experts.
- Bounded Context: A boundary within which a particular domain model is defined and applicable.
- Example: “User” in the Sales Context might refer to a customer with credit limits. “User” in the Support Context might refer to a ticket opener. These should be different Microservices.
3. Communication Patterns
Services need to talk to each other.Synchronous (Request/Response)
The client waits for a response.- HTTP/REST: Standard, easy to debug over JSON.
- gRPC: High performance, strictly typed (Protobuf).
Asynchronous (Event-Driven)
The client sends a message and forgets.- Message Queues: RabbitMQ, ActiveMQ.
- Event Streaming: Apache Kafka.
4. The 12-Factor App
A methodology for building cloud-native apps:- Codebase: One codebase tracked in revision control, many deploys.
- Dependencies: Explicitly declare and isolate dependencies.
- Config: Store config in the environment.
- Backing services: Treat backing services as attached resources.
- Build, release, run: Strictly separate build and run stages.
- Processes: Execute the app as one or more stateless processes.
- Port binding: Export services via port binding.
- Concurrency: Scale out via the process model.
- Disposability: Maximize robustness with fast startup and graceful shutdown.
- Dev/prod parity: Keep development, staging, and production as similar as possible.
- Logs: Treat logs as event streams.
- Admin processes: Run admin/management tasks as one-off processes.
5. CAP Theorem (The Trade-offs)
In any distributed data store, you can only provide two of the following three guarantees:- Consistency (C): Every read receives the most recent write or an error.
- Availability (A): Every request receives a (non-error) response, without the guarantee that it contains the most recent write.
- Partition Tolerance (P): The system continues to operate despite an arbitrary number of messages being dropped/delayed by the network.
- CP (Banking): If the network breaks, stop accepting updates until it’s fixed. Don’t show wrong balance.
- AP (Social Media): If the network breaks, show the old feed. It’s better than showing an error.