Sign in
TodayMapLearnPracticeReview
Library
13 MINadvancedArchitecture & InfrastructureNot started

Microservices

Microservices are an architectural style in which a system is built as a set of small, independently deployable services, each owning its own data store and communicating over a network (usually HTTP, gRPC, or async messages). The promise is independent team velocity; the cost is a dramatic increase in operational and integration complexity. Microservices are a trade-off, not a default — and they are usually the wrong choice for small teams and young products.

Why this matters

Microservices are the most consequential — and most over-applied — architectural pattern of the last 15 years. Done right, they let organizations scale engineering teams independently and isolate failures. Done wrong, they turn a single deployable bug into a distributed-system nightmare of latency, partial failures, and data consistency headaches. Understanding when microservices are worth the cost — and when a monolith is the better answer — is one of the highest-leverage architectural judgments you can make.

Prerequisites
  • Application Layer
  • Horizontal Scaling
Related
  • Service Discovery
  • Gateway Routing
Used in
  • Anti-Corruption Layer
  • Gateway Routing
  • Service Discovery
  • Service Mesh
  • Sidecar
  • Strangler Fig
Lesson

How it works

A monolith is one application: one codebase, one deployable, one database. It is easy to build, easy to test, and easy to reason about — until it isn't. As the codebase grows, builds slow down, tests take minutes, a change in shipping logic forces a full redeploy of the auth code, and 50 engineers trip over each other in the same repo.

Microservices split that application into smaller services, each owned by a team, each independently deployable, each with its own database. The shipping service deploys whenever the shipping team wants; the auth service is unaffected. Teams scale independently — if search traffic explodes, you scale search instances only, not the whole monolith.

The trade-off is brutal: every cross-service call is now a network request. Every transaction spanning services is now a distributed transaction. Every deploy is now a coordination problem. The complexity doesn't disappear — it shifts from inside the process to between processes.

What makes a service a microservice:

  1. Independent deployability — you can ship a new version of one service without redeploying any other. This is the defining property. If you must coordinate deploys across services, you have a distributed monolith.
  2. Bounded context — each service models one well-defined part of the business (orders, inventory, billing). The boundary follows the domain, not the technical layer.
  3. Owns its data — a service's database is not directly accessed by other services. Cross-service data access happens through the service's API, never by joining another service's tables. This is the hardest rule to follow and the most common one broken.
  4. Network communication — services talk to each other over a network (REST, gRPC, async messages). This is what makes them distributed systems, with all the failure modes that entails.

If a system claims to be microservices but every service shares one database, it is not microservices — it is a distributed monolith with extra network hops.

Trade-offs vs monolith:

DimensionMonolithMicroservices
Initial speedFast — one codebase, one deploySlow — must build infra first
Build/test timeSlows as codebase growsEach service stays small, fast
Team scalingOne team trips over itselfMany teams work in parallel
Deploy independenceFull redeploy for any changeShip one service at a time
Per-service scalingWhole app must scale togetherScale only the hot service
Tech stackOne language/frameworkEach service can differ
Failure isolationOne bug crashes everythingOne service down ≠ whole site down
LatencyIn-process calls (microseconds)Network calls (milliseconds)
Data consistencyACID transactionsDistributed transactions / sagas
Operational complexityLowHigh — observability, service mesh, discovery
DebuggingOne stack traceDistributed tracing across services
CostLower (less infra, fewer network hops)Higher (more services, more replicas, more ops)

The decision is rarely 'monolith vs microservices forever'. The common pattern is: start with a monolith, split out one or two services when a real pressure appears (team scaling, isolated scaling need, separate reliability SLA), and stop splitting as soon as the pressure stops.

When to use — and when NOT to use — microservices

