15 essential system design patterns with diagrams, trade-offs, and real-world examples.
Distributes incoming traffic across multiple servers to ensure no single server is overwhelmed. Essential for horizontal scaling.
Single entry point for all client requests. Handles cross-cutting concerns like auth, rate limiting, routing, and response aggregation.
Command Query Responsibility Segregation: separate the read (query) model from the write (command) model. Each side can be independently optimized and scaled.
Store all changes as a sequence of events instead of just current state. State is derived by replaying events. Provides complete audit trail.
Manage distributed transactions across multiple services using a sequence of local transactions with compensating actions for rollback.
Prevents cascading failures by stopping calls to a failing service. Like an electrical circuit breaker - trips when too many failures detected.
Publishers send messages to topics without knowing subscribers. Subscribers receive messages from topics they're interested in. Fully decoupled communication.
Application checks cache first. On miss, reads from database, then populates cache. Most common caching pattern for web applications.
Maps both data keys and servers to positions on a hash ring. Minimizes key redistribution when servers are added/removed.
Splitting a database across multiple machines. Each shard holds a subset of the data. Enables horizontal scaling beyond a single machine.
Restricting the number of requests a client can make within a time window. Protects services from abuse and ensures fair usage.
Choosing a single node as the coordinator/leader in a distributed system. The leader handles writes or coordinates tasks. If the leader fails, a new one is elected.
When a consumer can't keep up with producer speed, it signals the producer to slow down. Prevents buffer overflow and cascading failures.
Deploy a helper process alongside the main service (in the same pod/VM). Handles cross-cutting concerns without modifying the service code.
Incrementally replace a legacy system by routing requests to the new system piece by piece. Avoids risky big-bang rewrites.