Skip to content
intermediatePhase 51 · High-Level Design Framework

High-Level Architecture

Draw the system overview with clients, servers, databases, and caches.

1h
0 problems
Topic Progress0%

Component Design

What is High-Level Design?

High-Level Design (HLD) defines the system architecture at a macro level. It identifies the major components, their responsibilities, and how they interact. For an SDE-1 interview, your job is to break down a vague problem into concrete components and explain the tradeoffs.

The Building Blocks

Every distributed system is composed of these fundamental layers:

Layer Components Responsibility
Client Web browser, Mobile app, Desktop app User interface, input validation, rendering
Edge CDN, Load Balancer, Reverse Proxy Caching, traffic distribution, SSL termination
Gateway API Gateway, Auth Service Request routing, authentication, rate limiting
Services Business logic, Microservices, Workers Core domain logic, processing
Data SQL DB, NoSQL DB, Cache, Search Index Persistent storage, fast reads

Typical Web Application Architecture

┌─────────────────────────────────────────────────────────────────┐
│                          CLIENTS                                │
│   ┌──────────┐  ┌──────────┐  ┌──────────┐                    │
│   │ Web App  │  │Mobile App│  │  3rd Party│                    │
│   └────┬─────┘  └────┬─────┘  └────┬─────┘                    │
│        │              │              │                          │
└────────┼──────────────┼──────────────┼──────────────────────────┘
         │              │              │
         ▼              ▼              ▼
┌─────────────────────────────────────────────────────────────────┐
│                        CDN / EDGE                               │
│   ┌──────────┐  ┌──────────┐                                   │
│   │   CDN    │  │   WAF    │  (CloudFront, Cloudflare)        │
│   └────┬─────┘  └────┬─────┘                                   │
└────────┼──────────────┼─────────────────────────────────────────┘
         │              │
         ▼              ▼
┌─────────────────────────────────────────────────────────────────┐
│                     LOAD BALANCER                               │
│   ┌──────────────────────────┐                                 │
│   │  ALB / NLB / HAProxy     │  (Health checks, SSL, routing)  │
│   └────────────┬─────────────┘                                 │
└────────────────┼────────────────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────────────────────────┐
│                     API GATEWAY                                 │
│   ┌──────────────────────────┐                                 │
│   │  Kong / AWS API Gateway  │  (Auth, Rate Limit, Routing)    │
│   └────────────┬─────────────┘                                 │
└────────────────┼────────────────────────────────────────────────┘
                 │
        ┌────────┼────────┐
        ▼        ▼        ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Service A │ │ Service B │ │ Service C │
│ (Users)   │ │ (Orders)  │ │ (Payments)│
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
      │             │              │
      ▼             ▼              ▼
┌─────────────────────────────────────────────────────────────────┐
│                       DATA LAYER                                │
│  ┌────────┐  ┌────────┐  ┌────────┐  ┌────────┐               │
│  │ MySQL  │  │ Redis  │  │ S3     │  │ Kafka  │               │
│  │ (SQL)  │  │ (Cache)│  │ (Blob) │  │ (Queue)│               │
│  └────────┘  └────────┘  └────────┘  └────────┘               │
└─────────────────────────────────────────────────────────────────┘

Component Deep Dive

1. Client Layer

  • Renders UI, collects user input
  • Performs client-side validation (reduces bad requests)
  • Calls backend APIs via HTTP/HTTPS
  • Example: React SPA, iOS/Android native app

2. CDN (Content Delivery Network)

  • Caches static assets (images, CSS, JS) at edge locations
  • Reduces latency by serving content from the nearest node
  • Offloads ~80% of traffic from origin servers
  • Examples: CloudFront, Cloudflare, Akamai

3. Load Balancer

  • Distributes incoming requests across multiple backend servers
  • Performs health checks and removes unhealthy instances
  • Algorithms: Round Robin, Least Connections, IP Hash
  • Layer 4 (TCP) vs Layer 7 (HTTP) load balancing

