"Amazon's Dynamo"를 읽고 나서 - 3. Sloppy Quorum

⚠️
이 글에서 다루는 Dynamo는 2007년 아마존 내부 시스템이다. AWS DynamoDB(2012년 출시)는 이를 기반으로 했지만, 관리형 서비스로서 많은 부분이 추상화되고 자동화되었다.

1. Traditional Quorum

$$R+W>N$$

이 조건이 보장되면 읽기와 쓰기는 반드시 하나 이상의 노드에서 교차한다. 따라서 최소한 한 노드는 최신 데이터를 가지고 있어 강한 일관성(Strong Consistency) 을 확보한다고 본다. 전통적인 Quorum 시스템은 정족수를 못 채우면 작업을 거부한다.

일반적인 Quorum 시스템에서 아래의 상황을 가정해 보자.

이 경우, 하나의 쓰기 요청은 반드시 3개의 복제본 중 최소 2개 이상에 성공해야만 “성공"으로 인정된다. 즉, 클라이언트가 어떤 데이터를 쓰더라도, 그 데이터는 적어도 두 개의 노드에 복제되어 있어야 한다는 뜻이다.

읽기의 경우에는 조건이 다음과 같다. 전통적인 Quorum 시스템에서는

$$ R + W > N $$

이 만족되어야 최신 데이터를 읽을 수 있다. 여기서는 $W = 2$, $N = 3$이므로

$$ R + 2 > 3 \quad \Rightarrow \quad R > 1 $$

즉, 읽기 정족수 $R$은 최소 2여야 한다. 따라서 읽기 요청을 처리할 때도 3개의 복제본 중 적어도 2개 노드로부터 응답을 받아야 최신성을 보장할 수 있다.

장애 상황을 가정해 보자. 만약 노드 2개가 동시에 다운된다면, 쓰기 요청의 경우 살아 있는 노드는 단 1개뿐이다. 하지만 쓰기를 성공으로 인정하려면 $W=2$개의 응답이 필요하다. 이 조건을 만족할 수 없으므로, 쓰기는 실패한다. 읽기 요청 마찬가지로, 읽기를 위해 $R=2$개의 응답이 필요하지만, 현재는 응답 가능한 노드가 1개뿐이다. 따라서 읽기도 실패한다.

전통적인 Quorum 시스템에서는 정족수 조건을 만족하지 못하면 요청을 거부한다. 강한 일관성을 확보하기 위해 치러야 하는 대가다. 시스템이 부분적으로만 장애가 발생해도 전체적으로 쓰기나 읽기가 불가능해질 수 있는 것. Dynamo가 원한 “Always Writable”과는 정면으로 충돌하는 바다. 이를 해결하기 위해 Dynamo는 “Sloppy Quorum"이라는 유연한 접근으로 가용성을 극대화했다.

2. Sloppy Quorum

“Dynamo uses a ‘sloppy quorum’; all read and write operations are performed on the first N healthy nodes from the preference list, which may not always be the first N nodes encountered while walking the consistent hashing ring.”

Dynamo는 이 한계를 극복하기 위해 Sloppy Quorum이라는 개념을 도입한다. 정족수를 원래 복제본 집합에서만 찾는 것이 아니라, 현재 살아 있는 노드 중에서 확보한다. 즉, 전통적 Quorum의 조건을 그대로 유지하되, 노드 장애 상황에서는 유연하게 대체 노드로 확장하는 방식이다.

  1. Preference list: 각 키 $K$는 미리 정해진 복제본 후보 리스트(preference list)를 가지고 있다. 예를 들어 $K$의 preference list가 $[A, B, C]$라면, 원래는 이 세 노드가 복제를 담당한다.

  2. 장애 상황: 만약 노드 $A$가 다운된 상태에서 쓰기 요청이 들어오면, 전통적인 Quorum 시스템에서는 쓰기 실패로 처리된다. 그러나 Sloppy Quorum에서는 다음으로 건강한 노드가 대신 복제를 맡는다.

  3. 대체 저장: 예를 들어 노드 $D$가 살아 있다면, 클러스터는 $D$를 임시 복제본으로 선택하여 데이터를 저장한다. 이때 단순히 데이터를 저장하는 것에 그치지 않고, 메타데이터에 “이 데이터는 원래 $A$의 것이며, 나중에 복구되면 $A$에게 전달해야 한다”라는 힌트(hint)를 함께 기록한다.

