시스템 아키텍쳐 스터디

제 6장 - 키, 값 저장소 설계

parangofsky 2025. 9. 28. 19:32

이번 포스트는 제 6장에 대해서 정리할 것입니다. 예측 내용은 비관계형 데이터베이스에 관한 내용입니다.

 

서론

 

키 값 저장소는 비 관계형 데이터베이스다. 이 저장소에 pk 값처럼 고유 식별자를 키로 가져야 하고 이러한 관계를 키 - 값 pair라고 한다.

 

 

형태

키 - 값

 

  • 키는 유일해야 하고 값은 키를 통해서만 접근할 수 있다.
  • 키는 텍스트, 해시 값 모두 가능하다. 짧을 수록 좋다. 
  • 값은 문자열 or 리스트, 객체 

키 - 값을 쓰는 데이터베이스는 흔히 알고 있는 Redis, DynamoDB, memcached(단순 캐시용)가 있다.

 

설계 실습

put : 저장

get : 값 꺼내기

 

설계 실습에 앞서 키-값 크기는 10KB 이하, 큰 데이터를 저장,  높은 가용성, 확장성, 데이터 일관성 조절 가능, 응답 지연 시간 짧은 범위를 목표로 실습할 것이다.

 

단일 서버 저장소

1. 키-값 쌍을 메모리 해시 테이블로 저장

1-1. 데이터 압축

1-2. 자주 쓰이는 데이터만 메모리에 두고 나머지는 디스크 저장.

 

이제 분산 서버로 확장할 것이다.

 

분산 서버 저장소

 

 

CAP 정리.

 

cap 정리란 데이터 일관성, 가용성, 파티션 감내를 동시에 만족하는 분산 시스템을 설계하는 건 불가능하다는 이론이다. 즉, 셋 중 하나는 반드시 희생되어야 한다는 의미이다.

 

 

데이터 일관성 : 어떤 노드를 접속 하든지 일관된 데이터를 보는 것.

가용성 : 어떤 노드에 장애가 발생해도 항상 응답을 받을 수 있는 것.

파티션 감내 : 두 노드의 통신 장애가 생겨도 시스템은 계속 동작되어야 하는 것.

 

 

분산 시스템의 데이터는 여러 노드에 복제되어 있다. 

 

   n1

 

n2                              n3

 

노드가 이렇게 존재할때, n3에서 오류가 발생하면 n3의 데이터는 n1, n2 는 업데이트 되지 못한 채 존재하게 된다.

 

CP : 일관성 - 파티션 감내 

-> 가용성 대신 일관성을 선택

-> n1, n2에 대한 쓰기 연산을 중단

-> n3이 복구될 때까지 일부 기능 중단

-> 은행 시스템에서 데이터 정확성이 절대적으로 중요할 경우

 

AP : 가용성 - 파티션 감내

-> 오래된 데이터를 반환할 위험이 있더라도 계속 쓰기 연산을 허용

-> 일시적으로 노드 간 데이터 불일치가 발생

-> n3가 복구된 후, 새 게시물 데이터가 n3에 동기화

-> 콘텐츠 플랫폼 서비스 경우 적합

 

CA : 일관성 - 가용성

 

시스템 컴포넌트

- 데이터 파티션 

-> 데이터를 여러 서버에 고르게 분산

-> 노트가 추가, 삭제될 때 데이터 이동 최소화

 

- 데이터 다중화

-> 데이터를 N개 서버에 비동기적으로 다중화

-> 시계 방향으로 돌면서 서버에 데이터 사본 보관

 

- 데이터 일관성

-> 여러 노드에 다중화된 데이터는 동기화 되어야 한다.

-> 정족수 합 프로토콜 사용하여 읽기, 쓰기 연산에 일관성 보장

  • N: 총 복제본 수
  • W: 쓰기 연산 정족수, 쓰기 연산이 성공한 것으로 간주되려면 적어도 W개의 서버로부터 연산이 성공했다는 응답을 받아야 한다.
  • R: 읽기 연산 정족수, 읽기 연산이 성공한 것으로 간주되려면 적어도 R개의 서버로부터 연산이 성공했다는 응답을 받아야 한다.

예를 들어 N=3, W=1의 의미는 쓰기 연산이 성공했다고 판단하기 위해서는 중재자는 최소 한대 서버로 부터 쓰기 성공 응답을 받아야 한다는 뜻이다. 따라서 n1으로부터 성공 응답을 받았다면 n0, n2로 부터의 응답은 기다릴 필요가 없다.

 

-> 중재자는 클라이언트와 노드 사이의 프락시 역할

 

W, R, N을 정하는 방법 :

W, R, N을 정하는 것은 응답 지연과 데이터 일관성 사이의 타협점을 찾는 과정과 같다.

  • R=1, W=N: 빠른 읽기 연산에 최적화된 시스템
  • W=1, R=N: 빠른 쓰기 연산에 최적화된 시스템
  • W+R>N: 강한 일관성이 보장됨(보통 N=3, W=R=2)
  • W+R<=N: 강한 일관성이 보장되지 않음


