Mermaid.js Diagram Templates cho System Design

“Một bức diagram tốt thay thế 1,000 dòng giải thích. Trong System Design Interview, vẽ trước rồi nói sau.”

Tags: system-design mermaid diagram template Liên quan: Tuan-01-Scale-From-Zero-To-Millions · Tuan-02-Back-of-the-envelope · Tuan-05-Load-Balancer · Tuan-06-Cache-Strategy · Tuan-07-Database-Sharding-Replication


Cách sử dụng trong Obsidian

Obsidian hỗ trợ Mermaid.js native. Chỉ cần tạo code block với ngôn ngữ mermaid:

```mermaid
flowchart LR
    A[Client] --> B[Server]
```

Mẹo tùy chỉnh nhanh:

  • Copy template bên dưới, paste vào note của bạn

  • Thay đổi text trong [], (), {} để đổi nội dung node

  • Thay đổi style ở cuối để đổi màu sắc

  • LR = Left to Right, TD = Top Down, BT = Bottom to Top

  • Comment bắt đầu bằng ` Template: Single Server Setup Template: Load Balanced Multi-Server Template: 3-Tier Architecture Template: Microservices Architecture Template: Load Balancer with Health Checks Template: Cache-Aside Pattern Template: Cache-Aside Sequence (chi tiết hơn) Template: Database Replication Template: Database Sharding Template: Message Queue Pattern Template: Rate Limiter (Token Bucket / Sliding Window) Template: CI/CD Pipeline Template: Monitoring Stack Template: Blue-Green Deployment Khi switch: Blue trở thành standby / rollback target

    style Blue fill:#bbdefb,stroke:#1565c0,stroke-width:2px style Green fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px,stroke-dasharray: 5 5


### 3.4 Canary Deployment

> Phát hành version mới cho một phần nhỏ user trước — giảm rủi ro.

```mermaid
flowchart TD
     Customize: Đổi % canary, thêm metric check

    Users["👥 Users (100%)"]
    LB["Load Balancer<br/>(Traffic Splitting)"]

    subgraph Stable["Stable — v1.2.0 (95% traffic)"]
        S1["Server 1"]
        S2["Server 2"]
        S3["Server 3"]
        S4["Server 4"]
    end

    subgraph Canary["Canary — v1.3.0 (5% traffic)"]
        C1["Server 5<br/>(Canary)"]
    end

    Monitor["📊 Monitoring<br/>So sánh metrics:<br/>Error rate · Latency · CPU"]
    Decision{{"Canary healthy?"}}

    Users --> LB
    LB -->|"95%"| Stable
    LB -->|"5%"| Canary

    Canary --> Monitor
    Stable --> Monitor
    Monitor --> Decision
    Decision -->|"Yes → Tăng dần<br/>5% → 25% → 50% → 100%"| Stable
    Decision -->|"No → Rollback<br/>100% về Stable"| LB

    style Canary fill:#fff9c4,stroke:#f57f17,stroke-width:2px
    style Stable fill:#c8e6c9,stroke:#2e7d32

4. Security Diagrams

4.1 OAuth2 Authorization Code Flow

Flow an toàn nhất cho server-side apps — Client không bao giờ thấy password.

sequenceDiagram
     Customize: Đổi provider (Google, GitHub), thêm PKCE cho mobile

    participant U as 👤 User (Browser)
    participant C as 🖥️ Client App<br/>(Backend)
    participant A as 🔐 Auth Server<br/>(Google / Auth0)
    participant R as 📦 Resource Server<br/>(API)

    U->>C: 1. Click "Login with Google"
    C->>U: 2. Redirect → Auth Server<br/>/authorize?client_id=xxx<br/>&redirect_uri=xxx<br/>&response_type=code<br/>&scope=profile email<br/>&state=random_csrf_token

    U->>A: 3. User đăng nhập + đồng ý quyền
    A->>U: 4. Redirect về Client<br/>/callback?code=AUTH_CODE&state=xxx

    U->>C: 5. Browser gửi AUTH_CODE về backend
    C->>A: 6. POST /token<br/>{code, client_id, client_secret, redirect_uri}
    A->>C: 7. {access_token, refresh_token, expires_in}

    C->>R: 8. GET /api/user<br/>Authorization: Bearer {access_token}
    R->>C: 9. {user data}
    C->>U: 10. Welcome, User!

    Note over C,A: access_token ngắn hạn (15 phút)<br/>refresh_token dài hạn (30 ngày)<br/>client_secret KHÔNG bao giờ lộ ra frontend

