Back to Blog
System DesignHard

System Design Basics: Building Scalable Applications

Introduction to system design principles, covering load balancing, caching, databases, and distributed systems fundamentals.

November 28, 2024
18 min read
System DesignArchitectureScalability

System Design Basics: Building Scalable Applications


System design is crucial for building applications that can handle millions of users. Here are the fundamental concepts.


Core Principles


1. Scalability


Horizontal scaling means adding more servers.

Vertical scaling means giving each server more CPU, RAM, or disk.


2. Load Balancing


Distribute traffic across multiple servers.


  • Round robin walks servers in order.
  • Least connections prefers the least busy backend.
  • IP hashing pins a client IP to a stable backend when you need stickiness.

  • 3. Caching


    Store frequently accessed data in fast storage.


    # Example: Redis caching
    import redis
    
    cache = redis.Redis()
    
    def get_user(user_id):
        # Check cache first
        cached = cache.get(f"user:{user_id}")
        if cached:
            return json.loads(cached)
        
        # Fetch from database
        user = db.get_user(user_id)
        
        # Store in cache
        cache.setex(f"user:{user_id}", 3600, json.dumps(user))
        
        return user

    Database Design


    SQL vs NoSQL


    SQL (relational) fits when you need ACID guarantees, rich joins, and a strict schema you can reason about with the whole team.


    NoSQL fits when you need flexible documents, easier horizontal scale-out, or very high write throughput, and you accept different consistency tradeoffs.


    Replication


  • Master-Slave. Read from replicas
  • Master-Master. Write to any node

  • Key Components


  • CDN for static assets at the edge
  • Message queues for async work (RabbitMQ, Kafka, and similar tools)
  • Microservices when you need to split ownership and deploy independently
  • API gateways as a single front door for clients

  • Design Process


  • Requirements. Functional and non-functional
  • Capacity estimation for traffic, storage, and bandwidth
  • API design for endpoints and data models
  • Database design for schema and partitioning
  • Component design for the big moving parts
  • Scaling plans for the bottlenecks you expect first

  • Start with these fundamentals and build from there!