설계 #13720
revert to snapshot을 merge 대신 delete+recreate로 구현
설명
개요¶
manila driver의 revert_to_snapshot() 을 lvconvert --merge 대신 "원본(share) LV 삭제 → revert 대상 snapshot에서 원본 이름으로 thin snapshot 재생성" 의 형태로 구현한다. 형태는 Proxmox VE의 lvm-thin rollback(PVE/Storage/LvmThinPlugin.pm, volume_snapshot_rollback) 과 동일하다.
merge 대신 delete+recreate를 택한 이유는 두 가지다.
- LVM thin의
--merge는 형제 snapshot 계보를 파괴한다 — 댓글의 실측으로 확인 - GMS의 merge endpoint는 export 중인 share를 revert하지 못한다 — umount EBUSY로 500
근거 실측, GMS endpoint 문제 분석, 채택 효과와 실장비 검증 결과는 댓글에 남긴다.
오 지호님이 21일 전에 변경
실측 검증 — LVM thick/thin snapshot merge¶
ASE4 노드에서 loop 기반 임시 VG(TESTVG, 20G)로 직접 검증했다. 호스트 lvm.conf 에 volume_list="anystor-e" 가 있어 모든 LVM 명령에 --config 'activation/volume_list=["anystor-e","TESTVG"]' 를 붙여 우회했다. 테스트 후 VG/loop/img 전부 정리 완료.
원본에 파일 하나(/mark)를 두고 내용을 바꿔가며 snapshot 3개를 순차 생성했다. snapshot이 각각 다른 시점을 담게 하고 가운데 snapshot을 merge 했다.
- thick:
A(state-3),A1(state-0),A2(state-1),A3(state-2) - thin:
T(t-state-3),T1(t-state-0),T2(t-state-1),T3(t-state-2)
thick (COW snapshot) — 형제 snapshot 온전¶
lvconvert --merge /dev/TESTVG/A2 실행 후:
LV LSize Origin Attr Snap% A 2.00g owi-a-s--- <- state-1 로 복원됨 A1 500.00m A swi-a-s--- 0.41 <- state-0, origin 유지 A3 500.00m A swi-a-s--- 0.41 <- state-2, origin 유지
- A1/A3 데이터 정상 read,
origin=A관계 유지. 이어서 A3 merge → A=state-2, 다시 A1 merge → A=state-0. 순서 무관하게 반복 merge 성공 - merge는 원본 전체 재기록에 가까워 남은 snapshot COW가 급증했다(0.01% → 0.41%). COW가 부족하면 그 snapshot은 Invalid(
I플래그)로 죽는다 → 크기 산정 주의
thin — 형제 snapshot 계보 파괴¶
lvconvert --merge TESTVG/T2 실행:
Volume TESTVG/T2 replaced origin TESTVG/T. LV Origin ThId T 3 <- T2의 thin device를 그대로 인수, t-state-1 T1 2 <- Origin 칼럼이 비었다 T3 4 <- 역시 비었다
- 데이터는 살아있다: T1=t-state-0, T3=t-state-2 정상 read
- 하지만 snapshot 계보가 끊긴다:
# lvconvert --merge TESTVG/T3 TESTVG/T3 is not a mergeable logical volume. (exit=5)
- 원인: thin merge는 원본 LV의 thin device id를 snapshot 것으로 갈아끼우는 방식. 형제들이 참조하던 원래 device가 사라지면서 origin 링크가 null이 된다. 즉 "snapshot이 사라진다"가 아니라 일반 thin LV로 강등되어
--merge로는 영원히 복원 불가
thin rename 우회 — 문제를 지연시킬 뿐¶
--merge 대신 "snapshot 복제 + 이름 교체"로 복원은 된다:
lvcreate -s -n T_restore TESTVG/T3 lvrename TESTVG/T TESTVG/T_broken lvrename TESTVG/T_restore TESTVG/T -> T = t-state-2 복원 성공 (T3는 소비되지 않고 남음)
그러나 형제 계보는 여기서도 깨진다. LVM 텍스트 메타데이터에서 origin은 이름 문자열로 저장되고 lvrename 이 그 참조를 함께 갱신한다:
# vgcfgbackup 원문
T1 { device_id = 2 origin = "T_broken" }
T2 { device_id = 3 origin = "T_broken" }
T3 { device_id = 4 origin = "T_broken" }
T { device_id = 5 origin = "T3" }
원본 LV(T_broken)를 정리하면 --merge 와 동일 상태가 된다(T1/T2/T3의 origin 전부 null, 데이터는 전부 정상 read).
결론: 선택지가 둘 다 나쁘다.
- T_broken 유지 → 사용자에게 안 보이는 유령 볼륨이 pool 공간을 영구 점유하고 형제 부모가 유령을 가리키며 복원된 T는
origin=T3로 표시되어 "볼륨인가 snapshot인가" 판정이 깨짐 - T_broken 삭제 →
--merge와 동일하게 형제 origin 전부 null
rename 방식이 --merge 보다 나은 점은 T3가 소비되지 않아 재복원 소스로 재사용 가능하다는 것 하나뿐이다. 형제 계보 파괴는 피할 수 없다.
부수 비용: 새 T는 LV UUID가 다른 별개 LV다(fstab/pacemaker가 UUID 참조 시 깨짐). FS UUID는 복제되므로 XFS는 nouuid 마운트 또는 xfs_admin -U 필요. k(activation skip) 플래그가 상속되어 lvchange -kn 필요.
정리¶
| 형제 snapshot 데이터 | 형제 snapshot 재복원 | |
|---|---|---|
| thick | 보존 (COW 사용량 증가) | 가능, 순서 무관 |
| thin | 보존 (LV은 남음) | 불가 (not mergeable) |
근본 원인은 thin snapshot이 device_id별 독립 flat device인데 LVM이 부모-자식을 이름 참조 한 칸(origin)으로만 표현한다는 점이다.
오 지호님이 21일 전에 변경
GMS merge endpoint 문제¶
POST /api/lvm/snapshot/<name>/merge (perl-gms-plugin-lvm Controller/LVM/Snapshot.pm:409). export 중인 share를 revert하지 못한다:
_pacemaker_control이rsc_<vg>와 Filesystem resource는 비활성화하지만 kernel export를 잡고 있는share_<vg>_<lv>ShareCtl은 건드리지 않아umount가 EBUSY로 실패, endpoint가 500 반환- 실패 경로는 양 노드를
maintenance=on으로 남겨둔다(클러스터 strand)
오 지호님이 21일 전에 변경
delete+recreate 채택 효과¶
- merge도 소비도 없으므로 다른 모든 snapshot은 데이터 홀더이자 이후 revert의 소스로 그대로 유지된다
- detach된 snapshot도 LV와 데이터는 살아 있어 rollback 소스로 계속 쓸 수 있다. 단
GET /api/lvm/snapshotlisting에서는 사라지므로(origin != ""필터) driver는 snapshot API를 create 전용으로 쓰고 존재 확인은 LV view(get_lv), 삭제는DELETE /lvm/lvs/<lv>에entity.purpose = 'snapshot'으로 처리한다 - 실장비 검증: 동일 대상 2회 revert를 클라이언트 마운트 유지 상태로 통과, detached snapshot과 revert된 share 모두 정상 삭제, appliance에는 pool만 남음