일관성 모델

  • 강력한 일관성(Strong Consistency): 가장 최근에 갱신된 결과를 반환. 늘 최신 데이터를 반환.
    • 방법: 모든 사본에 현재 쓰기 연산의 결과가 반영될 때 까지 해당 데이터에 대한 읽기/쓰기를 금지
    • 문제: 고가용성 시스템에는 적합 x
  • 약한 일관성(Weak Consistency): 읽기 연산은 가장 최신 데이터를 반환하지 못할 수 있다.
  • 최종 일관성(Eventual Consistency): 약한 일관성의 한 형태로 업데이트 후에 결국에는 일관성 있는 상태로 반영된다.
    • 문제: 쓰기 연산이 병렬적으로 발생하면 시스템에 저장된 값의 일관성이 깨질 수 있다.
    • 해결 방법: 클라이언트측에서 데이터의 버전 정보를 활용해 일관성이 깨진 데이터를 읽지 않도록한다.

- 일관성 불일치 해소(inconsistency resolution) (데이터 버저닝, 벡터시계)

데이터 버저닝은 각 데이터 업데이트에 고유한 버전 번호를 부여한다.

 

-> 문제 : 버전 1, 버전2의 값이 다를 때

-> 해결 : 벡터시계

 

백터시계는 [서버, 버전]의 순서쌍을 데이터에 함께 저장하는 것

 

-> 문제 : 1. 충돌 감지, 해소하는 로직이 클라이언트에 들어가 있음. 구현 복잡 2. [서버 : 버전] 순서쌍 개수가 매우 빠르게 늘어남

-> 해결 : 길이에 임계치 설정. 오래된 순서쌍을 백터 시계에서 제거. (충돌 버전 선후관계기 비정확해질 수 있고 해소 과정의 효율성이 낮아지지만 아직 그런 문제를 발견한 적이 없다고 함. )

 

- 장애 처리

  • 장애 감지 (Failure Detection): 두 대 이상의 서버가 장애를 보고해야 실제 장애로 간주.
  • 장애 해소 (Failure Resolution)
  • 영구 장애 처리(Failure Resolution): 근본적인 해결책 필요

장애 감지

  • 멀티캐스팅
  • Gossip Protocol: 가십 프로토콜은 분산형 장애 감지 솔루션이다. 각 노드가 주기적으로 다른 노드에게 데이터를 노낸다. 노드가 예상 시간 안에 데이터를 보내지 않으면, 다른 노드들은 그 노드가 장애(오프라인) 상태인 것으로 간주한다.

일시적 장애 처리

Gossip Protocol로 장애를 감지한 시스템은 가용성을 보장하기 위해 필요한 조치를 해야한다.

 

방법:
엄격한 정족수 : 읽기 쓰기 연산 금지

느슨한 정족수 : 읽기, 쓰기 연산할 서버를 고른다. 

장애 서버로 가는 요청은 다른 서버가 맡아서 처리하고 변경사항은 서버가 복구 되었을 때 일괄 빈영한다. 이를 위해 임시 서버는 힌트를 남겨 두어야 한다. (임시 위탁)

 

영구 장애 처리

방법:

  • Anti-Entropy: 시스템의 다른 부분 간에 데이터 사본을 주기적으로 동기화하고 갱신한다. 사본 간의 일관성이 망가진 상태를 탐지하고 전송 데이터 양을 줄이기 위해 Merkle Trees가 사용된다.
  • Merkle Trees: 머클트리의 목적 은 빠른 검색이 아니라 데이터의 간편하고 확실한 인증 을 위해 사용하며 SHA-256(해시함수)를 사용한다.


- 시스템 아키텍처 다이어그램

분산 키-값 저장소의 전체적인 구조는 다음과 같다.

  • 클라이언트는 API(get, put)를 통해 시스템과 통신
  • 중재자(Coordinator)는 클라이언트와 노드 사이의 프록시 역할
  • 노드들은 안정 해시 링 위에 분포
  • 시스템은 완전히 분산되어 있어 노드의 자동 추가/삭제가 가능
  • 데이터는 여러 노드에 다중화되어 저장
  • 단일 장애점(SPOF)이 없는 구조


- 쓰기 경로(카산드라)

  1. 쓰기 요청이 커밋 로그 파일에 기록된다.
  2. 데이터가 메모리 캐시에 기록된다.
  3. 메모리 캐시가 가득차거나 사전에 정의된 어떤 임계치에 도달하면 데이터는 디스크에 있는 SSTable에 기록된다. SSTable은 Sorted-String Table의 약어로, <키, 값>의 순서쌍으로 정렬된 리스트 형태로 관리하는 테이블이다.


- 읽기 경로

읽기 요청을 받은 노드는 데이터가 메모리 캐시에 있는지 살핀다.

 

메모리캐시에 없을 때 디스크에서 가져오기 (블룸 필터 이용) -> SSTable에 키가 보관되어 있는지 알나 낸 후 데이터 반환