4. API Gateway

  • Single entry point for all client requests
  • Handles authentication (JWT validation), rate limiting, request routing
  • Can aggregate responses from multiple microservices
  • Translates public API to internal service calls

5. Service Layer

  • Contains the business logic
  • Can be monolithic (single deployable) or microservices (independent)
  • Each service owns its data store (database per service pattern)
  • Communicates via sync (REST/gRPC) or async (queues) patterns

6. Data Layer

  • Relational DB (MySQL, PostgreSQL): Structured data, ACID transactions
  • NoSQL (DynamoDB, MongoDB): Flexible schema, horizontal scaling
  • Cache (Redis, Memcached): Sub-millisecond reads, session storage
  • Message Queue (Kafka, SQS): Async communication, event streaming

Monolithic vs Microservices

Aspect Monolith Microservices
Deployment Single unit, simple to deploy Independent services, complex orchestration
Scaling Scale entire app Scale individual services
Development Faster for small teams Better for large teams, parallel work
Tech Stack One language/framework Polyglot (each service chooses)
Debugging Easier (single codebase) Harder (distributed tracing needed)
Fault Isolation One bug can crash everything Failure contained to single service
Latency In-process calls (fast) Network calls (slower, needs gRPC/async)
When to Use MVP, small team, <10 services Large scale, many teams, complex domain

Rule of thumb: Start with a monolith. Extract microservices when you have a clear boundary and the team is large enough to justify the operational overhead.

Real Example: E-Commerce Architecture

Customer → Web/App → CDN (product images)
                → Load Balancer
                    → API Gateway (auth, rate limit)
                        → Product Service → PostgreSQL (product catalog)
                        → Cart Service → Redis (session/cart state)
                        → Order Service → PostgreSQL (orders)
                        → Payment Service → Payment Gateway (Stripe)
                        → Notification Service → SQS → Email/SMS Worker

Each service has its own database. The Order Service publishes an OrderCreated event to Kafka. The Notification Service consumes it and sends a confirmation email. This is the essence of event-driven microservices.

Data Flow Patterns

Overview

Data flow describes how information moves through your system. Choosing the right pattern affects latency, reliability, and complexity.

Pattern 1: Request-Response (Synchronous)

The client sends a request and waits for a response. This is the most common pattern.

Client ──HTTP Request──▶ Service ──Query──▶ Database
Client ◀──HTTP Response── Service ◀──Result── Database

Characteristics:

  • Simple, easy to reason about
  • Client blocks until response arrives
  • Tight coupling: if Service B is down, Service A fails
  • Best for: CRUD operations, user interactions that need immediate feedback

Example: User loads their profile page. Browser sends GET /users/123, waits for JSON response.

Pattern 2: Event-Driven (Asynchronous)

Services produce events without knowing who consumes them. Consumers process events at their own pace.

Service A ──Publish Event──▶ Message Broker ──Deliver──▶ Service B
                                          ──Deliver──▶ Service C

Characteristics:

  • Decoupled: producer and consumer don't know about each other
  • Resilient: if consumer is down, messages queue up
  • Eventually consistent: data may be stale for a short time
  • Best for: notifications, analytics, audit logs, cross-service workflows

Example: User places an order. Order Service publishes OrderCreated event. Payment Service, Inventory Service, and Notification Service each consume it independently.

Pattern 3: Publish-Subscribe (Pub-Sub)

A specific form of event-driven where multiple subscribers receive the same event.

Publisher ──Topic: order.created──▶ Message Broker
                │                   │
                │                   ├──▶ Subscriber: Payment Service
                │                   ├──▶ Subscriber: Inventory Service
                │                   └──▶ Subscriber: Analytics Service

Characteristics:

  • One event, many consumers (fan-out)
  • Each subscriber processes the same event independently
  • Subscribers can be added without modifying the publisher
  • Best for: when multiple systems need the same data change

Pattern 4: CQRS (Command Query Responsibility Segregation)

