497. 툼스톤 (Tombstone) 마킹과 지연 삭제
⚠️ 이 문서는 데이터를 지우고 싶을 때 디스크에서 진짜로 데이터를 박박 지우느라 서버가 느려지는 것을 막고, 대신 "이 데이터는 죽었음"이라는 묘비명(Tombstone) 딱지 하나만 살포시 붙여놓고 나중에 한가할 때 몰아서 지우는 NoSQL(LSM 트리)의 핵심 삭제 기법을 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: 분산 NoSQL 데이터베이스(Cassandra 등)에서 데이터를 삭제(
DELETE)할 때, 즉시 지우지 않고 마커(Tombstone)만 추가하는 논리적 삭제(Soft Delete) 방식이다.- 이유 1 (속도): 하드디스크의 데이터를 직접 찾아가서 지우는 것(Random I/O)은 너무 느리다. 그냥 메모리에 묘비명을 하나 새로 추가하는 것(Sequential Write)이 100배 빠르다.
- 이유 2 (동기화): 전 세계 서버 3대에 데이터가 퍼져 있는데 1대가 꺼져 있다면? 나중에 그 서버가 켜졌을 때 "이 데이터는 옛날에 지워진 거야!"라고 알려주기 위해 '지워졌다는 기록(묘비명)' 자체가 필요하다.
Ⅰ. 개요: 묘비를 세우다 (Context & Necessity)
내가 페이스북에서 옛날에 쓴 부끄러운 일기를 지웠다 치자. (DELETE 일기)
페이스북 서버 3대(A, B, C) 중 C 서버가 하필 그때 정전으로 꺼져 있었다.
- A, B 서버는 일기를 완벽히 지웠다.
- 1시간 뒤 C 서버가 켜졌다. C 서버에는 여전히 부끄러운 일기가 남아있다.
- C 서버는 A, B 서버를 보며 말한다. "어? 너희들 일기 데이터가 없네? 내가 옛날 데이터 들고 있으니까 너희한테 다시 복사(동기화)해 줄게!"
- 대참사: 내가 지운 일기가 좀비처럼 다시 부활해 버렸다. (좀비 데이터 문제)
이 끔찍한 좀비 부활을 막으려면, 데이터를 아예 지우는 게 아니라 **"2026년에 이 일기 데이터는 사망했음!"이라는 묘비명(Tombstone)**을 데이터 자리에 세워두어야 한다. 그러면 C 서버가 켜졌을 때 A, B의 묘비를 보고 "아하, 이건 죽은 거구나. 내 데이터도 지워야지" 하고 납득하게 된다.
📢 섹션 요약 비유: 툼스톤 마킹은 **'출석부에 빨간 줄 긋기'**와 같습니다. 전학 간 친구의 이름을 출석부에서 지우개로 박박 지워서 아예 없애버리는 게 아니라, 이름 위에 빨간 줄을 죽 긋고 옆에
[전학]이라고 마커(Tombstone)를 칠해두는 것입니다. 그래야 다른 선생님이 나중에 출석부를 봐도 "아, 얘는 우리 반이었다가 전학을 갔구나" 하고 헷갈리지 않습니다.
Ⅱ. 툼스톤(Tombstone)의 작동 원리 ★
NoSQL의 심장인 LSM 트리(493번 문서) 엔진에서 DELETE가 작동하는 방식이다.
- 사용자의 DELETE 요청
- 사용자가
ID: 5데이터를 지워달라고 한다.
- 사용자가
- 메모리에 묘비 생성 (Write)
- 디스크에 있는 5번 데이터를 찾으러 가지 않는다.
- 그냥 메모리(MemTable)에
[ID: 5, 값: Tombstone 🪦]이라는 새로운 데이터를 하나 **'추가(Insert)'**한다. - (데이터를 지우는 명령인데 내부적으로는 '쓰기' 연산이 일어난다!)
- 읽기 (Read) 시의 필터링
- 다른 사용자가
ID: 5데이터를 달라고 한다. - DB가 디스크를 뒤져서
[ID: 5, 값: 진짜 데이터]를 찾았지만, 메모리에서 방금 세워진 묘비[ID: 5, 값: 🪦]를 같이 발견한다. - 묘비가 더 최신(시간이 빠름)이므로, DB는 사용자에게 "데이터가 없습니다(Null)"라고 대답한다.
- 다른 사용자가
Ⅲ. 툼스톤의 한계: 쓰레기를 비우는 날 (Compaction)
묘비를 무한정 세워두면 나중에 데이터베이스 용량이 가득 차서 터져버린다. "지워진 데이터를 안 지우고 묘비만 세우니까 오히려 용량이 늘어나네?"
그래서 DB는 밤마다 **콤팩션(Compaction - 378번 문서)**이라는 대청소를 한다.
- 디스크에 흩어져 있는 '진짜 데이터'와 '묘비명' 파일들을 하나로 모은다.
- 묘비명이 꽂혀 있는 데이터들은 서로 합쳐서 아예 흔적도 없이 영구 삭제해 버린다.
🚨 튜닝 꿀팁 (gc_grace_seconds):
카산드라 같은 DB는 묘비를 청소할 때, 묘비가 세워진 지 10일(gc_grace_seconds)이 안 된 묘비는 안 지우고 놔둔다. 왜? 꺼져있던 C 서버가 며칠 뒤에 켜져서 좀비를 부활시킬까 봐, 적어도 10일 동안은 묘비를 남겨둬서 C 서버에게 경고를 줘야 하기 때문이다. 만약 C 서버가 11일 뒤에 켜진다면? 묘비가 사라져서 결국 좀비 데이터가 부활하게 된다.
┌──────────────────────────────────────────────────────────────┐
│ 툼스톤 마킹 (Tombstone)과 콤팩션 처리 시각화 │
├──────────────────────────────────────────────────────────────┤
│ │
│ [ 💾 1월의 데이터 (SSTable_1) ] │
│ ID:1 (철수) / ID:2 (영희) / ID:3 (민수) │
│ │
│ [ 👨💻 사용자 ] "영희 지워줘! (DELETE ID: 2)" │
│ │
│ [ 💾 2월의 데이터 (SSTable_2) ] │
│ ID:2 (🪦 툼스톤! 2/15에 죽음) ◀── (지우는 대신 묘비를 새로 추가함) │
│ │
│ ───────────────── 🧹 3월 대청소 (Compaction) ────────────────── │
│ │
│ [ 💾 새로운 압축 파일 (SSTable_3) ] │
│ ID:1 (철수) / ID:3 (민수) ◀── (영희와 묘비는 영구적으로 소멸함! ✨) │
└──────────────────────────────────────────────────────────────┘
Ⅳ. 결론
"완벽한 삭제를 포기함으로써, 완벽한 분산 동기화를 얻어내다."
툼스톤(Tombstone) 마킹 기법은 NoSQL이 성능과 가용성을 위해 취한 가장 독특하고 위대한 트레이드오프 중 하나다. 디스크를 직접 건드리지 않기 때문에 DELETE 연산조차 INSERT와 똑같은 빛의 속도를 내게 만들었으며, 분산 서버들끼리 누가 진짜 최신 데이터인지를 가릴 때 '죽었다는 명확한 기록(묘비)'을 남겨줌으로써 데이터 동기화의 기준점을 세워주었다. 하지만 이 묘비들이 디스크를 갉아먹는 '쓰레기(Garbage)'라는 사실을 잊고 콤팩션 주기를 잘못 설정하면, 어느 날 디스크 용량 100% 알람과 함께 뻗어버리는 DB 서버를 마주하게 될 것이다.
📌 관련 개념 맵
- 관련 엔진: LSM-Tree (493번 문서 - 이 구조에서만 툼스톤 방식을 씀)
- 청소 기술: Compaction (콤팩션 - 378번 문서)
- 발생 버그: Zombie Data (좀비 데이터 부활 현상)
- 보조 파라미터:
gc_grace_seconds(묘비를 살려두는 유예 기간)
👶 어린이를 위한 3줄 비유 설명
- 내가 잘못 그린 그림을 지우개로 박박 지우려면 팔이 아프고 시간이 오래 걸리죠? (직접 삭제)
- 그래서 나는 지우개 대신, 그림 위에 엑스표(X)가 그려진 **'취소 스티커(툼스톤)'**를 1초 만에 턱! 붙여버려요. (마킹 삭제)
- 나중에 주말에 시간이 널널할 때, 스티커가 붙은 종이들을 모아서 한꺼번에 쓰레기통에 버리는(콤팩션) 아주 똑똑한 게으름쟁이의 방법이랍니다!