샤딩

2025. 6. 16. 16:22·Daily Logs/TIL (Today I Learned)
목차
  1. 샤딩(Sharding)의 등장
  2. 샤딩의 장점
  3. 샤딩 적용 방식
  4. 해시 함수와 샤딩
  5. 생각지도 못했던 문제: 리샤딩(Resharding)
  6. Consistent Hashing: 유연한 샤딩을 위한 해법
  7. 샤딩의 어두운 면: 복잡성
  8. 분산 트랜잭션 (Distributed Transactions)
  9. Cross-Shard JOIN
  10. 결론: 샤딩, 도입 전 반드시 확인할 체크리스트
데이터베이스 샤딩(Sharding): 대규모 트래픽 지옥에서 벗어나기

데이터베이스 샤딩(Sharding): 대규모 트래픽 지옥에서 벗어나기

동시 접속자 수가 기하급수적으로 늘어날 때, 데이터베이스는 가장 먼저 병목 현상을 겪는 지점 중 하나입니다.
이러한 한계를 극복하기 위한 강력한 기술인 샤딩(Sharding)에 대해 깊이 있게 알아보고, 도입 시 고려해야 할 점과 체크리스트까지 살펴보겠습니다.

샤딩(Sharding)의 등장

샤딩(Sharding)이란 데이터베이스를 수평적으로 분할하여 여러 개의 작은 데이터베이스(샤드)로 나누는 기술입니다. 즉, 하나의 거대한 데이터베이스를 여러 서버에 물리적으로 분산시켜 관리하는 방식입니다.

하나의 데이터베이스는 하나의 서버에 설치되므로 max_connections와 같은 물리적인 한계가 명확합니다. 샤딩은 이 물리적인 한계를 극복하기 위해 더 많은 물리적 자원을 투입하는 전략입니다. 4개의 데이터베이스를 사용한다면, 이론적으로 처리 가능한 커넥션 수도 4배로 늘어나 CCU 증가에 효과적으로 대응할 수 있습니다.

샤딩의 장점

  • 확장성(Scalability): 더 많은 커넥션을 처리할 수 있어 CCU가 늘어나도 안정적인 서비스 운영이 가능합니다.
  • 성능(Performance): 각 샤드는 독립적으로 작동하여 요청을 병렬적으로 처리할 수 있으므로, 전반적인 시스템 성능이 향상됩니다.
  • 가용성(Availability): 특정 샤드에 문제가 발생하더라도 다른 샤드는 영향을 받지 않으므로, 전체 서비스 중단을 막고 가용성을 높일 수 있습니다.

샤딩 적용 방식

수평적 샤딩은 주로 다음과 같은 키 기반 분할 방식을 사용합니다.

  1. 모듈로 기반 샤딩 (Modulo Sharding)

    플레이어 ID와 같은 숫자 키를 샤드의 총 개수로 나눈 나머지를 이용해 샤드를 결정합니다.

    // 플레이어 ID % 샤드의 총 개수 = 저장될 샤드 번호
    const shardNo = playerId % NUM_OF_SHARDS;
  2. 범위 기반 샤딩 (Range-Based Sharding)

    ID의 특정 범위를 기준으로 샤드를 할당합니다.

    if (playerId >= 1 && playerId <= 1000) {
        return 0; // 샤드 0
    } else if (playerId >= 1001 && playerId <= 2000) {
        return 1; // 샤드 1
    }
    // ...

해시 함수와 샤딩

샤딩 키를 분산시킬 때 해시 함수가 중요한 역할을 합니다. 좋은 해시 함수는 데이터를 여러 샤드에 균등하게 분배하여 특정 샤드에만 부하가 쏠리는 것을 막아줍니다. 마치 자바스크립트의 `Map`이 내부적으로 해시 테이블을 사용하여 키를 효율적으로 관리하는 것과 유사합니다.