Separate the write model (commands) from the read model (queries).

Write Path:     Client ──▶ Command Handler ──▶ Write DB ──▶ Event ──▶ Read DB
Read Path:      Client ──▶ Query Handler  ──▶ Read DB (optimized for reads)

Characteristics:

  • Write and read databases can be different (normalization vs denormalization)
  • Read model is pre-computed for fast queries
  • Adds complexity but dramatically improves read performance
  • Best for: systems with very different read/write patterns (e.g., social media feeds)

Pattern Comparison Table

Pattern Latency Consistency Complexity Best For
Request-Response Low (direct) Strong Low CRUD, user-facing queries
Event-Driven Medium (queue) Eventual Medium Workflows, cross-service sync
Pub-Sub Medium (queue) Eventual Medium Fan-out, notifications
CQRS Low reads Eventual High Read-heavy systems, analytics

Choosing the Right Pattern

  • Need immediate response? → Request-Response (REST/gRPC)
  • Multiple services need the same data? → Pub-Sub
  • Long-running or background work? → Event-Driven with queue
  • Read-heavy with different read/write patterns? → CQRS
  • Don't know all consumers upfront? → Event-Driven (add consumers later)

Real-World Example: Order Processing Pipeline

1. Client ──POST /orders──▶ Order Service (Request-Response)
   → Returns 201 Created with order ID immediately

2. Order Service ──Publish OrderCreated──▶ Kafka (Event-Driven)

3. Kafka delivers to:
   ├── Payment Service (charges card)
   ├── Inventory Service (reserves stock)
   ├── Notification Service (sends email)
   └── Analytics Service (records metrics)

4. Each service updates its own database independently

5. Client polls GET /orders/{id} (Request-Response) to check status

This hybrid approach gives you the best of both worlds: fast user experience (immediate response) with reliable background processing (event-driven).

Communication Patterns

Synchronous vs Asynchronous Communication

Aspect Synchronous Asynchronous
Flow Sender waits for response Sender sends and continues
Coupling Tight (both must be up) Loose (queue absorbs failures)
Latency Bounded (known timeout) Unbounded (depends on processing)
Use Case User-facing queries Background processing, events
Protocols REST, gRPC, GraphQL Kafka, SQS, RabbitMQ, Redis Streams

REST (Representational State Transfer)

The standard for HTTP APIs. Uses verbs (GET, POST, PUT, DELETE) on resources.

GET    /users/123          → Fetch user
POST   /users              → Create user
PUT    /users/123          → Update user
DELETE /users/123          → Delete user

Pros:

  • Universal: every language and framework supports it
  • Human-readable (JSON)
  • Stateless: each request contains all needed info
  • HTTP/2 support for multiplexing

Cons:

  • Text-based (larger payloads)
  • No built-in streaming
  • Contract is implicit (docs needed)

When to use: Public APIs, simple CRUD, when you need broad compatibility.

gRPC (Google Remote Procedure Call)

Binary protocol using Protocol Buffers. Enables efficient service-to-service communication.

// user.proto
syntax = "proto3";

service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc ListUsers (ListUsersRequest) returns (stream User);  // Server streaming
}

message GetUserRequest {
  string user_id = 1;
}

message User {
  string id = 1;
  string name = 2;
  string email = 3;
}
# Server
import grpc
from user_pb2 import GetUserRequest, User
from user_pb2_grpc import UserServiceServicer

class UserServicer(UserServiceServicer):
    def GetUser(self, request, context):
        return User(id=request.user_id, name="Alice", email="alice@example.com")

Pros:

  • 10x smaller payloads than JSON (binary)
  • Strongly typed with code generation
  • Supports streaming (server, client, bidirectional)
  • Built-in deadline propagation and cancellation

Cons:

  • Not human-readable
  • Requires protobuf tooling
  • Browser support limited (needs gRPC-Web proxy)

When to use: Internal microservices, high-throughput communication, streaming data.

Message Queues (SQS, RabbitMQ)

