인터그레이티드 Raft 스토리지
인터그레이티드 Raft 스토리지 (Integrated Raft storage)
Vault는 내구성 있는 정보 저장을 위한 여러 옵션을 지원합니다. 각 백엔드는 장단점과 장점, 트레이드오프를 지닙니다. 예를 들어 일부 백엔드는 고가용성을 지원하고, 어떤 백엔드는 더 견고한 백업/복원 과정을 제공합니다. 인터그레이티드 스토리지는 제3자 시스템에 의존하지 않고 백업/복원 워크플로, 고가용성, Enterprise 복제 기능을 지원하는 "내장(built-in)" 스토리지 옵션입니다.
출처: 문서
본문
Raft 프로토콜 개요 (Raft protocol overview)
팁: "The Secret Lives of Data"는 Raft 스토리지에 대한 훌륭한 시각적 설명이 있습니다.
Raft 스토리지는 Paxos와 "Raft: In search of an Understandable Consensus Algorithm"의 연구에 기반한 합의 프로토콜을 사용해 CAP 일관성을 제공합니다.
Raft 성능은 디스크 I/O와 네트워크 지연에 의해 제약되며 Paxos와 비슷합니다. 안정적인 리더십 아래에서 로그 항목을 커밋하려면 피어 세트의 절반으로 왕복 한 번만 필요합니다.
Paxos와 비교해 Raft는 상태가 더 적고, 더 단순하며 이해하기 쉬운 알고리즘으로 설계되었으며 다음 요소에 의존합니다:
- 로그 (Log) — 클러스터 변경을 추적하는 정렬된 항목 시퀀스(복제된 로그)입니다. 예를 들어 데이터 쓰기는 새 이벤트이며 해당 로그 항목을 만듭니다.
- 피어 세트 (Peer set) — 로그 복제에 참여하는 모든 구성원의 집합입니다. 모든 서버 노드는 로컬 클러스터의 피어 세트에 있습니다.
- 리더 (Leader) — 어느 시점이든 피어 세트는 노드 하나를 리더로 선출합니다. 리더는 새 로그 항목을 받아들이고, 로그를 팔로워에게 복제하며, 항목을 언제 커밋할지 관리합니다. 리더는 로그 복제를 관리하며, 복제된 로그 항목의 불일치는 리더에 문제가 있음을 나타낼 수 있습니다.
- 쿼럼 (Quorum) — 피어 세트 구성원의 다수입니다. 크기가
N인 피어 세트에서 쿼럼은 최소ceil((N + 1) / 2)명의 구성원이 필요합니다. 예를 들어 5명 피어 세트의 쿼럼은 3개 노드가 필요합니다. 클러스터가 쿼럼을 달성하지 못하면 클러스터는 사용 불가해지고 새 로그를 커밋할 수 없습니다. - 커밋된 항목 (Committed entry) — 노드의 쿼럼에 복제된 로그 항목입니다. 로그 항목은 커밋된 후에만 적용됩니다.
- 결정적 유한 상태 머신 (DFSM) — 상태 간의 예측 가능한 전이가 있는 알려진 상태들의 모음입니다. Raft에서 DFSM은 새 로그가 적용될 때마다 상태 간에 전이합니다. DFSM 규칙에 따라 같은 로그 시퀀스를 여러 번 적용하면 항상 같은 최종 상태가 되어야 합니다.
노드 상태 (Node states)
Raft 노드는 항상 다음 상태 중 하나입니다:
- follower — 모든 노드는 follower로 시작합니다. Follower는 리더로부터 로그 항목을 받아들이고 리더 선출을 위해 투표합니다.
- candidate — 노드는 주어진 시간 동안 로그 항목을 받지 못하면 스스로 candidate 상태로 승격합니다. 자기 승격 중에 candidate는 나머지 피어 세트로부터 투표를 요청합니다.
- leader — 노드는 candidate로서 쿼럼의 투표를 받으면 leader가 됩니다.
로그 쓰기 (Writing logs)
Raft에서 로그 항목은 불투명한 이진 blob입니다. 피어 세트가 리더를 선출하면 피어 세트는 새 로그 항목을 받아들일 수 있습니다. 클라이언트가 세트에 새 로그 항목 추가를 요청하면 리더는 그 항목을 내구성 스토리지에 쓰고 팔로워의 쿼럼에 데이터를 복제하려 시도합니다. 로그 항목이 커밋되면 리더는 그 로그 항목을 결정적 유한 상태 머신에 적용해 클러스터 상태를 유지합니다.
Vault의 Raft: Vault는 BoltDB 또는 WAL Raft를 결정적 유한 상태 머신으로 사용하며, 쓰기가 커밋되고 적용될 때까지 쓰기를 차단합니다.
로그 압축 (Compacting logs)
복제된 로그의 무한한 증가를 피하기 위해 Raft는 현재 상태를 스냅샷으로 저장한 다음 연결된 로그를 압축합니다. 유한 상태 머신이 결정적이므로 DFSM 스냅샷을 복원하면 항상 스냅샷과 연결된 로그 시퀀스를 재생한 것과 같은 상태가 됩니다. 스냅샷을 찍으면 Raft는 어느 시점의 DFSM 상태를 포착하고 그 상태에 도달하는 데 사용된 로그를 제거할 수 있으므로 로그 데이터를 압축합니다.
Vault의 Raft: Vault는 디스크 사용이 무한정 커지는 것을 막고 로그 재생에 소요되는 시간을 최소화하기 위해 로그를 자동으로 압축합니다. DFSM으로 BoltDB를 사용하면 Vault 데이터가 이미 BoltDB의 디스크에 영속화되어 있으므로 Vault 스냅샷도 가볍게 유지됩니다. 스냅샷 과정은 Raft 로그를 잘라내기만 하면 됩니다.
쿼럼 (Quorum)
피어 세트에 쿼럼이 있으면 Raft 합의는 내결함성(fault-tolerant)을 가집니다. 그러나 노드의 쿼럼을 사용할 수 없으면 피어 세트는 로그 항목을 처리하거나, 리더를 선출하거나, 피어 멤버십을 관리할 수 없습니다.
예를 들어 피어가 A와 B 두 개만 있다고 가정해 봅시다. 쿼럼을 가지려면 두 노드 모두 참여해야 하므로 쿼럼 크기는 2입니다. 결과적으로 두 노드 모두 동의해야 로그 항목을 커밋할 수 있습니다. 노드 하나가 실패하면 남은 노드는 쿼럼에 도달할 수 없고, 피어 세트는 더 이상 노드를 추가/제거하거나 추가 로그 항목을 커밋할 수 없습니다. 피어 세트가 더 이상 조치를 취할 수 없게 되면 사용 불가해집니다. 피어 세트가 사용 불가해지면 실패한 노드를 제거하고 남은 노드를 부트스트랩 모드로 재시작해 스스로를 리더로 선출하게 함으로써 수동으로만 복구할 수 있습니다.
Vault의 Raft 리더십 (Raft leadership in Vault)
단일 Vault 서버(노드)가 초기화되면 크기 1의 클러스터(피어 세트)를 만들고 스스로를 리더로 선출합니다. 클러스터에 리더가 생기면 추가 서버는 암호화된 challenge/answer 워크플로로 클러스터에 가입할 수 있습니다. 가입 과정이 작동하려면 단일 Raft 클러스터의 모든 노드가 같은 봉인 구성(seal configuration)을 공유해야 합니다. 클러스터가 자동 봉인 해제(auto-unseal)를 사용하도록 구성되면 가입 과정은 구성된 봉인으로 challenge를 자동으로 복호화하고 answer로 응답합니다. Shamir 봉인 같은 다른 봉인 옵션의 경우, 노드는 가입 전에 봉인 해제 키에 접근할 수 있어야 challenge를 복호화하고 복호화된 answer로 응답할 수 있습니다.
고가용성 구성에서 active Vault 노드가 리더 노드이고 모든 standby 노드는 follower입니다.
리더십 선거 (Leadership elections)
노드는 Raft 리더십 선거를 통해 Raft 리더가 됩니다. Raft 클러스터의 모든 노드는 follower로 시작합니다. Follower는 리더 하트비트를 통해 리더 건강 상태를 모니터링합니다. follower가 구성된 하트비트 타임아웃 내에 하트비트를 받지 못하면 그 노드는 candidate가 됩니다. Candidate는 클러스터의 다른 노드로부터 선거 알림을 관찰합니다. 선거 타임아웃 기간이 만료되면 candidate는 리더 선거를 시작합니다. candidate가 클러스터의 다른 노드 쿼럼으로부터 응답을 받으면 그 candidate는 새 리더 노드가 됩니다.
리더는 노드가 리더 임대 타임아웃 기간 내에 노드의 쿼럼에 연결하지 못하면 자발적으로 물러날 수 있습니다.
관련 타임아웃 기간(하트비트 타임아웃, 선거 타임아웃, 리더 임대 타임아웃)은 Vault 구성의 performance_multiplier 설정에 따라 배율이 조정됩니다. 기본적으로 performance_multiplier 는 5이며, 이는 다음 타임아웃 값으로 변환됩니다:
| 타임아웃 | 기본 기간 |
|---|---|
| 하트비트 타임아웃 (Heartbeat timeout) | 5초 |
| 선거 타임아웃 (Election timeout) | 5초 |
| 리더 임대 타임아웃 (Leader lease timeout) | 2.5초 |
다음 중 하나에 해당하지 않는 한 기본 배율을 사용할 것을 권장합니다:
- 플랫폼 텔레메트리가 기본 동작이 충분하지 않다고 강하게 나타내는 경우.
- 플랫폼이나 네트워크의 신뢰성이 다른 동작을 요구하는 경우.
BoltDB Raft 로그 (BoltDB Raft logs)
BoltDB는 단일 파일 데이터베이스이므로 데이터를 삭제할 때 디스크의 파일을 줄여 공간을 회수할 수 없습니다. 대신 BoltDB는 삭제된 데이터가 저장된 위치를 "freelist"에 기록합니다. 이후의 쓰기에서 BoltDB는 데이터를 영속화할 새 공간을 할당하기 전에 freelist를 참조해 오래된 페이지를 재사용합니다.
BoltDB는 신중한 조정이 필요합니다.
- 변경이 많은(churn) Vault 클러스터에서 BoltDB freelist는 매우 커질 수 있고 데이터베이스 파일은 심하게 조각화될 수 있습니다. 큰 freelist와 조각화된 데이터베이스 파일은 BoltDB 트랜잭션을 느리게 만들어 Vault 클러스터 성능에 직접 영향을 줍니다.
- 바쁜 Vault 클러스터에서 새 follower가 리더로부터 후속 스냅샷을 받기 전에 Raft 스냅샷 동기화에 어려움을 겪으면, BoltDB 파일은 갑작스러운 쓰기 폭주에 취약합니다. 새 follower가 쿼럼에 가입하지 못할 뿐 아니라, 급격한 파일 증가를 위한 공간을 제공하지 않거나 과도하게 할당해 디스크 공간을 낭비하는 Vault 설치는 성능이 좋지 않을 가능성이 높습니다.
Write-ahead Raft 로그 (Write-ahead Raft logs)
| 라이브러리 | 파일 이름 | 저장 디렉터리 |
|---|---|---|
| raft-boltdb | raft.db | raft |
| raft-wal | wal-meta.db, XXXXXXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXX.wal | raft/wal |
실험적(Experimental): 실험적 기능은 테스트되었지만 검증되지 않았습니다. 생산(production) 사용을 통해 그 기능이 검증될 때까지 주의해서 진행하세요.
기본적으로 Vault는 Raft 로그를 저장하는 BoltDB용 raft-boltdb 라이브러리를 사용하지만, write-ahead Raft 로그에는 raft-wal 라이브러리를 사용하도록 Vault를 구성할 수도 있습니다.
raft-wal 라이브러리는 Raft 로그 저장을 위해 특별히 설계되었습니다. raft-boltdb 처럼 freelist를 사용하는 대신 raft-wal 은 데이터 저장소로 파일 디렉터리를 유지하며, 특정 파일이 더 이상 필요하지 않으면 시간이 지남에 따라 데이터를 압축해 공간을 확보합니다.
데이터를 디렉터리의 파일로 저장한다는 것은 raft-wal 라이브러리가, 잘리거나 압축되기 전에 리더가 보유하는 로그 수를 급격한 쓰기의 성능 저하 위험 없이 쉽게 늘리거나 줄일 수 있음을 의미하기도 합니다.
Vault의 쿼럼 관리 (Quorum management in Vault)
autopilot 사용 시 (With autopilot)
autopilot 기능으로 Vault는 노드를 쿼럼 목록의 적격 유권자로 간주하기 전에 노드가 건강한지 확인하기 위해 구성 가능한 파라미터 집합을 사용합니다.
autopilot은 기본적으로 활성화되며 클러스터에 가입하는 노드에 대한 안정화 로직을 포함합니다:
- 노드가 비유권자(non-voter)로 클러스터에 가입합니다.
- 가입한 노드가 현재 Raft 인덱스와 동기화합니다.
- 구성된 안정성 임계값이 충족되면 노드가 클러스터의 완전한 투표 구성원이 됩니다.
안정성 임계값이 적절한지 확인하세요: 안정성 임계값을 너무 낮게 설정하면 노드가 Raft 인덱스와 완전히 동기화되기 전에 투표를 시작할 수 있어 클러스터 불안정이 발생할 수 있습니다.
autopilot에는 죽은 서버 정리(dead server cleanup) 기능도 포함됩니다. Autopilot API로 죽은 서버 정리를 활성화하면 Vault는 수동 운영자 개입 없이 비정상 노드를 Raft 클러스터에서 자동으로 제거합니다.
autopilot 미사용 시 (Without autopilot)
autopilot 없이 노드가 Raft 클러스터에 가입하면, 그 노드는 리더로부터 받은 데이터를 복제하는 것만으로 피어 세트를 따라잡으려 시도합니다. 노드가 초기 동기화 상태에 있는 동안에는 투표할 수 없지만 쿼럼 목적에는 포함됩니다. 여러 노드가 동시에(또는 충분히 가까운 시간에) 클러스터에 가입하면 클러스터가 예상 내결함성을 초과하고, 쿼럼이 손실되며, 클러스터가 실패할 수 있습니다.
예를 들어 데이터가 많고 내결함성이 1인 3노드 클러스터를 고려해 봅시다. 3개 노드가 동시에 클러스터에 가입하면 클러스터 크기는 6이 되고 예상 내결함성은 2가 됩니다. 하지만 그중 3개 노드는 여전히 동기화 중이고 투표할 수 없으므로 클러스터는 쿼럼을 잃습니다.
autopilot을 사용하지 않는다면, 추가 노드를 추가하기 전에 모든 새 노드의 Raft 인덱스가 리더와 동기화되어 있는지(또는 매우 가깝게 동기화되어 있는지) 확인하는 것을 강력히 권장합니다. 현재 Raft 인덱스 상태는 vault status CLI 명령으로 확인할 수 있습니다.
쿼럼 크기와 내결함성 (Quorum size and failure tolerance)
아래 표는 다양한 클러스터 크기에 대한 쿼럼 크기와 내결함성을 비교합니다:
| 서버 수 | 쿼럼 크기 | 내결함성 |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
| 6 | 4 | 2 |
| 7 | 4 | 3 |
모범 사례: 최상의 성능을 위해 표준 프로덕션 배포에는 최소 내결함성 2를 유지하도록 최소 5대의 서버를 권장합니다. 또한 투표 교착(voting stalemate)을 피하기 위해 홀수 개 노드의 클러스터 유지를 권장합니다. 장애 시나리오에서 데이터 손실 위험이 높으므로 프로덕션용 단일 서버 배포는 강력히 권장하지 않습니다.
유지보수와 다른 변경 중에도 내결함성을 유지하려면 클러스터를 한 번에 2개 노드씩 순차적으로 확장하고 되돌리기를 권장합니다.
예를 들어 5노드 클러스터로 시작한다면:
- 클러스터를 7개 노드로 확장합니다.
- 새 노드가 가입되어 나머지 피어 세트와 동기화되었는지 확인합니다.
- 이전 노드 2개를 중지하거나 제거합니다.
- 이 과정을 2번 더 반복해 기존 노드의 나머지를 교체합니다.
Vault 인스턴스를 변경하거나 확장할 때 내결함성에 미치는 영향을 제한하려면 항상 쿼럼을 유지해야 합니다.
참고: 확장 이벤트 중에는 필요에 따라 피어를 조정해야 합니다. 클러스터 크기를 늘리거나 줄이려는 의도적인 확장 이벤트는 짧은 시간에 일어날 수 있기 때문입니다. 자동 서버 정리에 Autopilot을 사용한다면 이것을 고려하세요. 확장 시간 창이 기본
dead_server_last_contract_threshold보다 짧을 수 있으므로 이런 경우 이 값을 조정해야 합니다.
리던던시 존 (Redundancy Zones)
| 리던던시 존 | 존당 서버 수 | 쿼럼 크기 | 내결함성 | 낙관적 내결함성 |
|---|---|---|---|---|
| 2 | 2 | 2 | 0 | 2 |
| 3 | 2 | 2 | 1 | 4 |
| 3 | 3 | 2 | 1 | 7 |
| 5 | 2 | 3 | 2 | 7 |
리던던시 존과 함께 autopilot을 사용하면 총 서버 수는 위와 달라지며, 선택한 리던던시 존 수와 존당 서버 수에 따라 달라집니다.
클러스터에서 구성 변경에 동의하려면 투표 서버의 다수가 사용 가능해야 합니다. 투표 노드가 사용 불가해져 클러스터에 쿼럼 크기보다 적은 투표 노드가 남으면, Autopilot은 비유권자를 유권자로 승격할 수 없습니다. 이것이 클러스터의 내결함성입니다. 리던던시 존은 클러스터의 내결함성을 개선할 수 없습니다.
리던던시 존을 2개로 구성하고 각 존에 서버 2개(총 4개 노드)가 있다고 가정해 봅시다. 쿼럼 크기는 2입니다. 두 리던던시 존 중 하나의 zone voter가 사용 불가해지면 클러스터는 쿼럼이 없으며, 그 존의 비유권자를 유권자로 승격하는 데 필요한 구성 변경에 동의할 수 없습니다.
리던던시 존은 클러스터의 낙관적 내결함성(optimistic failure tolerance)을 개선합니다. 낙관적 내결함성은 정전(outage)을 일으키지 않고 점진적으로 실패할 수 있는 건강한 active 및 백업 투표 서버의 수입니다. Vault 클러스터가 투표 노드의 쿼럼을 유지할 수 있으면, 노드가 점진적으로 손실되고 대기 리던던시 존 노드를 유권자 자리를 대신하도록 승격할 수 있는 능력을 가집니다.
예를 들어 리던던시 존을 3개로 구성하고 각 존에 노드 2개가 있다고 생각해 봅시다. 투표 노드에 접근할 수 없게 되면 그 존의 대기 노드가 승격됩니다. 그러면 클러스터는 2개의 남은 대기 노드로 3개의 투표 노드를 유지합니다. 클러스터는 쿼럼을 잃기 전에 추가로 3번의 점진적 실패를 처리할 수 있습니다.
모범 사례: 리던던시 존을 사용하기로 한다면 내결함성을 보장하기 위해 최소 3개 존을 사용할 것을 강력히 권장합니다.