USE microservices when: (1) your engineering org is large enough that teams genuinely trip over each other in one codebase, (2) subsystems have sharply different scaling or reliability requirements (search needs 1000 instances, billing needs 5), (3) you need to isolate failures (a buggy service must not take down the whole site), or (4) different subsystems are owned by different teams with different release cadences. DO NOT use microservices when: the team is small (under ~20 engineers), the product is still finding product-market fit, you don't have observability infrastructure (distributed tracing, centralized logs), or you cannot afford the operational overhead. Most early-stage companies should ship a monolith. Most large platforms (Netflix, Uber, Amazon) arrived at microservices only after their monolith became unmanageable.

The distributed-system tax:

Splitting a monolith into services replaces in-process function calls with network calls. The fallout:

  • Latency: an in-process call is microseconds; a network call is milliseconds — 1000x slower. Cross-service request chains add up. A 'simple' checkout that touched 4 in-process functions now pays 4× 5ms = 20ms extra.
  • Partial failures: in a monolith, either the call works or the process is dead. In microservices, the auth service is up but the catalog service is slow. Every caller must handle timeouts, retries, and degraded behavior (circuit breakers, fallbacks).
  • Data consistency: a monolith can wrap multi-step updates in one DB transaction. Microservices cannot — distributed transactions (2PC) are slow and brittle. Real systems use sagas, outbox patterns, and eventual consistency, all of which are harder to reason about than ACID.
  • Observability: a single user request now spans 5 services. You need distributed tracing (OpenTelemetry), centralized logs (with a correlation ID), and metrics broken down per service. Without these, debugging is impossible.
  • Operational load: 5 services means 5 deploy pipelines, 5 on-call rotations, 5 sets of dashboards. The SRE tax is real.

This tax is why microservices are usually the wrong default. Only pay it when the team-scaling or isolation benefit clearly outweighs.

Check yourself
interview

Your company has 8 engineers and just shipped its MVP. Leadership wants to 'go microservices' from day one to 'be ready for scale'. What is the most responsible recommendation?

Pick one answer.

Check yourself
solid

Five services all read and write to the same shared Postgres database. They each expose an HTTP API. Is this a microservices architecture?

Pick one answer.

Check yourself
interview

In a microservices system, what is the most common replacement for an ACID transaction that spans multiple services?

Pick one answer.

Engineering mental model

Mental model. Think of Microservices as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does Microservices mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”

Design lens

Before choosing Microservices, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.

Original NO CAP systems visual for Microservices.
Image unavailable. Original NO CAP systems visual for Microservices.
Microservices: a compact system-thinking visual.— Original NO CAP visual.
// Pseudocode
request = receive()
result = microservices(request)
return result

// Production questions:
// 1. What happens on timeout?
// 2. Can this operation be retried safely?
// 3. What is the bottleneck?
A minimal engineering sketch for reasoning about Microservices.

Back-of-the-envelope reasoning

Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.

Interactive sandboxdeterministic

Interactive thought experiment: Microservices

Change the variables below and predict what breaks first in Microservices. The production lab can later reuse these same inputs.

System pressure6%
Try this

Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.

Hint

If you are stuck on Microservices, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.

Check yourself
solid

You increase traffic by 10× in a system using Microservices. What should you inspect first?

Pick one answer.

Check yourself
interview

Which statement is the safest engineering habit when using Microservices?

Pick one answer.

Try this
interview

You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.

Production scenario: your system uses Microservices, traffic suddenly spikes, and p99 latency doubles. What is your first move?

Interview drill

Answer this without notes: When would you choose Microservices, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.

Engineering lens

A useful engineering lens for Microservices: define the problem it solves, the simpler design that fails first, the constraint that forces you to introduce this concept, and the new failure modes the concept creates.

Numerical sanity check

Back-of-the-envelope reasoning beats fake precision. State your traffic, payload, concurrency and growth assumptions explicitly, then calculate enough to know whether the current architecture is orders of magnitude away from the target.

Check yourself
interview

Do not optimize for a memorized definition. Reason from the workload and failure mode.

Imagine the simplest version of a system using Microservices. What breaks first as traffic grows by 10×, and what would you change before reaching 100×?

Pick one answer.

Trade-offs

What you gain, what you pay

