How fan-out-on-write works (high level)
- A user creates a post. The post is written to the canonical posts table/stream.
- The publish event is appended to a durable message stream or queue (Kafka, Pulsar, Kinesis, Redis Streams, etc.).
- A fan-out worker consumes the stream and computes the follower set for the author.
- The worker writes a per-follower feed entry (often a small summary or pointer to the canonical post) into each follower’s personal feed store.
- Followers read their personal feed directly; reads are fast because feeds were pre-populated.
Example worker (pseudocode)
The following Python-like pseudocode demonstrates a fan-out worker loop. It emphasizes batching, idempotency, and retry behavior.- Use
entry_idas an idempotency key so retries do not produce duplicates. - Keep per-follower entries small (summary or pointer) to limit write amplification and storage costs.
- Batch follower writes to reduce RPC overhead and increase throughput.
- Persist a durable marker (or offset) of processed events so the consumer can resume safely.
- For very large follower lists, shard the fan-out work across multiple workers by author, by post, or by follower ranges.
Storage options for per-follower feeds
Choose the per-follower feed store based on your read-latency requirements, write throughput, storage cost, and operational familiarity.Important operational considerations
- Write amplification: one post may be written once per follower. Expect higher IOPS and storage usage.
- Hot authors: accounts with millions of followers create hot shards and cause large write spikes.
- Ordering: preserve timestamps; use monotonic counters or server-side timestamps if strict ordering is required.
- Consistency: fan-out is typically eventually consistent — followers may see a brief delay while writes propagate.
- Idempotency: use stable entry keys to make retries safe.
- Backpressure: handle spikes using batching, sharding, worker autoscaling, and circuit breakers.
- TTL and compaction: enforce retention (TTL) or compaction to bound per-user storage.
- Privacy and deletes: define a strategy for deletes and privacy changes (cascade deletes, tombstones, or access checks at read time).
- Monitoring: track consumer lag, queue depth, fan-out latency, write error rates, and per-shard throughput.
Accounts with extremely large follower counts (celebrities) are a major operational risk: they can cause sustained high write volumes and create hot partitions. Plan special handling (hybrid fan-out, rate-limiting, separate shards, or read-time fetch for followers) to protect the rest of the system.
Scaling patterns and hybrids
- Fan-out on write (proactive): precompute and store each follower’s feed. Best: read latency. Trade-off: highest write cost and storage duplication.
- Fan-out on read (lazy): store canonical posts and follower lists; assemble feed at read time. Best: reduced write amplification. Trade-off: higher read latency and more CPU at read time.
- Hybrid approaches:
- Fan-out to active followers (heavy readers) and fan-in on read for inactive followers.
- Treat super-followed authors specially: store their posts in a shared high-throughput timeline that is merged at read time.
- Use tiered storage: keep recent items in Redis for low latency; older items in cold storage (wide-column DB).
Summary
Fan-out-on-write pre-populates followers’ feeds at write time to deliver instant reads. It is ideal when read latency is the priority and extra write/storage cost is acceptable. To operate this pattern at scale, pay attention to batching, idempotency, hot-key handling, retention policies, and observability.Fan-out-on-write delivers excellent read performance but increases write amplification and storage. Use hybrid strategies and special-case hot authors to balance cost and latency.
Links and references
- Kafka: https://kafka.apache.org/
- Pulsar: https://pulsar.apache.org/
- AWS Kinesis: https://aws.amazon.com/kinesis/
- Redis Streams: https://redis.io/topics/streams-intro
- Cassandra Data Modeling: https://cassandra.apache.org/doc/latest/
- DynamoDB Best Practices: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html
Example checklist before production rollout
- Implement idempotent writes (
entry_idper follower). - Add batching and worker sharding.
- Define TTL/retention policy and compaction strategy.
- Add monitoring for consumer lag, write failures, and hot keys.
- Design special handling for high-follower-count accounts.
- Test recovery and resume semantics for the consumer stream (offset management).