4.2 JWT Authentication Flow

Stateless authentication — server không cần lưu session, token tự chứa thông tin.

sequenceDiagram
     Customize: Thêm refresh token rotation, đổi expiry time

    participant C as 👤 Client
    participant A as 🔐 Auth Service
    participant API as 📦 API Server
    participant DB as 🗄️ Database

    C->>A: 1. POST /login {email, password}
    A->>DB: 2. Verify credentials<br/>(bcrypt compare)
    DB-->>A: 3. User valid ✅

    Note over A: Tạo JWT Token:<br/>Header: {alg: RS256}<br/>Payload: {sub: user_id, role: admin, exp: +15min}<br/>Signature: sign(header.payload, private_key)

    A-->>C: 4. {access_token: "eyJ...", refresh_token: "xyz...", expires_in: 900}

    C->>API: 5. GET /api/orders<br/>Authorization: Bearer eyJ...

    Note over API: Verify JWT:<br/>1. Decode header + payload<br/>2. Verify signature (public_key)<br/>3. Check exp > now<br/>4. Check role permission

    API-->>C: 6. 200 OK {orders data}

    Note over C: Khi access_token hết hạn:
    C->>A: 7. POST /refresh {refresh_token: "xyz..."}
    A-->>C: 8. {new access_token, new refresh_token}

    Note over A: Refresh Token Rotation:<br/>Mỗi lần dùng refresh_token cũ bị revoke<br/>→ Phát hiện token theft nếu dùng lại token cũ

4.3 Zero Trust Network Architecture

“Never trust, always verify” — Mọi request đều phải được xác thực, kể cả internal traffic.

flowchart TD
     Customize: Thêm micro-segmentation, đổi policy engine

    subgraph External["External Network"]
        User["👤 User<br/>(Any location)"]
        Device["📱 Device"]
    end

    subgraph ZeroTrustLayer["Zero Trust Layer"]
        IdP["🔐 Identity Provider<br/>(Okta / Azure AD)<br/>MFA Required"]
        DeviceTrust["📋 Device Trust<br/>Check: OS patched?<br/>Disk encrypted?<br/>MDM enrolled?"]
        PolicyEngine["⚙️ Policy Engine<br/>Who + What + Where + When<br/>→ Allow / Deny / Step-up"]
        Proxy["🛡️ Access Proxy<br/>(BeyondCorp / Cloudflare Access)<br/>mTLS + JWT"]
    end

    subgraph InternalServices["Internal Services (Micro-segmented)"]
        ServiceA["Service A<br/>🔒 mTLS"]
        ServiceB["Service B<br/>🔒 mTLS"]
        ServiceC["Service C<br/>🔒 mTLS"]
        DB[("Database<br/>🔒 Encrypted at rest")]
    end

    subgraph Monitoring["Continuous Monitoring"]
        SIEM["📊 SIEM<br/>(Security Events)"]
        AnomalyDetect["🔍 Anomaly Detection<br/>Unusual access patterns"]
    end

    User --> IdP
    Device --> DeviceTrust
    IdP --> PolicyEngine
    DeviceTrust --> PolicyEngine
    PolicyEngine -->|"Allow"| Proxy
    Proxy -->|"mTLS"| ServiceA
    Proxy -->|"mTLS"| ServiceB
    Proxy -->|"mTLS"| ServiceC
    ServiceA <-->|"mTLS"| ServiceB
    ServiceB <-->|"mTLS"| ServiceC
    ServiceC --> DB

    ServiceA & ServiceB & ServiceC --> SIEM
    SIEM --> AnomalyDetect
    AnomalyDetect -->|"Revoke access"| PolicyEngine

    style ZeroTrustLayer fill:#ffecb3,stroke:#ff6f00,stroke-width:2px
    style InternalServices fill:#e8eaf6,stroke:#283593
    style Monitoring fill:#fce4ec,stroke:#c62828

