ASHD Dev_Blog

5&6. 분산 키 값 저장소 [SYS-study]

단일 서버 구조에서 사용자 수가 증가함에 따라 추가해야 할 설계

이재룡
이재룡 Jul 2, 2025


[ ch5. Hash key Rehash & Hash Ring ]

서버를 다중화 하면서 서버의 개수에 따라 해시 값을 serverIndex로 재분배해야함

  • 안정 해시 (stable hash) : 시간/위치에 제약되지 않고 동일한 해싱
  • 일관성 해시 (consistent hash) : 노드 수가 변경되어도 대부분의 키가 재배치되지 않는 해싱
 

해시 링(Hash Ring)

  • 서버 조회 : 해당 key로 부터 시계 방향에 가장 가까운 서버
  • 서버 추가 : 추가된 서버로부터 반시계 기준 다음 서버 사이의 key를 신규 서버로 재배치
  • 서버 삭제 : 삭제된 서버로 부터 반시계 방향에 있는 key를 시계방향 앞 서버로 재배치
    • (즉 key 반시계 방향 탐색 / 서버는 시계 방향 탐색)

⇒ 결과적으로 삭제와 생성을 반복하면, 서버와 서버 간격 즉 소유하고 있는 key의 개수가 불균등

 

가상노드 : 한개의 서버가 N개의 가상 노드를 가지도록 설계 (파티션)

  • 실제 아래 이미지에서 서버는 S0, S1뿐
  • 결과적으로 N이 충분히 크면 key가 고르게 분포 (uniform distribution)
  • 생성 및 삭제 메커니즘에서 중복되는 서버의 가상 노드가 붙어있을 경우 무시
 
 
 

[ 6-1. 분산 Key-Value 저장소 ]

CAP 정리 아래 : 3개는 모두 가질 수 없고 반드시 하나를 포기해야 함

  • Consistency : 일관성 : 어떤 노드는지 데이터 일관
  • Availability : 가용성 : 일부 노드의 장애가 발생해도 계속 동작
  • Partition tolerance : 파티션 감내 : 네트워크가 갈려도 계속 동작
Callout icon'
CA 시스템?
네트워크 장애는 피할 수 없으므로 CAP 정리에 따라 시스템은 반드시 파티션 감내가 필요!
 

핵심 기술

  1. 데이터 파티션 ⇒ Hash Ring 구조 그 자체
 
  1. 데이터 다중화 ⇒ 작업 서버 이후 N-1개의 서버에 복제
    1. Callout icon'
      매우 중요한 특성
      즉 Hash 값을 풀었을 때, S1이 나왔고, N이 3이면 S1, S2, S3만 해당 key를 가짐!
      즉, 한 데이터의 소유 서버는 연속적
 
  1. 데이터 일관성
      • 정족수 합의 (Quorum Consensus) : 1개의 서버를 중재자로 설정하고, 타 서버로 부터 N개의 성공 응답을 받으면 시스템 상 성공으로 간주
       
      • 강한 일관성 (Strong Consistency) : W[쓰기 성공]+R[읽기 성공] > N
        • Callout icon'
          왜 강한 일관성이 W+R>N?
          강한 일관성 : 항상 최신의 데이터를 읽는다! (낡은 데이터는 확인 불가)
          N = W+R일때 W가 아닌 R이 존재 가능 즉, 크다에서는 N중에 1은 W&R이 반드시 존재

          ⇒ 결국 강한 일관성은 한개의 최신데이터를 보장한다

          새로운 요청이 왔을때, N개중에 어떤 서버가 최신 데이터를 가지고 있는지는 어떻게 판별하지?

          ⇒ 데이터 버저닝!

       
      • 데이터 버저닝 (Vector Clock)
        • 데이터에 요청을 준 서버 번호와, 버전을 기록
        • 버전이 낮으면 최신버전을 쓰고, 버전이 충돌나면 깃허브 충돌 해결 하듯이! (사용자 해결 OR Timestamp 비교)
 
  1. 장애 감지
      • 멀티 캐스팅 (다중 연결) : 확실하지만, 비효율적
      • 가십 프로토콜 (Gossip Protocol)

      ⇒ 랜덤으로 서버에서 HearbeatCounter와 Time을 기록 / 응답이 없으면 주변 체크 / 장애 노드로 감지

 
  1. 장애 처리
      • 일시적 장애 처리 : 장애서버의 역할 W/R을 타 서버에 위탁 ⇒ 이후 변경 사항을 일괄 반영
        • Callout icon'
          [Hinted handoff]
          ⇒ 아래와 같은 Hint(일괄 반영할 데이터 기록)을 큐에 저장하고, 지속적으로 부활 확인

          {
          "target_node": "S2", // 누구 거였는지
          "key": "user:123", // 어떤 데이터를
          "value": "Alice", // 실제 값
          "timestamp": 1723456789123, // 언제 쓰기 시도됐는지
          "ttl": 3600000 // 얼마나 보관할지
          }

      • 영구 장애 처리 : 반 엔트로피 프로토콜 ⇒ 없어진 데이터를 찾고 다른 서버에 복원
        • Callout icon'
          [Merkle Tree]
          • 서버를 버킷으로 나누고
          • 각 버킷의 해시를 이용해서 uniform hash 연산
            • ⇒ Hash( key + value + timestamp/version ) : 버전이 있어야 덮어쓰기 가능

          • 이를 트리형태로 루트노드까지 해싱
          • 루트노드부터 값을 비교하면 데이터가 다른 위치를 파악 가능

          ⇒ 결국 장애가 발생한 서버가 어떤 키를 가져야할지는 백업정보 혹은 키 자체의 serverIndex 연산으로 알 수 있음

        • 장애난 서버와 같은 데이터를 덮어쓰기한 이후 N-1개의 서버와 차이나는 데이터를 복구해야하는데 이때 비교를 편하게 할 수 있는게 “Merkle Tree”
 

추천 글

BlogPro logo