Netflix Case Study: Microservices and Streaming at Scale
7 years
Cloud migration
Hundreds
Monolith → services
TBD
Infra cost
Hundreds of independently deployable services on AWS for everything except the video itself, which streams from Netflix's own appliances inside ISP networks
This is a standalone teardown, based on Netflix’s public engineering writeup. This system was neither built nor consulted on by KarmaKoders.
Who: Netflix—a streaming service available in just about every country. Scale Netflix says it rebuilt from a monolithic application into hundreds of microservices, denormalized its data model onto NoSQL databases, and finished the job in early 2016 after seven years of effort—shutting down the last data center components used by streaming. It launched service in over 130 new countries at once on January 6, 2016, which was only possible because capacity could be added in minutes across AWS regions rather than racked by hand.
Constraint: Two workloads with opposite shapes co-occur in a product. The control plane is an enormous number of small, personalized, latency-sensitive requests—sign-in, search, recommendations, playback authorization, and billing. The data plane is massive, mostly the same bytes of video, the same episode being streamed to millions of homes. If you run both through the same infrastructure, you make each worse. Worse, the failure model is harsh: a stalled homepage is an annoyance, and a stalled stream is a canceled subscription. The public-facing version of the trigger from Netflix is blunt: a database corruption in 2008 stopped shipping for three days and made the case that it shouldn't be a data-center operations company.
Rendering diagram…
Before
A monolithic application running in Netflix’s own data centers, where one database problem could bring the business to a halt. The 2008 corruption incident halted shipping for 3 days. Vertical scaling: Growth meant adding more servers to a rack. The limit on expansion was how quickly the hardware could be installed. Single source of truth for all relational normalized data model Video delivered via third-party CDNs with all other content Coupled releases: one deploy pipeline, one blast radius, and cross-team coordination for each change.
After
Hundreds of independently deployable microservices on AWS, each owning a narrow capability, across multiple regions. Netflix’s own summary of the end state. Horizontal elasticity: thousands of instances, petabytes of storage added in minutes, which is what enabled launching simultaneously in 130 countries NoSQL stores (Cassandra) and in-memory tier (EVCache) denormalized Kafka pipelines feeding the data and personalization platforms "Video split onto Open Connect, Netflix’s own CDN, with appliances in ISP networks and at exchange points, filled in off-peak windows and serving all video traffic Platform engineering as a product: Zuul on the edge, Eureka for discovery, Titus for containers, Spinnaker for delivery, and deliberate failure injection in production
Decisions
| Option A | Option B | What Netflix chose | Why it fits | |
|---|---|---|---|---|
| How to move to cloud | Lift and shift the monolith into AWS | Rebuild cloud-native, service by service | Rebuild — Netflix says forklifting would have moved the data centre's problems along with it | The goal was elasticity and no single point of failure; a forklifted monolith delivers neither, and the seven-year cost bought an architecture that then scaled for a decade |
| Become a data-centre company? | Build world-class data-centre operations | Buy commodity infrastructure and spend engineering on streaming | Public cloud for the control plane | Racking servers was not the competitive advantage; encoding, personalisation and player quality were |
| Where video bytes come from | Third-party CDNs for everything | Build a purpose-built CDN and place it inside ISP networks | Open Connect, serving all video traffic | Video is huge, cacheable and mostly identical across users; moving it next to the viewer cuts transit and removes the biggest load from the general-purpose stack |
| Data model | Keep normalised relational schemas | Denormalise onto NoSQL per service | Denormalised NoSQL with a caching tier | Availability and partition tolerance beat strict consistency for browse and playback; each service owns its own store rather than sharing one schema |
| Handling failure | Prevent failure through testing and review | Assume failure and engineer degradation, then cause outages on purpose | Fallbacks, timeouts, load shedding, and chaos experiments in production | At hundreds of services, something is always broken; the question becomes what the member sees when it is |
| Client API shape | One shared REST API for every device | A per-client or federated graph layer | Moved from device-specific/Falcor approaches to GraphQL federation over domain graphs | Dozens of device types need different payload shapes; federation lets teams own their slice of the schema without a central API team becoming the bottleneck |
The through line is different; what has a different failure and cost profile unifies what teams need to reason about together. Video bytes and personalization requests are not intended to go down the same pipe. Services own their own data, so a schema change can't ripple through the company. And that edge is there for a reason, so when a downstream service is unhealthy, something still renders.
It’s worth being honest about what this costs. The microservices only worked because Netflix built and staffed a platform underneath them—service discovery, an edge gateway, container orchestration, continuous delivery, observability, and chaos tooling, much of it open-sourced. That’s the invoice most teams don’t see when they copy the architecture diagram. Netflix has also moved on from parts of it: Hystrix, the circuit breaker library that launched a thousand blog posts, says in its own README that it’s no longer in active development, and the Falcor-era client data-fetching approach gave way to GraphQL federation.
// The interesting part is not the circuit breaker. It is that the fallback is a
// product decision, written down in code, for every dependency on the home screen.
public class HomeRowsService {
private final PersonalizationClient personalization; // ranked, per-member
private final TrendingClient trending; // regional, cacheable
private final RowCache cache; // last good response per member
public HomeRows forMember(String memberId, String region) {
// 1. Try the personalized path with a hard deadline. Latency is a failure mode:
// a slow row is worse than a generic one, so the timeout is tight.
Supplier<HomeRows> primary = () ->
personalization.rankedRows(memberId, Duration.ofMillis(80));
// 2. Degrade, in a deliberate order, to something the member can still use.
return Resilience
.of(primary)
.withCircuitBreaker("personalization") // stop hammering a sick service
.withLoadShedding(Priority.INTERACTIVE) // shed before the tier collapses
.fallback(() -> cache.lastGood(memberId)) // slightly stale, still personal
.fallback(() -> trending.rowsFor(region)) // not personal, always warm
.fallback(HomeRows::staticEvergreen) // never an error screen
.execute();
}
}
// Two consequences worth stealing:
// - Chaos experiments become meaningful: kill personalization in production and assert
// that members still see rows, instead of asserting that an alert fired.
// - "Availability" gets defined per screen, not as one number for the whole system.
Being told to build it like Netflix?
We help founders and CTOs figure out what of this is worth copying at your stage — and what will cost you a year. Schedule a 30-minute architecture review.
Next step
Book a 15-min Architecture Review
Walk through your system with a lead architect and leave with a scoped recommendation.
Schedule on Cal.com