5. Case Study Templates

5.1 URL Shortener — High Level

Tham chiếu: Tuan-16-Design-URL-Shortener

flowchart TD
     Customize: Đổi hash strategy, thêm analytics, thêm expiry

    User["👤 User"]

    subgraph WriteFlow["Write Flow: Tạo short URL"]
        W_API["API Server<br/>POST /api/shorten"]
        W_IDGen["ID Generator<br/>(Snowflake / Base62 encode)"]
        W_DB[("URL Database<br/>short_code → original_url<br/>PostgreSQL")]
    end

    subgraph ReadFlow["Read Flow: Redirect"]
        R_API["API Server<br/>GET /abc123"]
        R_Cache[("Redis Cache<br/>Hot URLs<br/>TTL: 24h")]
        R_DB[("URL Database")]
    end

    subgraph Analytics["Analytics (Async)"]
        Queue[["Kafka<br/>click-events"]]
        ClickProcessor["Click Processor<br/>(Country, Device, Referrer)"]
        AnalyticsDB[("ClickHouse<br/>Analytics DB")]
    end

    User -->|"1. POST long_url"| W_API
    W_API --> W_IDGen
    W_IDGen -->|"2. Generate: abc123"| W_API
    W_API -->|"3. Store mapping"| W_DB
    W_API -->|"4. Return: short.ly/abc123"| User

    User -->|"5. GET /abc123"| R_API
    R_API -->|"6a. Check cache"| R_Cache
    R_Cache -->|"HIT"| R_API
    R_API -->|"6b. Cache MISS"| R_DB
    R_API -->|"7. 302 Redirect → original_url"| User
    R_API -->|"8. Log click event"| Queue
    Queue --> ClickProcessor --> AnalyticsDB

    style WriteFlow fill:#e3f2fd,stroke:#1565c0
    style ReadFlow fill:#e8f5e9,stroke:#2e7d32
    style Analytics fill:#fff3e0,stroke:#e65100

5.2 Chat System (WebSocket)

Tham chiếu: Tuan-17-Design-Chat-System

flowchart TD
     Customize: Thêm group chat logic, thêm read receipts, thêm typing indicator

    subgraph Clients["Clients"]
        UserA["👤 User A<br/>(WebSocket connected)"]
        UserB["👤 User B<br/>(WebSocket connected)"]
        UserC["👤 User C<br/>(Offline)"]
    end

    subgraph ChatService["Chat Infrastructure"]
        LB["Load Balancer<br/>(Sticky Session / WebSocket aware)"]
        WS1["WebSocket Server 1<br/>Connections: User A"]
        WS2["WebSocket Server 2<br/>Connections: User B"]

        subgraph Routing["Message Routing"]
            PubSub[["Redis Pub/Sub<br/>Channel per user"]]
            PresenceService["Presence Service<br/>(Online/Offline tracker)"]
            SessionStore[("Session Store<br/>user_id → ws_server_id")]
        end
    end

    subgraph Storage["Storage"]
        MsgQueue[["Kafka<br/>message-events"]]
        MsgDB[("Message DB<br/>(Cassandra)<br/>Partition key: chat_id")]
        PushService["Push Notification<br/>(FCM / APNs)"]
    end

    UserA -->|"1. Send message"| LB --> WS1
    WS1 -->|"2. Publish to channel"| PubSub
    WS1 -->|"3. Persist async"| MsgQueue --> MsgDB

    PubSub -->|"4a. User B online"| WS2
    WS2 -->|"5a. Deliver via WebSocket"| UserB

    PresenceService -->|"4b. User C offline"| PushService
    PushService -->|"5b. Push notification"| UserC

    style ChatService fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    style Storage fill:#fff3e0,stroke:#e65100

5.3 News Feed (Fan-out)

Fan-out on write (push model) vs Fan-out on read (pull model) — trade-off giữa write cost và read latency.

