LWW와 CRDT — 충돌 해결 전략
두 기기가 같은 데이터를 오프라인에서 각각 수정했을 때 어떻게 합치느냐의 전략. overview|Local-First Sync 탐구에서 파생.
왜 충돌이 생기는가
기기 A와 B가 같은 데이터를 가지고 있고, 둘 다 오프라인에서 수정한 뒤 sync하면 — 어느 버전이 "맞는" 버전인지 시스템이 알 수 없다.
폰 (오프라인): 경험치 100 → 110
PC (오프라인): 경험치 100 → 120
온라인 sync: ???
Last-Write-Wins (LWW)
원리
타임스탬프를 찍고, 나중에 수정된 게 이긴다.
폰: "운동" 완료 표시 (14:00)
PC: "운동" 미완료로 (14:05)
→ PC 버전 채택 (14:05 > 14:00)
문제점
기기마다 시계가 미묘하게 달라 (clock skew). 1ms 차이로 틀린 버전이 이길 수 있다. 단, 할 일 앱 수준에서는 이 오차가 치명적이지 않다.
적합한 데이터
- 단순 상태 값: 완료 여부, 우선순위, 오늘 목표 텍스트
- "둘 중 하나만 맞는" 경우
CRDT (Conflict-free Replicated Data Type)
원리
수학적으로 충돌이 아예 발생하지 않도록 데이터 타입 자체를 설계하는 방식. "어떤 상태인가" 대신 "어떤 변화가 있었는가"를 기록한다.
# 일반 카운터 (충돌)
폰: 경험치 100 → +10 → 110
PC: 경험치 100 → +20 → 120
합치면? 불확정
# CRDT 카운터 (충돌 없음)
폰: "+10 했다" 기록
PC: "+20 했다" 기록
합치면: 100 + 10 + 20 = 130 ← 순서 무관, 항상 동일
수학적 보장
합치는 연산(merge)이 다음 세 성질을 만족하면 CRDT:
- 교환법칙: A merge B = B merge A
- 결합법칙: (A merge B) merge C = A merge (B merge C)
- 멱등성: A merge A = A
이 성질 덕에 순서나 중복에 상관없이 항상 같은 결과.
적합한 데이터
- 누적 값: 경험치, 포인트
- 추가만 있는 로그: 히스토리, 스트릭 기록
- 여러 기기가 동시에 수정할 수 있는 데이터
묵연 적용 기준
| 데이터 | 전략 | 이유 | |--------|------|------| | 할 일 완료 여부 | LWW | 둘 중 하나만 맞음 | | 우선순위 | LWW | 최근 설정이 의도 | | 오늘 목표 텍스트 | LWW | 최근 수정이 의도 | | 경험치 누적 | CRDT | 두 기기의 변화 모두 반영해야 함 | | 스트릭 카운트 | CRDT | 누락 없이 합산 필요 | | 히스토리 로그 | CRDT | 이벤트 추가만 있음 (append-only) |