본문으로 바로가기

etcd가 정보를 기록하는 방식

PUT 하나가 raft 합의(WAL fsync × 과반)를 거쳐 MVCC 저장소(treeIndex + boltdb)에 리비전으로 적히기까지 — 같은 데이터가 디스크에 두 번 기록되는 이유를 20단계로 따라간다.

1 / 20클라이언트가 PUT(foo, bar)을 gRPC로 보냅니다. 쿠버네티스라면 kube-apiserver가 이 클라이언트입니다.etcd에 '수정'은 없습니다. 모든 쓰기는 새 리비전을 만드는 추가(append)입니다 — MVCC의 출발점입니다.
리더 노드팔로워 1팔로워 2클라이언트kubectl · clientv3gRPC 서버etcdserverraft 모듈합의 상태 기계WALfsync 순차 기록적용 계층커밋된 엔트리 소비treeIndex키 → 리비전 (메모리 B-tree)boltdb리비전 → 값 (디스크 B+tree)raft 모듈팔로워WALfsyncraft 모듈팔로워WALfsyncPUT foo=bar
단계 목록 · 키보드 ←/→ 이동, Space 재생

출처: etcd 공식 문서 — Data model · etcd 공식 문서 — KV API guarantees · In Search of an Understandable Consensus Algorithm (Raft 논문)

etcd의 기록은 2막이다 — 1막 합의(WAL: 잃지 않기 위한 디스크), 2막 적용(boltdb: 찾기 위한 디스크). 그 사이에 raft 과반이 있다.

왜 헷갈리는가

'etcd에 저장했다'는 말이 실제로는 두 개의 서로 다른 디스크 기록을 뜻한다는 것이 첫 번째 혼동이다. WAL은 순서를 잃지 않으려는 추가 전용 로그이고, boltdb는 리비전으로 찾아 읽는 B+tree다. 두 번째 혼동은 응답을 못 받은 쓰기의 운명 — 실패가 아니라 '미확정'이며, 과반에 복제됐다면 다음 리더가 커밋한다. 그래서 재시도는 멱등해야 한다.

애니메이션이 보여주는 것

kubectl apply 한 번이 etcd 관점에서 어떻게 보이는지다. gRPC로 들어온 PUT이 raft 제안이 되고, 리더와 팔로워가 각자 WAL에 fsync한 뒤에야 ack하고, 과반이 모이면 커밋 인덱스가 전진한다. 여기까지가 1막 — 이 시점부터 이 쓰기는 어떤 장애에도 사라지지 않는다.

2막은 적용이다. 전역 단조 증가 리비전이 발급되고, 메모리의 treeIndex가 키→리비전을, 디스크의 boltdb가 리비전→값을 기록한다. 응답 헤더에 리비전이 실리고, 이 키를 watch하던 컨트롤러들에게 이벤트가 발행된다 — 쿠버네티스 조정 루프(reconcile loop)가 도는 원리다.

왜 키→값이 아니라 키→리비전→값인가

etcd는 MVCC다. 쓰기는 덮어쓰기가 아니라 새 리비전의 추가이고, 옛 리비전은 컴팩션 전까지 남는다. 덕분에 '리비전 42 시점의 값'을 조회할 수 있고, watch가 끊겼다 재연결해도 리비전 번호로 놓친 이벤트를 되짚어 받을 수 있다.

대가는 공간이다. 컴팩션(쿠버네티스 기본 5분)과 조각 모음(defrag)을 하지 않으면 boltdb가 무한히 자란다 — etcd 운영 장애의 단골 원인이다.

  • treeIndex(메모리): 키 → 리비전 이력
  • boltdb(디스크): 리비전 → (키, 값, 메타데이터)
  • watch는 리비전 기반 — 재연결 시 이어받기 가능

fsync가 병목이 되는 이유

모든 쓰기가 리더와 과반 팔로워의 WAL fsync를 기다린다. 그래서 etcd의 쓰기 지연 하한은 '가장 느린 과반 노드의 디스크 fsync 시간 + 네트워크 왕복'이다. etcd 공식 문서가 SSD를 요구하고 디스크 지연 경보(wal_fsync_duration)를 두는 이유다.

읽기는 다르다. 선형화 읽기도 ReadIndex 확인(하트비트 왕복)만 필요하고 디스크를 기다리지 않는다. serializable 읽기는 그마저 없이 로컬에서 답한다 — 대신 아주 잠깐 낡은 값을 볼 수 있다.

기억할 것

  • 쓰기 = 합의(1막: WAL fsync × 과반) + 적용(2막: 리비전 → treeIndex → boltdb).
  • ack은 fsync 뒤에만 — '받았다'가 아니라 '디스크에 남겼다'가 약속이다.
  • 리비전은 전역 단조 증가 — 시점 조회와 watch 이어받기의 근거.
  • 응답 없는 쓰기는 실패가 아니라 미확정 — 재시도는 멱등하게.
  • 컴팩션·defrag는 선택이 아니라 운영 필수 — MVCC는 공간과 맞바꾼 기능이다.
etcd가 정보를 기록하는 방식 | KIE