flowchart TD
     Customize: Đổi threshold follower count, thêm ranking algorithm

    Publisher["👤 Publisher<br/>tạo post mới"]

    subgraph FanOutService["Fan-out Service"]
        PostAPI["Post API<br/>POST /feed"]
        PostDB[("Post Storage<br/>(MySQL)")]
        FanOutWorker["Fan-out Worker"]
        GraphDB[("Social Graph<br/>follower list")]
        Decision{{"Followers > 10K?<br/>(Celebrity check)"}}
    end

    subgraph FanOutOnWrite["Fan-out on Write (Push)"]
        Queue1[["Task Queue"]]
        CacheWriter["Cache Writer"]
        FeedCache1[("Feed Cache<br/>user:feed:A → [post_ids]<br/>user:feed:B → [post_ids]")]
    end

    subgraph FanOutOnRead["Fan-out on Read (Pull)"]
        FeedCache2[("Celebrity Posts<br/>celebrity:123 → [post_ids]")]
    end

    subgraph ReadPath["Read Path — GET /feed"]
        FeedAPI["Feed API"]
        Merger["Feed Merger<br/>+ Ranking<br/>(Chronological + ML Score)"]
        Reader["👤 Reader"]
    end

    Publisher --> PostAPI --> PostDB
    PostAPI --> FanOutWorker
    FanOutWorker --> GraphDB
    GraphDB --> Decision

    Decision -->|"No (<10K followers)<br/>Push to each follower cache"| Queue1
    Queue1 --> CacheWriter --> FeedCache1

    Decision -->|"Yes (Celebrity)<br/>Lazy load on read"| FeedCache2

    Reader --> FeedAPI
    FeedAPI --> FeedCache1
    FeedAPI --> FeedCache2
    FeedCache1 --> Merger
    FeedCache2 --> Merger
    Merger -->|"Sorted + Ranked feed"| Reader

    style FanOutOnWrite fill:#e8f5e9,stroke:#2e7d32
    style FanOutOnRead fill:#fff3e0,stroke:#e65100
    style Decision fill:#f9a825,stroke:#333,stroke-width:2px

5.4 Notification System (Multi-channel)

Gửi notification qua nhiều kênh: Push, SMS, Email — routing dựa trên user preference.

flowchart TD
     Customize: Thêm kênh, đổi priority logic, thêm template engine

    subgraph Triggers["Trigger Sources"]
        OrderSvc["Order Service<br/>order.completed"]
        PaymentSvc["Payment Service<br/>payment.failed"]
        SocialSvc["Social Service<br/>user.followed"]
        ScheduleSvc["Scheduler<br/>daily_digest"]
    end

    subgraph NotificationService["Notification Service"]
        Ingestion[["Kafka<br/>notification-events"]]
        Processor["Notification Processor"]
        Template["Template Engine<br/>(i18n support)"]
        UserPref[("User Preferences<br/>channel: [push, email]<br/>quiet_hours: 22:00-07:00")]
        RateLimiter["Rate Limiter<br/>Max 10 noti/user/hour"]
        Router["Channel Router"]
    end

    subgraph Channels["Delivery Channels"]
        Push["📱 Push<br/>(FCM / APNs)"]
        SMS["📲 SMS<br/>(Twilio)"]
        Email["📧 Email<br/>(SendGrid / SES)"]
        InApp["🔔 In-App<br/>(WebSocket)"]
    end

    subgraph Tracking["Delivery Tracking"]
        StatusDB[("Delivery Status DB<br/>sent / delivered / read / failed")]
        Retry[["Retry Queue<br/>(Failed deliveries)"]]
    end

    Triggers --> Ingestion
    Ingestion --> Processor
    Processor --> Template
    Processor --> UserPref
    Processor --> RateLimiter
    RateLimiter --> Router

    Router -->|"preference: push"| Push
    Router -->|"preference: sms"| SMS
    Router -->|"preference: email"| Email
    Router -->|"always"| InApp

    Push & SMS & Email & InApp --> StatusDB
    StatusDB -->|"status: failed"| Retry
    Retry --> Router

    style NotificationService fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    style Channels fill:#e8f5e9,stroke:#2e7d32