해시 함수에서 다른 키가 같은 해시 값을 갖는 해시 충돌(Hash Collision)은 피할 수 없는 문제입니다. 따라서 충돌을 최소화하고 해시 값을 최대한 균등하게 분산시키는 것이 좋은 해시 함수의 핵심 덕목입니다. 샤딩에서도 마찬가지로, 데이터가 모든 샤드에 고르게 분산되지 않으면 샤딩의 의미가 퇴색됩니다.

생각지도 못했던 문제: 리샤딩(Resharding)

모듈로 기반 샤딩(playerId % NUM_OF_SHARDS)은 단순하지만 치명적인 문제가 있습니다. 바로 샤드의 수가 변경될 때입니다. 게임이 흥행하여 서버를 증설하거나, 혹은 반대의 이유로 축소해야 하는 상황을 가정해 봅시다. 샤드의 총 개수가 4개에서 3개로 줄어들면 어떻게 될까요?

playerId % 4로 계산되던 샤드 위치가 playerId % 3으로 바뀌면서, 대부분의 데이터가 원래 있던 샤드와 다른 샤드를 가리키게 됩니다. 이는 곧 대규모 데이터 재배치(Data Migration)를 의미하며, 이 과정에서 막대한 비용과 시스템 부하가 발생합니다.

기존 데이터를 그대로 두고 새로운 규칙을 적용하면 되지 않을까?

불가능합니다. 기존 사용자 데이터에 접근할 때도 새로운 규칙(playerId % 3)이 적용되므로, 데이터 이동 없이는 올바른 샤드를 찾을 수 없어 심각한 데이터 불일치 문제가 발생합니다.

샤드의 개수가 바뀔 때마다 이런 대공사가 발생한다면 매우 곤란합니다. 이 문제를 해결하기 위해 등장한 것이 바로 Consistent Hashing(안정 해시)입니다.

Consistent Hashing: 유연한 샤딩을 위한 해법

Consistent Hashing은 해시 링(Hash Ring)을 기반으로 동작하는 해싱 기법입니다. 데이터 키와 샤드 서버를 모두 동일한 해시 공간 위의 링에 배치합니다. 데이터는 링 위에서 시계 방향으로 가장 먼저 만나는 샤드에 저장됩니다.

이 방식의 가장 큰 장점은 샤드가 추가되거나 제거될 때 나타납니다. 샤드가 하나 제거되더라도, 영향을 받는 데이터는 제거된 샤드에 저장되어 있던 데이터에 한정됩니다. 나머지 데이터는 전혀 이동할 필요가 없어 데이터 재배치 비용을 최소화할 수 있습니다.

또한, 가상 노드(Virtual Nodes) 개념을 도입하면 데이터 분산을 더욱 균등하게 만들 수 있습니다. 하나의 물리적 샤드를 여러 개의 가상 노드로 만들어 링 전체에 흩뿌려 놓음으로써, 특정 샤드로 데이터가 편중될 위험을 줄일 수 있습니다.

샤딩의 어두운 면: 복잡성

샤딩은 성능과 확장성을 제공하지만, 그 대가로 엄청난 복잡성을 동반합니다.

분산 트랜잭션 (Distributed Transactions)

일반적인 트랜잭션은 단일 데이터베이스 내에서만 ACID 속성을 보장합니다. 하지만 샤딩 환경에서는 여러 데이터베이스에 걸쳐 데이터의 일관성을 유지해야 하는 경우가 발생합니다. 예를 들어, A 샤드에 있는 유저가 B 샤드에 있는 유저에게 아이템을 보내는 경우입니다.

이를 위해 분산 트랜잭션이 필요하며, 보통 Two-Phase Commit (2PC) 프로토콜을 사용합니다. 하지만 이 방식은 여러 데이터베이스와 통신해야 하므로 매우 느리고 복잡하며, 네트워크 장애 시 처리하기가 까다롭습니다. 이 때문에 메시지 큐나 SAGA 패턴과 같은 다른 접근법을 사용해 애플리케이션 레벨에서 트랜잭션을 구현하기도 합니다.

