Monolith vs Microservices
The whole app as one deployable unit (monolith), or small independent services that talk over the network (microservices); a modular monolith sits in between.
30.1 Why is it used?
- When a team grows from 5 to 500 engineers, everyone blocks each other in one codebase; with microservices each team deploys independently.
- On sale day only search and checkout are loaded; with microservices you scale only those, not the whole app.
- But microservices bring new problems such as network latency, distributed debugging and data consistency.
- Choosing the right architecture depends on the company stage; a wrong choice costs both speed and money.
30.2 How it works
- Monolith: one codebase, one deployment, one database; simple, function calls are fast, transactions are easy.
- Modular monolith: one deployment but strict modules inside (orders, payments, users) with clear interfaces; easy to extract a service later.
- Microservices: each service owns its business domain + its own database and talks via REST/gRPC/events.
- Database per service: do not query another service's DB directly; get data through an API or events. Use the Saga pattern for consistency.
- API Gateway: a single entry point for clients; routing, auth, rate limiting.
- Service mesh (Istio, Linkerd): a sidecar proxy (Envoy / linkerd2-proxy) beside every pod; mTLS, retries, timeouts, traffic split, telemetry, with no app code change.
- Strangler fig pattern: pull features out of the monolith one by one into new services, and the gateway shifts traffic gradually.
- Observability is essential: distributed tracing (OpenTelemetry, Jaeger), centralized logs, metrics per service.
- 1.A Monolith: all modules (users, orders, payments, search) in one app, 1 deploy, one shared DB; fast calls, easy transactions
- 2.B Modular monolith: 1 deploy, strict modules + interfaces, 1 DB with a schema per module; easy to extract a service later
- 3.C Microservices: users, orders, payments, search behind an API Gateway; each service has its own DB, talks via REST / gRPC / events, deploys + scales independently
- 4.D Strangler fig: the API Gateway sends '/search' to the new Search service, other routes stay on the Django monolith; Saga order flow: order create -> payment -> inventory (on failure: payment refund + order cancel)
- 5.Once services pass 25+, a Linkerd mesh: a sidecar proxy with every pod; mTLS, retries, timeouts, traffic split, telemetry; tracing with OpenTelemetry / Jaeger
With the strangler fig you pull features out one at a time; a Saga is not a distributed transaction, it is compensating actions
30.3 Tools
| Tool | Type | How it is used |
|---|---|---|
| Kubernetes | Container orchestration | Deploys, scales and self-heals microservices; each service is a Deployment + Service. |
| Istio | Service mesh | mTLS, canary traffic split, retries and circuit breaking via Envoy sidecars (or ambient mode); feature rich but heavy. |
| Linkerd | Service mesh (CNCF) | A light, Rust-based proxy; automatic mTLS and golden metrics; simple setup. |
| Spring Boot / Spring Modulith | Java framework | Spring Boot for microservices; Spring Modulith enforces the boundaries of a modular monolith. |
| Kong / AWS API Gateway | API Gateway | Single entry in front of microservices, auth, rate limit, routing. |
| OpenTelemetry + Jaeger | Distributed tracing | A trace shows which services a request passed through and where it was slow. |
30.4 Comparison: Monolith vs Modular Monolith vs Microservices
| Point | Monolith | Modular Monolith | Microservices |
|---|---|---|---|
| Deployment | One unit, everything deployed together | One unit, but clear modules inside | Each service deployed separately |
| Scaling | The whole app must be scaled | Whole app, but easy to split later | Each service by its own load |
| Data | One shared DB, ACID transactions are easy | One DB, schema per module | DB per service, eventual consistency, Saga |
| Performance | In-process calls, fastest | In-process calls, fast | Network calls, latency + failure handling |
| Team size fit | Small team (1-15) | Medium team, growing startup | Many independent teams |
| Ops complexity | Low | Low-medium | High: K8s, mesh, tracing, CI/CD per service |
| Failure | One bug can bring down the whole app | Same process, but clear boundaries | Isolated, but risk of cascading failure |
| Best for | MVP, early startup | The sweet spot for most companies | Amazon/Netflix/Uber scale orgs |
30.5 When to choose which
- Monolith: a new product, a small team, requirements still changing.
- Modular monolith: the team is growing, but you do not yet want the ops burden of microservices.
- Microservices: separate teams, different scaling needs, independent release cycles are required.
- Service mesh (Linkerd simple, Istio feature rich): when you have 20+ services and need mTLS, retries and traffic control everywhere.
30.6 Real-world example
Real world: the microservices journey of Netflix and Amazon, then an Indian startup scenario
- In 2008, after a major database corruption, Netflix moved from a monolith in its own data center to the AWS cloud and microservices (publicly documented).
- The migration took several years and by roughly 2016 streaming was fully on AWS; today it runs hundreds of microservices.
- In the early 2000s Amazon broke up its monolith and adopted 'two-pizza teams' and a service-oriented architecture; each team owns its service.
- Scenario: an Indian startup begins with a Django monolith and has 80 engineers 3 years later.
- First they split the code into modules (modular monolith), then use the strangler fig to make the most loaded part, 'search', a separate service.
- Payments becomes a separate service with its own DB; the order flow uses a Saga: order create -> payment -> inventory, with compensating actions on failure.
- Once services pass 25, they add Linkerd so mTLS and retries come in every service without code changes.
30.7 Interview tips
- Distributed monolith: services are separate but share a DB and use a synchronous chain; you get the downsides of both and no benefit.
- 30 microservices from day 1: a small team drowns in ops.
- Drawing service boundaries on technical layers (UI service, DB service) instead of business domains (orders, payments).
- Interview tip: speak in trade-offs: 'microservices solve organizational scaling, but bring operational complexity'.