Pros
  • +Independent deployability — ship one service without touching others.
  • +Team scaling — many teams work in parallel without contention.
  • +Per-service scaling — scale the hot service only, not the whole app.
  • +Failure isolation — a buggy service can be cordoned off without crashing the whole site.
  • +Tech-stack freedom — each service can use the right language for its job.
Cons
  • −Network calls replace in-process calls — 1000x latency increase per hop.
  • −Distributed-system failure modes: partial failures, timeouts, retries, circuit breakers.
  • −No more ACID transactions across services — sagas, eventual consistency, outbox pattern.
  • −Operational complexity: observability, service discovery, API gateway, service mesh.
  • −Higher cost: more services, more replicas, more infra. The per-request cost rises.
  • −Harder debugging — a single user request may span 5 services.
Failure modes

How this breaks in production

  • Distributed monolith — services share one database or must be deployed in lockstep, defeating the core benefit.
  • Chatty services — a single user request fans out to 10 service calls, multiplying latency and failure surface.
  • Cascade failures — one slow service causes callers to hold connections, exhausting their pools and bringing down the whole system (mitigate with circuit breakers and bulkheads).
  • Schema drift — services evolve incompatible API versions and silently break each other.
  • Lost observability — without distributed tracing, no one can explain why a request took 2 seconds across 6 services.
Common mistakes

Don't fall into these traps

  • •Adopting microservices before there is a team-scale or scaling problem to justify the cost.
  • •Sharing one database across 'microservices' — this is a distributed monolith, not microservices.
  • •Splitting along technical layers (a 'web service', a 'data service') instead of along business boundaries (orders, billing, shipping).
  • •Treating network calls as free — every cross-service hop is a failure surface and a latency cost.
  • •Skipping observability: no distributed tracing, no centralized logs, no per-service dashboards. Debugging becomes a forensic nightmare.
  • •Naive retries without backoff or circuit breakers — a downstream outage becomes a self-inflicted DDoS.
Where you see it

Real systems using this

Netflix, Uber, Amazon, Spotify — large orgs where teams number in the hundreds and need independence.E-commerce platforms where search, catalog, cart, checkout, and payments have different scaling and reliability needs.Financial systems where risk and accounting subsystems must be isolated from user-facing services.
Teardowns

How real systems implement this

  • Netflix — Netflix migrated from a monolith to hundreds of microservices over ~7 years. Each service owns its data and deploys independently. The migration was driven by team scale and the need to isolate failures — not by a single architectural decision.
  • Amazon (two-pizza teams) — Amazon's famous 'two-pizza team' structure pairs small teams with small service boundaries. Each team owns a service end-to-end, including its data store. The microservices pattern emerged from the org structure, not the other way around — Conway's Law in action.
  • Shopify — Shopify famously stayed on a modular monolith for years despite massive scale (Black Friday traffic), arguing that the operational simplicity of one deployable outweighed microservices' benefits until very specific pressures appeared. A reminder that even at scale, the monolith is often the right call.
Interview prompts

Practice saying it out loud

  • Q1When would you recommend a monolith over microservices? Defend the choice.
  • Q2Your team split a service into 5 microservices that all share one Postgres database. What's wrong, and how would you fix it?
  • Q3A user request now spans 6 services and takes 500ms when it used to take 50ms in the monolith. How do you diagnose and reduce latency?
  • Q4How do you maintain data consistency across microservices without distributed transactions?
  • Q5What infrastructure must exist before microservices are viable? (Service discovery, API gateway, distributed tracing, etc.)
Research

Further reading & references

System Design Primer
Open source
ByteByteGo — Scale from zero to millions
ByteByteGo
System Design Tutorial
GeeksforGeeks
System Design Roadmap
roadmap.sh
Architecture & Infrastructure reference
Reference
Architecture & Infrastructure reference
Reference
Architecture & Infrastructure reference
Reference

Core explanations are original NO CAP material. External references are provided for deeper study and standards.

What next?

Mark as understood once the mental model clicks.

Next recommended

Service Discovery