- 스냅샷이 무엇이고 어디에서 찾을 수 있는지
- 문제가 어떻게 나타나는지
- 가능한 복구 전략과 각 전략의 의미
Keeper 스냅샷 개요
스냅샷이란 무엇입니까?
스냅샷은 특정 시점의 Keeper 내부 데이터(예: 클러스터 관련 메타데이터, 테이블 조정 경로, 구성)를 직렬화한 상태입니다. 스냅샷은 클러스터 내 Keeper 노드의 재동기화, 장애 발생 시 메타데이터 복구, 그리고 정상 상태로 확인된 Keeper 상태에 의존하는 시작 또는 재시작 과정에 매우 중요합니다.스냅샷은 어디에서 찾을 수 있습니까?
스냅샷은 Keeper 노드의 로컬 파일 시스템에 파일 형태로 저장됩니다. 기본적으로/var/lib/clickhouse/coordination/snapshots/에 저장되며, keeper_server.xml 파일의 snapshot_storage_path에 지정한 사용자 지정 경로에 저장될 수도 있습니다. 스냅샷 이름은 증가하는 순서로 지정되며(예: snapshot.23), 최신 스냅샷일수록 숫자가 더 큽니다.
멀티 노드 클러스터에서는 각 Keeper 노드가 자체 스냅샷 디렉터리를 가집니다.
복구를 위해서는 노드 간 스냅샷의 일관성이 매우 중요합니다.
손상된 Keeper 스냅샷의 주요 증상과 징후
아래 표는 손상된 Keeper 스냅샷에서 흔히 나타나는 몇 가지 주요 증상과 징후를 보여줍니다:
로그 징후:
스냅샷 손상을 진단하기 전에 Keeper 로그에서 특정 오류 패턴을 확인하십시오:
손상된 Keeper 스냅샷에서 복구하기
파일을 건드리기 전에 항상 다음 사항을 수행하십시오:- 추가 손상을 방지하기 위해 모든 Keeper 노드를 중지합니다
- 전체 coordination 디렉터리를 안전한 위치에 복사해 모두 백업합니다
- 클러스터 정족수(quorum)를 확인하여 최소 1개의 노드에 정상 데이터가 있는지 검증합니다
- 기존 Backup에서 복원
다음에 해당하면 이 절차를 따르십시오:
- Keeper 메타데이터(metadata) 또는 스냅샷 손상으로 인해 현재 데이터를 복구할 수 없습니다.
- 정상 상태로 확인된 Keeper 상태가 포함된 Backup이 있습니다.
- 메타데이터 일관성을 기준으로 가장 최신 Backup을 찾아 검증합니다.
- ClickHouse 및 Keeper 서비스를 종료합니다.
- Backup 디렉터리의 스냅샷 및 로그로 손상된 항목을 대체합니다.
- Keeper 클러스터를 다시 시작하고 메타데이터 동기화가 정상인지 검증합니다.
- 이전 스냅샷으로 롤백
다음과 같은 경우 이 절차를 따르십시오.
- 최근 스냅샷이 손상되었지만, 이전 스냅샷은 여전히 사용할 수 있습니다.
- 일관된 복구에 필요한 증분 로그가 온전하게 유지되어 있습니다.
- Keeper 디렉터리에서 유효한 이전 스냅샷(예: snapshot.19)을 찾아 선택합니다.
- 더 최신 스냅샷과 로그를 제거합니다.
- Keeper를 다시 시작하여 로그를 재생하고 메타데이터 상태를 복구합니다.
SYSTEM RESTORE REPLICA를 사용해 메타데이터 복원
다음과 같은 경우 이 절차를 따르십시오.
SYSTEM RESTORE REPLICA를 사용해 메타데이터 복원- Keeper 메타데이터가 유실되었거나 손상되었지만 테이블 데이터는 여전히 디스크에 남아 있는 경우
- ZooKeeper/Keeper 메타데이터가 없어 테이블이 읽기 전용 모드로 전환된 경우
- 로컬에서 사용 가능한 데이터 파트를 기반으로 Keeper 메타데이터를 재생성해야 하는 경우
-
구성의
<path>로 설정된clickHouse-server데이터 경로에 테이블 데이터가 로컬에 존재하는지 확인하십시오. (기본값:/var/lib/clickhouse/data/) - 영향을 받는 각 테이블에 대해 다음을 실행하십시오:
- 데이터베이스 수준 복구를 수행하는 경우(Replicated 데이터베이스 엔진 사용 시):
- 동기화가 완료될 때까지 기다리십시오:
system.replicas에서is_readonly = 0인지 확인하고system.detached_parts를 모니터링하여 복구를 검증합니다
작동 방식
SYSTEM RESTORE REPLICA는 기존의 모든 파트를 detach한 뒤 Keeper에 메타데이터를 재생성한 다음(새 빈 테이블인 것처럼), 모든 파트를 다시 ATTACH합니다. 이렇게 하면 네트워크를 통해 데이터를 다시 다운로드하지 않아도 됩니다.
- Keeper에서 레플리카 메타데이터 삭제 및 재생성
다음과 같은 경우 이 절차를 따르십시오:
- 오류가 클러스터의 단일 레플리카에서 발생했고, Keeper의 메타데이터가 손상되었거나 일관되지 않은 경우
- “Part XXXXX intersects previous part YYYYY”와 같은 오류가 발생하는 경우
- 로컬 데이터는 유지하면서 레플리카의 Keeper 메타데이터를 완전히 재설정해야 하는 경우
- 영향을 받은 레플리카에서 테이블을 detach합니다:
- Keeper에서 레플리카의 메타데이터를 제거합니다(임의의 레플리카에서 실행):
- 테이블을 다시 ATTACH합니다(읽기 전용 모드로 전환됩니다):
- 레플리카 메타데이터를 복원합니다:
- 다른 레플리카와 동기화:
- 복구 후 모든 레플리카에서
system.detached_parts를 확인합니다
- ClickHouse 서버를 중지합니다
- 복구 플래그를 생성합니다:
- ClickHouse 서버를 시작합니다
- 서버가 자동으로 플래그를 삭제하고 모든 복제된 테이블을 복원합니다
- 로그를 확인하여 복구 진행 상황을 모니터링합니다
- Keeper 클러스터 재구축
다음과 같은 경우 이 절차를 따르십시오.
- 복구에 사용할 수 있는 유효한 스냅샷, 로그 또는 Backup이 없습니다.
- 전체 Keeper 클러스터와 해당 메타데이터를 다시 생성해야 합니다.
- ClickHouse 클러스터와 Keeper 클러스터를 완전히 중지합니다.
- 스냅샷 및 로그 디렉터리를 정리하여 각 Keeper 노드를 초기화합니다.
- Keeper 노드 하나를 리더로 초기화한 다음, 다른 노드를 순차적으로 추가합니다.
- 외부 기록이 있는 경우 메타데이터를 다시 가져옵니다.
- 시작 시 스냅샷에서 고아 노드 제거하기
고아(orphaned) 노드란 스냅샷에 부모 노드가 없는 노드를 말합니다. Keeper는 이러한 스냅샷의 로드를 거부하고 Failure to load from latest snapshot with index라는 로그를 남깁니다.
이 절차는 다음 조건에 모두 해당할 때 따르십시오.
- 스냅샷이 정확히 이러한 방식으로 구조적 손상을 입었고,
- 유효한 Backup이나 이전 스냅샷을 사용할 수 없는 경우(전략 1과 2를 적용할 수 있다면 항상 해당 전략을 우선 사용하는 것이 좋습니다).
<keeper_server> 아래에 다음 두 설정을 모두 지정한 후 노드를 재시작하십시오.
인메모리 노드 저장소 필요이 정리 작업은 인메모리 노드 저장소에서만 구현되어 있습니다.
<coordination_settings> 아래에서 use_lsmt_storage가 활성화되어 있으면
remove_orphaned_nodes_on_startup이 설정된 상태에서 Keeper가 시작을 거부합니다. 복구를 위해 재시작할 때는
use_lsmt_storage를 비활성화하고, 정상적으로 시작된 후 다시 활성화하십시오.WARNING
레벨로 두 줄에 걸쳐 기록됩니다. 한 줄에는 삭제된 노드의 총 개수와 삭제된 고아 하위 트리의 루트가, 다른 한 줄에는
스냅샷에서 누락되어 손상된 영역의 경계가 되는 경로가 기록됩니다. 해당 루트 아래의 하위 노드도 함께 삭제되지만 개별적으로 나열되지는 않습니다.
Keeper는 로컬 로그 끝부분을 확인한 후, Raft를 시작하기 전에 복구된 트리를 동일한 로그 인덱스의 새 스냅샷 파일에
기록합니다. 완료된 복구 결과는 해당 인덱스의 이전 사본보다 우선하므로, 복구가 중단되더라도 손상된 스냅샷을 선택하지 않고
재개할 수 있습니다. 새 팔로워는 복구된 스냅샷을 전달받으며, 이후 재시작할 때는
고아 노드 제거를 더 이상 활성화할 필요가 없습니다. 원본 스냅샷과 동일 인덱스의 모든 사본은 파일 이름에 orphaned_ 접두사가 붙은 채로
보존되며, 이 파일들은 스냅샷 로드와 자동 보존 관리 대상에서 제외됩니다. 진단용으로 보관해 두었다가 더 이상 필요하지 않으면
수동으로 삭제하십시오. 복구를 위한 재시작에는 복구된 스냅샷과 원본 Backup을 저장할 추가 디스크 공간이 필요합니다.
복구된 스냅샷 기록, 로컬 디렉터리 변경 사항 동기화 또는 원본 보존 중 하나라도 실패하면 Keeper는 시작을 거부합니다.
중단된 보관 작업은 다음 시작 시 마저 완료됩니다.
스냅샷 이후의 로컬 로그 엔트리가 손상된 영역, 즉 삭제된 노드, 그 아래의 모든 노드, 또는 삭제된 하위 트리의 직계 부모를 참조하면
Keeper는 의도적으로 시작을 거부합니다. 직계 부모를 충돌로 간주하는 이유는 해당 부모의 자식 집합이 로그 기록 당시의 트리와 더 이상 일치하지 않기 때문입니다.
따라서 부모만 건드리는 엔트리라도 다르게 재생될 수 있으며, 여기에는 복구된 자식 카운터를 갱신하는 그 아래 형제 노드의 생성이나 삭제도 포함됩니다.
반면 부모의 존재 여부, 버전 또는 수정 ID만 확인하는 엔트리는 영향을 받지 않으며 복구를 막지 않습니다. 예를 들어 Check, CheckNotExists, numChildren과 cversion을 모두 비교하지 않는 CheckStat,
부모 자신의 데이터나 ACL만 다시 쓰는 Set 또는 SetACL,
클라이언트가 재연결 후 다시 등록하는 data, child, exist watch가 이에 해당합니다.
클라이언트가 다시 등록하는 영구(persistent) watch는 트리를 전혀 참조하지 않으므로 복구를 막지 않습니다.
그보다 더 위쪽의 노드는
영향을 받지 않습니다. 이 노드들은 정상 피어와 정확히 동일한 데이터, 버전, 자식을 유지하므로, 이러한 노드만
건드리는 엔트리는 동일하게 재생되며 복구를 막지 않습니다. 단, 재귀적 삭제나 재귀적 목록 조회처럼 해당 경로 아래의 전체 하위 트리를
순회하는 엔트리는 예외입니다. 이러한 엔트리는 삭제된 노드를 실제로 참조하므로 높이에 관계없이 충돌합니다. 다만 Keeper가 트리를 확인하기 전에
요청을 거부하는 경우(예: /의 재귀적 삭제)는 여기에 해당하지 않습니다. 로그 끝부분의 세션 종료(Close)도
해당 세션이 삭제된 임시(ephemeral) 노드를 소유했거나, 그러한 부모 바로 아래에 남아 있는 임시 노드를 소유하고 있다면 마찬가지입니다.
세션을 종료하면 해당 세션의 임시 노드가 삭제되고 그 부모의 카운터가 갱신되기 때문입니다. 이러한 엔트리를
복구된 트리에 재생하면 아무런 경고 없이 다른 상태가 만들어집니다. 이 경우에는 정상 피어로부터
노드를 복구하십시오. 노드를 중지하고 조정 디렉터리를 비운 다음 리더로부터 다시 동기화하게 하거나,
전략 1 또는 2를 사용하십시오.