🍕 1. 샤딩(Sharding): 데이터를 조각내자

서비스가 대박이 나서 사용자가 1억 명이 되었습니다. 단일 DB로는 감당이 안 됩니다. 이제 데이터를 여러 서버에 나눠 담아야 하는데, 이를 **샤딩(Sharding)**이라 합니다.

문제는 **“어떤 기준으로 나눌 것인가?”**입니다.

전략 1: Range Sharding (범위)

  • 식별자 1 ~ 100만 -> DB 1
  • 식별자 100만 ~ 200만 -> DB 2
  • 문제점: 최근 가입한 유저만 활동한다면? DB 2만 불타오르고(Hotspot) DB 1은 놉니다.

전략 2: Modular Sharding (해시)

  • ID % 서버수로 배정합니다. 데이터가 아주 고르게 퍼집니다.
  • 치명적 문제: 서버를 3대에서 4대로 늘리면?
User ID = 3
Before (Mod 3): 3 % 3 = 0번 서버
After  (Mod 4): 3 % 4 = 3번 서버

⚠️ 재앙(Rebalancing): 서버 대수가 바뀌면 거의 모든 데이터가 이동해야 합니다. 서비스 중단 없이는 불가능합니다.

Modular vs Consistent Hashing

특징Modular HashingConsistent Hashing
규칙Key % NHash(Key)의 링 위 위치
서버 추가 시전체 데이터의 약 100% 이동일부 데이터 (1/N)만 이동
유연성매우 낮음 (서버 수 고정 권장)매우 높음 (Elastic Scaling)
복잡도낮음중간 (링 관리, 가상 노드)

🍩 2. Consistent Hashing (일관된 해싱)

이 재앙을 막기 위해 **“서버가 추가/삭제되어도 데이터 이동을 최소화”**하는 알고리즘이 나왔습니다. 핵심은 **원형 링(Ring)**입니다.

동작 원리

graph TD
    subgraph Ring ["Hash Ring (0 ~ 2^32)"]
        N1((Node A: 100))
        N2((Node B: 300))
        N3((Node C: 600))
        
        N1 --- N2
        N2 --- N3
        N3 --- N1
    end
    
    Data1[Key 1: Hash 150] -->|Clockwise ->| N2
    Data2[Key 2: Hash 400] -->|Clockwise ->| N3
    Data3[Key 3: Hash 800] -->|Clockwise ->| N1
    
    style N1 fill:#ffccbc,stroke:#d84315
    style N2 fill:#ffe0b2,stroke:#ef6c00
    style N3 fill:#fff9c4,stroke:#fbc02d
  1. 커다란 원(해시 링)을 상상하세요. (0 ~ 2^32)
  2. **서버(Node)**를 해시값에 따라 링 위에 배치합니다.
  3. **데이터(Key)**도 해시값에 따라 링 위에 배치합니다.
  4. 데이터는 시계 방향으로 돌면서 만나는 첫 번째 서버에 저장됩니다.

서버가 추가된다면?

서버 C와 A 사이에 서버 D를 추가했습니다.

  • 기존 Modular: 전체 데이터의 100%가 뒤섞임.
  • Consistent Hashing: C와 D 사이의 데이터만 A에서 D로 이동. 나머지(A->B, B->C)는 그대로!

결과: 데이터 이동량이 1/N로 획기적으로 줄어듭니다.

2.2 가상 노드 (Virtual Nodes)

“운 나쁘게 Node A, B, C가 한쪽에 쏠려 있으면 어떡하죠?” (Data Skew) -> 가짜 노드를 수백 개 만들어서 링 전체에 뿌립니다.

graph TD
    subgraph VirtualRing ["Virtual Nodes Spread"]
        A1((A-1)) --- B1((B-1))
        B1 --- C1((C-1))
        C1 --- A2((A-2))
        A2 --- B2((B-2))
        B2 --- C2((C-2))
        C2 --- A1
    end
    
    Note[Data is evenly distributed due to high variety of V-Nodes]

🆔 3. 분산 ID 생성기 (Snowflake)

샤딩을 하면 DB의 AUTO_INCREMENT를 못 씁니다. (1번 DB와 2번 DB에서 같은 ID 100번이 생기면 충돌) 전역적으로 유일한 ID가 필요합니다.

Twitter Snowflake 구조 (64bit)

packet-beta
0-15: "Sequence (12bit)\n(동일 밀리초 내 순서)"
16-25: "Machine ID (10bit)\n(서버 식별)"
26-63: "Timestamp (41bit)\n(시간순 정렬)"
필드비트 수설명
Sign Bit1 bit양수 보장 (항상 0)
Timestamp41 bit밀리초 단위 시간 (약 69년 사용 가능)
Machine ID10 bit1024개의 노드 식별 가능
Sequence12 bit밀리초당 4096개 ID 생성 가능
  1. Timestamp: 시간순 정렬을 보장합니다. (Index 성능에 중요)
  2. Machine ID: 어느 서버에서 생성했는지 구분합니다.
  3. Sequence: 같은 밀리초에 생성된 ID를 구분합니다.

요약

  • Range Sharding: 쉽지만 핫스팟 위험.
  • Modular Sharding: 균등하지만 확장 시 대이동(Rebalancing) 발생.
  • Consistent Hashing: 확장이 유연함. (현대 분산 시스템 표준)
  • Snowflake: 타임스탬프 기반의 유니크 ID 생성 전략.