본문 바로가기
1. K8s Core & Architecture/1.1. 컨트롤 플레인 (Control Plane) 심층 분석

etcd 데이터베이스 조각화(Defragmentation) 원리와 유지보수 방법

by K8s Architect 2026. 3. 18.

etcd 데이터베이스 조각화(Defragmentation) 원리와 유지보수 방법

1. MVCC 아키텍처와 공간 단편화(Fragmentation)의 발생 원인

etcd가 고성능 읽기를 보장하면서도 다수의 컨트롤러가 쏟아내는 동시 쓰기 요청을 안전하게 처리할 수 있는 핵심 기술은 다중 버전 동시성 제어(MVCC) 아키텍처입니다. etcd는 키(Key)에 대한 수정이나 삭제 요청이 들어왔을 때 기존 데이터를 물리적으로 덮어쓰거나 즉시 삭제하지 않습니다. 대신 리비전(Revision)이라는 전역 논리 시계를 증가시키며 새로운 버전의 데이터를 추가로 기록합니다. 이를 통해 잠금(Lock) 없이 과거 데이터를 조회할 수 있는 강력한 이점을 얻습니다.

하지만 이러한 아키텍처는 치명적인 부작용을 동반합니다. 변경이 잦은 클러스터(예: 파드가 수시로 생성/삭제되거나 리더 선출 이벤트가 빈번한 환경)에서는 보존할 필요가 없는 과거 리비전 데이터가 디스크에 기하급수적으로 쌓이게 됩니다.

etcd의 백엔드 스토리지 엔진인 bbolt는 내부적으로 B+Tree 구조를 사용하여 데이터를 페이지(Page) 단위로 저장합니다. Kube-apiserver가 주기적으로 오래된 리비전을 정리하는 컴팩션(Compaction) 작업을 수행하면, 해당 과거 데이터들은 논리적으로는 삭제 처리됩니다. 그러나 bbolt 엔진의 특성상 논리적으로 삭제된 공간(Free Page)은 향후 새로운 데이터를 기록하기 위해 내부적으로 재사용 가능 상태로 표시될 뿐, 실제 OS 파일 시스템 레벨에서 물리적인 데이터베이스 파일(.db)의 크기가 줄어들지는 않습니다.

데이터가 기록되었다가 삭제되는 과정이 반복되면, 파일 내부에 사용 중인 페이지와 빈 페이지가 마치 스위스 치즈처럼 뒤섞이는 '내부 단편화(Internal Fragmentation)' 현상이 발생합니다. 파일 크기는 계속 커져 있는데 실제 유효한 데이터는 절반도 안 되는 비효율적인 상태가 누적되는 것입니다.

2. 공간 고갈(NOSPACE) 장애와 클러스터 마비

etcd는 무한정 스토리지를 소모하여 노드의 전체 디스크를 마비시키는 것을 방지하기 위해 데이터베이스 크기에 엄격한 쿼터(Quota)를 설정해 둡니다. 기본값은 2GB이며, 대규모 클러스터에서는 최대 8GB까지 확장하여 사용합니다.

단편화를 방치하여 물리적 파일 크기가 이 쿼터 한계치에 도달하면, etcd는 스스로 보호 모드에 돌입하며 alarm: NOSPACE 경보를 발생시킵니다. 이 순간 클러스터에 발생하는 파급 효과는 다음과 같습니다.

  • 읽기 전용 상태 전환: etcd 클러스터는 즉시 읽기 전용(Read-only) 모드로 전환되어 어떠한 쓰기 작업도 수용하지 않습니다.
  • API 서버 쓰기 실패: 파드 생성, 서비스 수정, 시크릿 업데이트 등 상태를 변경하려는 사용자의 모든 kubectl 명령이 거부됩니다.
  • 내부 컨트롤 루프 정지: Kubelet이 노드의 상태(NodeStatus)를 업데이트하지 못하고, 스케줄러가 파드를 노드에 바인딩하지 못하며, 컨트롤 플레인의 리더 선출 하트비트가 기록되지 않아 클러스터 전체의 오케스트레이션 기능이 완전히 마비됩니다.

3. 컴팩션(Compaction)과 조각 모음(Defragmentation)의 역할 차이

이러한 재플을 막기 위해서는 두 가지 유지보수 메커니즘이 반드시 상호 보완적으로 작동해야 합니다. 이 둘의 차이를 명확히 이해하는 것이 운영의 핵심입니다.

  • 컴팩션 (Compaction): 과거 리비전의 데이터를 '논리적'으로 삭제하는 작업입니다. Kube-apiserver는 기본적으로 5분마다 etcd에 컴팩션을 요청하여 오래된 이력을 제거합니다. 컴팩션이 수행되면 etcd 내부의 가용 공간(Free Page)이 늘어나지만, 물리적인 디스크 용량은 반환되지 않습니다.
  • 조각 모음 (Defragmentation): 컴팩션으로 인해 발생한 파일 내부의 구멍(빈 페이지)들을 물리적으로 제거하여 실제 디스크 공간을 회수하는 작업입니다. etcd는 백그라운드에서 임시 파일을 새로 생성하고, 기존 데이터베이스에서 유효한 데이터만을 순차적으로 읽어 임시 파일에 촘촘하게 쓴 뒤, 원본 파일을 이 압축된 새 파일로 교체합니다.