Cross-Shard JOIN

여러 샤드에 분산된 테이블들을 JOIN하는 쿼리는 매우 비효율적이고 복잡합니다. 각 샤드에서 필요한 데이터를 가져와 애플리케이션 레벨에서 조합해야 하므로, 성능 저하를 감수해야 합니다.

결론: 샤딩, 도입 전 반드시 확인할 체크리스트

샤딩은 강력한 기술이지만 명확한 단점 때문에 필요한 순간에 도입하는 것이 현명합니다. 샤딩 도입을 고려하기 전에 아래 체크리스트를 통해 스스로 점검해 보세요.

✨ 샤딩 도입 전 체크리스트 ✨

  • [ ] 데이터베이스의 크기가 단일 서버로 처리하기 어려울 정도로 거대한가요?
  • [ ] 동시 접속자가 많아 단일 DB 서버의 커넥션 한계를 초과하고 있습니까?
  • [ ] 현재 데이터베이스의 성능이 부족하여 응답 시간이 길거나 처리 속도가 느린가요?
  • [ ] 복잡한 샤드 관리와 모니터링을 처리할 수 있는 기술적 역량과 리소스가 충분한가요?
  • [ ] 분산 트랜잭션, Cross-Shard Join 등의 복잡성을 감당하고 관리할 수 있습니까?

위 체크리스트에 자신 있게 '예'라고 답할 수 있을 때가 바로 샤딩 도입을 진지하게 고려할 시점입니다. 샤딩은 특정 상황에서 매우 유용한 기술이지만, 모든 문제의 해결책은 아니며 그로 인한 복잡성과 관리 부담도 충분히 고려해야 한다는 사실을 잊지 마세요.

'Daily Logs > TIL (Today I Learned)' 카테고리의 다른 글

개발자 구글링 올바르게 사용하는 방법  (1) 2025.06.23
대규모 서비스를 위한 백엔드 아키텍처 도구  (2) 2025.06.16
데이터베이스 인덱스  (1) 2025.06.14
DB part.7  (2) 2025.06.13
DB part.6  (4) 2025.06.12
  1. 샤딩(Sharding)의 등장
  2. 샤딩의 장점
  3. 샤딩 적용 방식
  4. 해시 함수와 샤딩
  5. 생각지도 못했던 문제: 리샤딩(Resharding)
  6. Consistent Hashing: 유연한 샤딩을 위한 해법
  7. 샤딩의 어두운 면: 복잡성
  8. 분산 트랜잭션 (Distributed Transactions)
  9. Cross-Shard JOIN
  10. 결론: 샤딩, 도입 전 반드시 확인할 체크리스트
'Daily Logs/TIL (Today I Learned)' 카테고리의 다른 글
  • 개발자 구글링 올바르게 사용하는 방법
  • 대규모 서비스를 위한 백엔드 아키텍처 도구
  • 데이터베이스 인덱스
  • DB part.7
Jcob.moon
Jcob.moon
반가워요~ 하루하루 꾸준히 코딩 작성하는 곳입니다 !!
  • Jcob.moon
    Pixelated Thoughts
    Jcob.moon
  • 전체
    오늘
    어제
    • HelloWorld (178)
      • Daily Logs (126)
        • TIL (Today I Learned) (65)
        • Algorithm Practice (55)
        • Dev Book Notes (6)
      • Deep Dives (36)
        • 문제 해결 (Troubleshooting) (3)
        • CS Fundamentals (22)
        • Career Prep (4)
        • Technical Notes (7)
      • Project Log (7)
      • Any (3)
      • Cooperation (5)
        • Github (2)
        • Conventions (1)
        • Git (1)
        • Postman (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
Jcob.moon
샤딩

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.