5.5 Distributed Key-Value Store (Hash Ring + Replication)

Consistent Hashing phân phối data — replication đảm bảo durability.

flowchart TD
     Customize: Đổi replication factor, thêm virtual nodes, đổi consistency level

    Client["Client<br/>PUT/GET key"]
    Coordinator["Coordinator Node<br/>(Bất kỳ node nào)"]

    subgraph HashRing["Consistent Hash Ring"]
        direction LR
        N1["Node A<br/>Range: 0–90"]
        N2["Node B<br/>Range: 91–180"]
        N3["Node C<br/>Range: 181–270"]
        N4["Node D<br/>Range: 271–360"]
    end

    subgraph Replication["Replication (N=3)"]
        direction TB
        Primary["Primary: Node B<br/>(hash(key) lands here)"]
        Rep1["Replica 1: Node C<br/>(Clockwise next)"]
        Rep2["Replica 2: Node D<br/>(Clockwise next+1)"]
    end

    subgraph Consistency["Consistency Levels"]
        W["Write: W=2<br/>(Ack from 2/3 nodes)"]
        R["Read: R=2<br/>(Read from 2/3 nodes)"]
        Note1["W + R > N → Strong Consistency<br/>2 + 2 > 3 ✅"]
    end

    Client --> Coordinator
    Coordinator -->|"hash(key) = 150<br/>→ lands in Node B range"| N2

    N2 -->|"Write primary"| Primary
    Primary -->|"Replicate"| Rep1
    Primary -->|"Replicate"| Rep2

    style HashRing fill:#e8eaf6,stroke:#283593,stroke-width:2px
    style Replication fill:#e8f5e9,stroke:#2e7d32
    style Consistency fill:#fff8e1,stroke:#f57f17

6. Sequence Diagrams

6.1 HTTP Request Lifecycle

Từ browser gõ URL đến khi render xong — mỗi bước một latency.

sequenceDiagram
     Customize: Thêm cache layers, thêm CDN, thêm middleware

    participant B as 🌐 Browser
    participant DNS as DNS Resolver
    participant CDN as CDN (Cloudflare)
    participant LB as Load Balancer
    participant App as App Server
    participant Cache as Redis Cache
    participant DB as Database

    B->>DNS: 1. DNS Lookup: api.example.com
    DNS-->>B: 2. IP: 203.0.113.10 (TTL: 300s)

    B->>CDN: 3. TCP Handshake (SYN → SYN-ACK → ACK)
    B->>CDN: 4. TLS Handshake (nếu HTTPS)

    B->>CDN: 5. GET /api/users/123
    alt CDN Cache HIT
        CDN-->>B: 6a. 200 OK (from CDN cache, ~20ms)
    else CDN Cache MISS
        CDN->>LB: 6b. Forward request
        LB->>App: 7. Route to healthy server

        App->>Cache: 8. GET user:123
        alt Cache HIT
            Cache-->>App: 9a. Data from cache (~1ms)
        else Cache MISS
            Cache-->>App: 9b. null
            App->>DB: 10. SELECT * FROM users WHERE id=123
            DB-->>App: 11. Row data (~5ms)
            App->>Cache: 12. SET user:123 (TTL=300s)
        end

        App-->>LB: 13. 200 OK + JSON
        LB-->>CDN: 14. Response
        CDN-->>B: 15. Response + Cache-Control header
    end

    B->>B: 16. Parse JSON + Render UI

    Note over B,DB: Tổng latency tốt nhất: ~20ms (CDN hit)<br/>Trung bình: ~50ms (Cache hit)<br/>Xấu nhất: ~200ms (DB query)

6.2 TLS Handshake

Thiết lập kết nối mã hóa — 1-RTT cho TLS 1.3, 2-RTT cho TLS 1.2.

