Designing Data-Intensive Applications, session 1

Reliable.Scalable.Maintainable.

Three questions to answer before you pick any database, cache, or queue.

→ next · ← back · N notes · F full screen

The bottleneck isn’t the CPU anymore.

It’s the amount of data, its complexity, and how fast it changes.

Databasestore, find later
Cacheremember expensive work
Search indexkeyword & filter
Streamasync messages
Batchcrunch big piles

Glue code makes you a data system designer.

Put a cache and a search index next to your database, and keeping them in sync is now your job.

Redis: store or queue?Kafka: queue or log-database?
Client Application code Cache Primary DB Search index Change queue Workers

Three words we use daily and rarely define.

Reliability

Keeps working correctly, even when things go wrong.

Scalability

Has reasonable ways to cope as load grows.

Maintainability

Many people, over years, can work on it productively.

01

Reliability

Continuing to work correctly, even when things go wrong.

A fault is not a failure.

Fault: one component breaks its spec.
Failure: users stop getting service.

Faults will happen. The job is to stop them becoming failures.

With fault tolerance ✕ Users fine ✓ Without ✕ Outage

Where faults come from

~1/day
Hardware. Disk failures in a 10,000-disk cluster. Random, mostly independent.
1 second
Software. The 2012 leap second hung many services at once. Bugs are correlated across nodes.
#1
Humans. Operator config errors led outages in one study; hardware played a role in only 10–25%.

Break things on purpose.

Many critical bugs hide in error handling. Netflix’s Chaos Monkey randomly kills processes so the recovery path is always tested.

Designing for unreliable humans

APIs that make the right thing easy Sandboxes with real data Tests at every level Fast rollback Gradual rollouts Tools to recompute data Detailed telemetry

Lab: at scale, failure is routine

Failures per day
One failure every
0
Simulated days (1 s = 1 day)
0
Disks lost so far
02

Scalability

Not a label. A question about growth.

“Our system is scalable.”

“If load grows like this, what are our options?”

First describe today’s load with a few load parameters:

requests / secread : write ratioconcurrent userscache hit ratea few extreme cases

Twitter, 2012: the problem was fan-out.

4.6k
tweets / sec
300k
timeline reads / sec
30M
followers of one celebrity

Work at read time, or at write time?

1. Join when reading

One global tweets table. Each timeline read runs:

SELECT tweets.*, users.* FROM tweets
JOIN users   ON tweets.sender_id = users.id
JOIN follows ON follows.followee_id = users.id
WHERE follows.follower_id = :me

Couldn’t keep up with 300k reads/sec.

2. Fan out when writing

A cached “mailbox” per user. Each tweet is pushed into every follower’s timeline.

Reads become cheap, and reads outnumber posts ~100×.

But 4.6k tweets × 75 followers = 345k writes/sec, and one celebrity tweet = 30M writes.

Final answer: a hybrid. Fan out for most users; merge celebrities in at read time.

Lab: fan-out calculator

Cache writes/sec with fan-out on write
Timeline reads per tweet posted
Writes/sec to deliver one celebrity tweet in 5 s

Response time is a distribution, not a number.

network waiting in queue service time network Response time: what the client sees Latency: waiting to be handled
GC pausecontext switchlost packet + TCP retransmitpage faultrack vibration (really)

Lab: why the mean misleads

Mean
Median (p50)
p95
p99

The tail is your best customers.

p99.9
Amazon’s target for internal services. The slowest requests often belong to customers with the most data.
100 ms
of extra response time cost Amazon about 1% in sales.
p50 < 200ms
plus p99 < 1 s: what an SLA might define as “up”.

Measure on the client side: a few slow requests block the fast ones behind them.

Lab: one slow call ruins the request

of user requests end up slow. Formula: 1 − (1 − p)n

Never average percentiles.

To combine servers or time windows, add the histograms, then read the percentile.

HdrHistogramt-digestforward decayMicrometer percentile histograms

No magic scaling sauce.

Scale up Scale out

Real systems mix both. Stateless services spread easily; a stateful database doesn’t.

100k × 1 kB / s
vs
3 × 2 GB / min

Same throughput. Completely different systems.

03

Maintainability

Most of the cost of software comes after launch.

Operability

Make it easy for ops to keep it healthy.

Monitoring, automation, no single-machine dependency, predictable behaviour, good defaults you can override.

Simplicity

Make it easy for a new engineer to understand.

Remove accidental complexity: the kind that comes from the implementation, not the problem.

Evolvability

Make change easy when requirements shift.

Agility, but at the level of the whole data system, not just the code.

Best weapon against complexity: good abstractions. SQL hides disk layouts, concurrency, and crash recovery.

Now, our system.

Reliability

A settlement run crashes halfway: fault or failure? Can we recompute safely? Do we detect amount mismatches automatically?

Scalability

What’s our key load parameter? Transactions per settlement window, read/write ratio, or skew across merchants (our “celebrities”)?

Performance

Do we track response times and batch durations as percentiles or averages? How much of our p99 is GC?

Maintainability

Where is our accidental complexity? How long would a new engineer need to trace one settlement into PostgreSQL?

Next session

Data models & query languages

Relational or document? The object-relational mismatch we meet daily with JPA, declarative queries, and graphs.