즉, Kube-apiserver가 자동으로 수행하는 컴팩션만으로는 파일 크기 증가를 막을 수 없으며, 관리자가 정기적으로 조각 모음(Defrag) 명령을 실행해주어야만 쿼터 초과를 예방할 수 있습니다.

4. 프로덕션 환경의 안전한 조각 모음(Defrag) 실행 전략

조각 모음 작업(etcdctl defrag)은 실행되는 동안 막대한 디스크 I/O와 CPU를 소비하며, 가장 치명적인 점은 작업이 진행되는 동안 해당 노드의 모든 읽기/쓰기 요청 처리가 완전히 차단(Block)된다는 것입니다.

만약 클러스터의 리더(Leader) 노드에서 무턱대고 디프래그를 실행하면, 리더가 차단된 동안 팔로워(Follower) 노드들이 하트비트를 받지 못해 리더가 죽었다고 판단하고 강제로 리더 선출(Leader Election)을 트리거합니다. 이는 클러스터 전체에 수 초에서 수십 초간의 일시적인 가용성 저하를 유발합니다. 따라서 다중 노드로 구성된 프로덕션 환경에서는 반드시 다음과 같은 무중단 순차 실행 전략을 따라야 합니다.

1단계: 현재 리더 및 노드 상태 파악
모든 etcd 노드의 엔드포인트를 대상으로 상태를 조회하여 현재 누가 리더 역할을 수행 중인지 정확히 식별합니다. (IS_LEADER 필드 확인)

2단계: 팔로워(Follower) 노드 순차 디프래그
리더가 아닌 팔로워 노드들을 하나씩 순차적으로 조각 모음합니다. 팔로워 노드가 차단되더라도 리더가 정상 작동하므로 클러스터의 읽기/쓰기 서비스에는 전혀 지장이 없습니다. 한 노드의 작업이 완전히 끝난 것을 확인한 후 다음 팔로워 노드로 넘어갑니다.

3단계: 리더 권한 이전(Move Leader)
모든 팔로워 노드의 최적화가 끝났다면, 마지막 남은 리더 노드를 작업하기 전에 선제적으로 조치를 취해야 합니다. 기존 리더 노드에서 etcdctl move-leader 명령을 사용하여, 이미 최적화가 끝난 건강한 팔로워 노드 중 하나로 리더 권한을 수동으로 안전하게 넘겨줍니다(Transfer).

4단계: 구 리더(현 팔로워) 노드 디프래그
권한을 넘겨주고 팔로워로 강등된 마지막 노드에 대해 디프래그를 실행합니다. 이 과정을 통해 단 한 번의 클러스터 장애나 불필요한 리더 선출 경쟁 없이 전체 멤버의 물리적 디스크 공간을 완벽하게 회수할 수 있습니다.

5. 이미 공간 고갈(NOSPACE) 장애가 발생했을 때의 복구 절차

만약 사전 유지보수에 실패하여 쿼터 초과 알람이 발생하고 클러스터가 멈췄다면, 다음 절차를 통해 신속하게 복구해야 합니다.

  1. 현재 리비전 확인: 현재 etcd의 리비전을 조회합니다.
  2. 수동 컴팩션 실행: 확인된 리비전을 기준으로 그 이전의 모든 이력을 논리적으로 삭제하는 강제 컴팩션을 실행합니다.
  3. 조각 모음(Defrag) 실행: 모든 노드에 대해 디프래그를 실행하여 물리적 여유 공간을 확보합니다.
  4. 알람 해제(Disarm): 디스크 공간이 정상적으로 확보되었더라도 etcd는 스스로 알람을 해제하지 않습니다. 관리자가 명시적으로 etcdctl alarm disarm 명령을 실행하여 NOSPACE 알람을 해제해야만 클러스터가 다시 읽기/쓰기 가능 상태로 전환되며 시스템이 정상화됩니다.

6. 모니터링 체계와 자동화 파이프라인 구축

가장 이상적인 운영은 사람이 개입하기 전에 시스템이 스스로 단편화를 관리하는 것입니다. 이를 위해 프로메테우스(Prometheus)를 활용한 지속적인 모니터링과 크론잡(CronJob) 기반의 자동화 파이프라인이 필수적입니다.

핵심 모니터링 메트릭:

  • etcd_mvcc_db_total_size_in_bytes: 실제 OS 디스크에 기록된 물리적 데이터베이스 파일의 크기입니다. 이 값이 쿼터에 근접하는지 감시해야 합니다.
  • etcd_mvcc_db_total_size_in_use_in_bytes: 논리적으로 실제 유효한 데이터가 차지하는 크기입니다.
    이 두 메트릭의 차이가 바로 '단편화로 인해 낭비되고 있는 빈 공간'입니다. 낭비되는 공간의 비율이 50%를 초과하거나, 물리적 파일 크기가 쿼터의 70%를 넘어서는 시점을 임계치(Threshold)로 설정하여 얼럿을 발생시켜야 합니다.

자동화 (Defrag CronJob):
쿠버네티스 내부에 CronJob 리소스를 생성하여 매주 주말 새벽이나 트래픽이 가장 적은 시간대에 앞서 설명한 '리더 회피 순차 디프래그 로직'이 담긴 셸 스크립트를 주기적으로 실행하도록 구성합니다. 이를 통해 관리자의 수동 개입 없이도 etcd 데이터베이스를 항상 최적의 상태로 유지하고 치명적인 장애를 영구적으로 예방할 수 있습니다.