sequenceDiagram
     Customize: Đổi cipher suite, thêm 0-RTT resumption

    participant C as 👤 Client (Browser)
    participant S as 🖥️ Server

    Note over C,S: TCP Handshake đã hoàn thành

    C->>S: ClientHello<br/>- Supported TLS versions: [1.3, 1.2]<br/>- Cipher suites: [AES_256_GCM_SHA384, ...]<br/>- Key share: (ECDHE public key)<br/>- SNI: api.example.com

    S->>C: ServerHello<br/>- Selected: TLS 1.3<br/>- Cipher: AES_256_GCM_SHA384<br/>- Key share: (ECDHE public key)

    S->>C: EncryptedExtensions
    S->>C: Certificate (server cert chain)
    S->>C: CertificateVerify (signature)
    S->>C: Finished (MAC of handshake)

    Note over C: Verify certificate chain:<br/>1. Check CA signature<br/>2. Check expiry<br/>3. Check revocation (OCSP)<br/>4. Check hostname match SNI

    C->>S: Finished (MAC of handshake)

    Note over C,S: ✅ Handshake complete (1-RTT)<br/>Both sides derive symmetric keys<br/>from ECDHE shared secret<br/>→ All subsequent data encrypted

    C->>S: 🔒 GET /api/data (encrypted)
    S->>C: 🔒 200 OK {data} (encrypted)

6.3 Database Transaction with Retry

Xử lý optimistic concurrency — retry khi conflict, tránh data corruption.

sequenceDiagram
     Customize: Đổi max retry, đổi backoff strategy, đổi isolation level

    participant A as App Server
    participant DB as Database
    participant Log as Audit Log

    Note over A,DB: Scenario: Transfer $100 from Account A → Account B<br/>Isolation Level: SERIALIZABLE

    loop Retry (max 3 lần, exponential backoff)
        A->>DB: BEGIN TRANSACTION

        A->>DB: SELECT balance FROM accounts WHERE id='A' FOR UPDATE
        DB-->>A: balance = $500

        A->>DB: SELECT balance FROM accounts WHERE id='B' FOR UPDATE
        DB-->>A: balance = $200

        Note over A: Validate: $500 >= $100 ✅

        A->>DB: UPDATE accounts SET balance = 400 WHERE id='A'
        A->>DB: UPDATE accounts SET balance = 300 WHERE id='B'
        A->>DB: INSERT INTO transactions (from, to, amount) VALUES ('A', 'B', 100)

        A->>DB: COMMIT

        alt Commit SUCCESS ✅
            DB-->>A: COMMIT OK
            A->>Log: Log: Transfer A→B $100 SUCCESS
            Note over A: Break khỏi retry loop
        else Deadlock / Serialization Failure ❌
            DB-->>A: ERROR: could not serialize access
            A->>DB: ROLLBACK
            Note over A: Wait: 100ms × 2^attempt<br/>(Exponential backoff)<br/>Attempt 1: 100ms<br/>Attempt 2: 200ms<br/>Attempt 3: 400ms
        else Max Retries Exceeded ❌
            A->>Log: Log: Transfer A→B $100 FAILED after 3 retries
            A-->>A: Return error to caller
        end
    end

Quick Reference: Mermaid Syntax Cheat Sheet

SyntaxÝ nghĩaVí dụ
flowchart TDFlow chart Top → Downflowchart LR cho Left → Right
A[Text]Rectangle nodeA["Node with special chars"]
A(Text)Rounded nodeA("Rounded")
A{Text}Diamond (decision)A{"Yes or No?"}
A[(Text)]Database cylinderA[("PostgreSQL")]
A[[Text]]SubroutineA[["Queue"]]
A-->BSolid arrowA-->&#124;"Label"&#124;B cho arrow có label
A-.->BDotted arrowDùng cho async/optional
A==>BThick arrowDùng cho main flow
A-.-xBDotted crossDùng cho rejected/blocked
subgraph TitleGroup nodessubgraph S["Title"]
style A fill:#fffStylingfill, stroke, stroke-width
sequenceDiagramSequence diagramDùng cho request/response flows
participant A as NameNamed participantparticipant C as 👤 Client
A->>B: messageSolid arrow (seq)->> solid, -->> dotted
alt / else / endConditional (seq)Dùng cho branching logic
loop / endLoop (seq)Dùng cho retry logic
Note over A,BNote span (seq)Note over A,B: Explanation

Tham khảo