Point-to-point communication. One producer, one consumer per message.

Producer ──▶ Queue ──▶ Consumer
            (FIFO)

Characteristics:

  • At-least-once delivery: message retried if consumer fails
  • Dead letter queue: failed messages go here for debugging
  • Visibility timeout: message hidden while being processed
  • Batching: send/receive multiple messages at once
# AWS SQS Example
import boto3

sqs = boto3.client('sqs')

# Send
sqs.send_message(
    QueueUrl='https://sqs.us-east-1.amazonaws.com/123456/orders',
    MessageBody='{"orderId": "123", "amount": 99.99}'
)

# Receive
response = sqs.receive_message(
    QueueUrl='https://sqs.us-east-1.amazonaws.com/123456/orders',
    MaxNumberOfMessages=10,
    WaitTimeSeconds=20  # Long polling
)
for msg in response['Messages']:
    process(msg)
    sqs.delete_message(QueueUrl=..., ReceiptHandle=msg['ReceiptHandle'])

When to use: Task queues, order processing, email sending, any background job.

Event Streaming (Kafka)

Distributed commit log. Messages are retained for a configurable time. Multiple consumers can read the same stream.

Producer ──▶ Topic: orders ──▶ Partition 0 ──▶ Consumer Group A (Payment)
                           ──▶ Partition 1 ──▶ Consumer Group A (Payment)
                           ──▶ Partition 2 ──▶ Consumer Group B (Analytics)

