Courses › System Design › Patterns
Scaling Writes
Sharding, batching, queues as buffers, and write-optimized storage.
Writes are harder to scale than reads: you can't cache them away, and every write must land durably somewhere. When write volume outgrows a single database, these are the standard techniques.
1. Choose a write-friendly store
Before anything else, make sure the database fits the workload.
- B-tree databases (Postgres, MySQL) update pages in place; they handle a lot, but random writes and many indexes add up.
- LSM-tree databases (Cassandra, ScyllaDB, RocksDB-based stores) turn writes into sequential appends and handle far higher write volumes.
- Time-series databases are specialized for append-only metrics.
Also: drop unneeded indexes — every index multiplies the cost of a write.
2. Partition (shard) the writes
Spread writes across many machines by a partition key (see Sharding). The key must distribute writes evenly — a time-based key sends every new write to the same partition.
3. Buffer with a queue
Put a durable queue (Kafka, SQS) between producers and the database:
Client -> [API] -> {Kafka} -> [Writer Workers] -> (Database)- Absorbs bursts — the API accepts writes at peak rate while workers write at a steady rate.
- Isolates the database from traffic spikes.
- Trade-off: writes become asynchronous. Make sure the product tolerates a short delay before data is visible, and that consumers are idempotent.
4. Batch
Writing 1,000 rows in one batch is far cheaper than 1,000 single-row writes. Batch in the client, in the writer workers, or with periodic flushes.
5. Pre-aggregate
Often you don't need every raw event in the hot database:
- Counters — instead of inserting a row per "like", increment an in-memory or Redis counter and flush periodically.
- Stream aggregation — a stream processor (Flink) turns 100k click events/second into per-minute aggregates; store raw events cheaply in object storage for audit and reprocessing.
6. Handle hot keys
A single viral post's like counter can receive more writes than one node can handle.
- Split the key: write to
likes:post:9:{0..15}at random and sum on read. - Buffer and coalesce: accumulate increments in memory for a second and write one update.
[!INTERVIEW] Connect it to the requirements "Clicks arrive at 100k/second at peak, which a single Postgres primary can't absorb. I'll write click events to Kafka partitioned by ad ID, have Flink aggregate per-minute counts, and write those aggregates to the database — about 1,000 writes per second. Raw clicks go to S3 for reconciliation."