3. Hinted Handoff: 임시 보관과 전달

Hinted Handoff의 작동 과정:

  1. $D$는 힌트가 달린 레플리카를 별도 로컬 DB에 보관
  2. 주기적으로 $A$의 복구 여부 확인
  3. $A$가 복구되면 데이터 전달
  4. 전달 성공 시 $D$는 로컬 사본 삭제

이 메커니즘으로 Dynamo는 일시적 장애를 우아하게 처리한다. 전체 시스템의 레플리카 수는 유지되면서도 가용성은 극대화된다.

4. Configuration

Dynamo는 서비스마다 읽기 빈도, 쓰기 빈도, 내구성지연(latency) 요구 사항에 따라 $N, R, W$ 값을 조정할 수 있게 설계되었다. 클라이언트 애플리케이션 또는 운영자가 이 세 파라미터를 “튜닝(tune)”함으로써 자신이 원하는 수준의 성능, 가용성, 내구성을 실현할 수 있다.

논문에서 “일반적인 Dynamo 사용자”들이 많이 사용하는 $N$ 값은 3이다. 복제본 개수 $N=3$은 서비스 안정성과 내구성(Durability) 면에서 균형이 괜찮은 선택으로 여겨졌다. 쓰기/읽기 정족수 $W$와 $R$는 이 $N$을 기반으로 여러 조합이 가능하다.

읽기가 많고 업데이트(Write)가 적은 서비스 유형에서는 읽기 응답 시간을 최소화하는 것이 중요하므로, 보통 $R=1$로 설정한다. 이때 $W$는 $N$으로 설정해 쓰기 복제본 모두에게 데이터를 보내게 한다. 이런 설정은 제품 카탈로그, 프로모션 항목 등 주로 읽기 중심(Read-Heavy)인 서비스에 적합하다.

또한 “항상 쓰기가 가능한(Always Writeable)” 특성이 필요한 서비스들에서는 $W$ 값을 가능한 낮게 (예: $W=1$) 설정할 수 있다. 이렇게 하면 시스템 내 어떤 노드 하나만 정상이라도 쓰기 요청을 수락할 수 있다. 하지만 이럴 경우 일관성(Consistency)과 내구성(Durability)의 취약성(Vulnerability)이 증가한다는 위험이 존재함이 논문에서 명확히 언급된다. $W$와 $R$ 값이 낮을수록, 정족수를 아직 확보하지 못한 상태에서도 클라이언트에게 성공 응답을 반환하게 되어 불일치(stale data 반환 가능성) 및 내구성 손실의 가능성이 생긴다.

논문에서 가장 많이 사용된 균형 조합은 $(N,R,W) = (3,2,2)$이다. 이 설정은 읽기/쓰기 모두에 대해 어느 정도의 응답성(Latency)과 최신성(Consistency), 그리고 내구성 및 가용성 SLA(Service Level Agreement)를 동시에 만족시킨 것으로 보고된다.


Dynamo는 전통적인 Quorum의 강한 일관성보다는 가용성과 내구성을 우선시하도록 설계되었다. 이를 위해 Sloppy Quorum과 Hinted Handoff를 도입하여, 노드나 네트워크 장애가 발생하더라도 읽기와 쓰기가 실패하지 않도록 했다. 실제로 Amazon 내부 서비스에서는 데이터 특성과 비즈니스 요구에 따라 $N, R, W$ 값을 조정해, 읽기 지연을 최소화하거나 쓰기 내구성을 높이는 등 커스터마이즈가 가능하다.

이와 같은 접근 덕분에 Dynamo는 항상 쓰기 가능(Always Writable)하며, 단일 노드나 데이터센터 장애에도 안정적으로 데이터를 보관하고 서비스할 수 있다.


comments powered by Disqus