Key Concepts:

  • Topic: logical channel (e.g., order-events)
  • Partition: parallel unit within a topic
  • Consumer Group: set of consumers that share partitions
  • Offset: position in the partition (tracks what's been read)
  • Retention: messages kept for N days regardless of consumption

Pros:

  • Replay: reprocess events from any point in time
  • High throughput: millions of messages per second
  • Durable: messages persisted to disk
  • Multiple consumer groups read independently

Cons:

  • Operational complexity (Kafka cluster management)
  • Ordering guarantees only within a partition
  • Eventual consistency

When to use: Event sourcing, real-time analytics, log aggregation, audit trails.

When to Use Each Pattern

Scenario Recommended Pattern
User fetches their profile REST (request-response)
Service-to-service internal call gRPC (fast, typed)
Process background jobs SQS (message queue)
Multiple services react to same event Kafka (event streaming)
Real-time notifications WebSocket + Redis Pub/Sub
Batch data processing Kafka → Spark/Flink consumer
Third-party integration REST (widely supported)

Hybrid Example: Ride-Sharing App

Rider App ──REST──▶ API Gateway ──gRPC──▶ Trip Service (state machine)
                                       ──gRPC──▶ Driver Service (matching)
                                       ──gRPC──▶ Pricing Service (surge calc)

Trip Service ──Kafka──▶ Driver Service (location updates)
                    ──Kafka──▶ Notification Service (SMS push)
                    ──Kafka──▶ Analytics Service (metrics)

Driver App ──WebSocket──▶ Real-time location stream ──▶ Kafka ──▶ Trip Service
  • REST: Client-facing APIs (simple, compatible)
  • gRPC: Internal service calls (fast, typed)
  • Kafka: Event streaming (location updates, trip events)
  • WebSocket: Real-time bidirectional communication

Practice Problems

0/3solved
Design High-Level Architecture System

Design a scalable High-Level Architecture system. Cover high-level architecture, data model, and API design.

Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliability
High-Level Architecture Scaling

How would you scale High-Level Architecture to handle 10x the current load? Identify bottlenecks and solutions.

Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decomposition
High-Level Architecture Failure Modes

Analyze potential failure modes for High-Level Architecture and design mitigation strategies.

Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradation

Quiz

1. Which component sits between the client and backend services to handle authentication, rate limiting, and request routing?

Question 1 options

2. When should you choose gRPC over REST for internal service communication?

Question 2 options

3. An Order Service needs to notify Payment, Inventory, and Notification services when an order is placed. Which pattern best fits this scenario?

Question 3 options

4. What is the key difference between a message queue (SQS) and event streaming (Kafka)?

Question 4 options

5. In the e-commerce architecture example, why does each microservice have its own database?

Question 5 options

6. What is the purpose of a CDN in a web application architecture?

Question 6 options

Flashcards

Question

What are the 5 fundamental layers of a web application architecture?

Answer

Client (UI), Edge (CDN/Load Balancer), Gateway (API Gateway/Auth), Services (Business Logic), Data (Databases/Cache/Queues)

Question

Monolith vs Microservices: When to choose which?

Answer

Monolith: MVP, small team, <10 services. Microservices: large scale, many teams, complex domain, need independent scaling.

Question

REST vs gRPC: Key differences?

Answer

REST: text/JSON, human-readable, browser-friendly, universal. gRPC: binary/protobuf, 10x smaller payloads, strongly typed, streaming support, best for internal services.

Question

When to use synchronous vs asynchronous communication?

Answer

Sync: user needs immediate response (CRUD, queries). Async: background processing, cross-service workflows, when you can tolerate eventual consistency.

Question

What is the database-per-service pattern?

Answer

Each microservice owns its own database. Services cannot directly access each other's data. Prevents tight coupling, enables independent evolution and scaling. Tradeoff: eventual consistency.

Question

Kafka vs SQS: When to use which?

Answer

Kafka: event streaming, replay, multiple consumer groups, high throughput, audit trails. SQS: task queues, simple background jobs, at-least-once delivery, dead letter queues.

Revision Notes

Key Takeaways

  • 1.Start with a monolith. Extract microservices only when you have clear boundaries and team size justifies it.
  • 2.Use REST for public APIs and simple CRUD. Use gRPC for internal high-performance service calls.
  • 3.Prefer async (event-driven) for cross-service communication to decouple services and improve resilience.
  • 4.Kafka for event streaming and replay. SQS for simple task queues and background jobs.
  • 5.Every architecture decision is a tradeoff. In an interview, explain the tradeoffs, not just the choice.
  • 6.The database-per-service pattern is key to microservices: each service owns its data.
  • 7.CDNs offload ~80% of traffic. Always consider caching at the edge.

Interview Tips

  • Always start by clarifying requirements: scale, latency, consistency needs, and team size.
  • Draw the architecture diagram first. Identify the 5 layers and populate with specific technologies.
  • Explain tradeoffs for every decision. Interviewers want to see your reasoning, not just the answer.
  • When asked about communication patterns, mention both sync and async options and explain when each is appropriate.
  • For microservices questions, always mention database-per-service and eventual consistency.
  • Mention scalability: how does your design handle 10x traffic? Think horizontal scaling, caching, and queueing.
  • Don't over-engineer. A simple design that works is better than a complex one that doesn't.

Cheat Sheet

High-Level Architecture Cheat Sheet

5 Layers: Client → Edge (CDN/LB) → Gateway (API Gateway) → Services → Data

Monolith: Single deployable, simple, good for small teams.
Microservices: Independent services, database-per-service, complex but scalable.

Communication Patterns:

  • REST: HTTP/JSON, universal, request-response, good for public APIs
  • gRPC: Binary/protobuf, 10x smaller, streaming, good for internal services
  • SQS: Message queue, at-least-once, dead letter queue, good for task processing
  • Kafka: Event streaming, replay, multiple consumer groups, good for audit/analytics

Data Flow:

  • Request-Response: Client waits for answer (CRUD)
  • Event-Driven: Publish event, consumers react independently
  • Pub-Sub: One event, many subscribers (fan-out)
  • CQRS: Separate read/write models for optimized queries

Key Design Decisions:

  • CDN for static assets (images, CSS, JS)
  • Load Balancer for traffic distribution and health checks
  • API Gateway for auth, rate limiting, routing
  • Database-per-service for decoupled microservices
  • Async for background work, sync for user-facing queries