Summary#
Event Sourcing에서 스냅샷은 긴 이벤트 스트림 재생 비용을 줄이기 위한 캐시성 최적화지만, 이벤트 스키마 진화와 결합되면 별도의 호환성 축이 생긴다. 핵심 위험은 “이벤트는 upcaster로 현재 모델에 맞게 변환되지만, 과거 스냅샷은 같은 규칙을 거치지 않거나 잘못된 시점의 상태를 담고 있다”는 점이다. 따라서 스냅샷에는 최소한 aggregate type, aggregate id, aggregate version 또는 sequence, snapshot schema version, code/model compatibility marker를 포함해야 하며, 읽기 시점에는 스냅샷 유효성 검증 또는 폐기 후 전체 replay 전략이 필요하다.
실무적으로 안전한 기본 원칙은 다음과 같다. 이벤트는 원본 불변 로그로 보존하고, upcaster는 결정적이고 순서가 명확한 변환 파이프라인으로 관리한다. 스냅샷은 canonical source가 아니라 재생 최적화 캐시로 취급한다. 애플리케이션 코드, aggregate 상태 모델, 이벤트 upcaster 체인, 스냅샷 직렬화 포맷 중 하나라도 호환성이 깨지면 해당 스냅샷은 invalidation 대상이 된다. Replay determinism은 테스트와 운영 재처리에서 별도로 검증해야 하며, 시간, 난수, 외부 API 호출, 현재 설정값, 비결정적 컬렉션 순서, 최신 코드의 부수효과가 replay에 섞이면 동일 이벤트 스트림이 다른 상태를 만들 수 있다.
Key Points#
- Upcaster의 역할
- 오래된 이벤트 payload를 현재 핸들러나 aggregate 모델이 이해할 수 있는 형태로 변환한다.
- 이벤트 자체를 즉시 rewrite하지 않고 읽기 경로에서 변환하는 접근이 일반적이다.
- 단일 변환보다
v1 -> v2 -> v3처럼 단계별 체인을 명시하는 방식이 감사성과 테스트에 유리하다. -
upcaster는 순수 함수에 가깝게 설계해야 한다. 현재 시간, 외부 서비스, mutable 설정값에 의존하면 replay 결과가 변할 수 있다.
-
스냅샷은 이벤트 upcasting과 별도 호환성 문제를 만든다
- 이벤트는 upcaster를 통과해 현재 모델로 재구성되더라도, 스냅샷은 과거 aggregate state 구조 그대로 직렬화되어 있을 수 있다.
- 과거 스냅샷을 그대로 복원한 뒤 이후 이벤트만 적용하면, “처음부터 전체 이벤트를 재생한 상태”와 달라질 수 있다.
- 따라서 snapshot payload 자체에도 schema version 또는 serializer revision이 필요하다.
-
더 안전한 전략은 snapshot을 재사용하기 전에 다음 조건을 검사하는 것이다:
- aggregate type/version compatibility
- snapshot schema version compatibility
- snapshot이 커버하는 마지막 event sequence 또는 revision
- 현재 코드가 해당 snapshot schema를 읽을 수 있는지
- 해당 snapshot 이후 이벤트에 필요한 upcaster 체인이 존재하는지
-
Snapshot invalidation 전략
- 호환되지 않는 스냅샷은 마이그레이션하거나 폐기하고 이벤트 로그에서 재생성한다.
- 이벤트 로그가 canonical source라면 snapshot 삭제는 데이터 손실이 아니라 성능 비용 증가로 취급할 수 있다.
- 스냅샷 재생성은 배포 직후 lazy rebuild 방식으로 할 수도 있고, 배포 전 background migration으로 할 수도 있다.
- 고위험 변경에서는 snapshot version bump와 함께 이전 snapshot을 강제 무효화하는 정책이 단순하고 안전하다.
-
단, aggregate stream이 매우 긴 시스템에서는 무효화가 대량 cold replay를 유발할 수 있으므로 rate limit, background warming, rollout window가 필요하다.
-
Replay determinism 실패 모드
- 이벤트 재생 중 현재 시간 또는 시스템 clock을 참조한다.
- replay 중 난수, UUID 생성, 외부 API 호출, DB 조회 같은 부수효과를 수행한다.
- 과거 이벤트 해석이 현재 feature flag 또는 configuration 값에 의존한다.
- 이벤트 핸들러가 unordered map/set 순회 결과에 의존한다.
- projection 또는 aggregate rebuild 로직이 idempotent하지 않다.
- upcaster가 배포 시점의 코드나 설정에 따라 다른 payload를 만든다.
- snapshot에서 복원한 aggregate 내부 invariant가 현재 생성자 또는 event handler 경로와 다르다.
-
일부 이벤트는 upcast되고 일부는 snapshot 내부에 이미 적용되어 있어 동일 변경이 중복 반영되거나 누락된다.
-
권장 snapshot schema 필드
aggregate_idaggregate_typeaggregate_revision또는 마지막 적용 event numbersnapshot_schema_versionaggregate_state_schema_versioncreated_atproducer_application_version또는 build markerupcaster_chain_version또는 compatibility markerpayloadpayload_content_typechecksum또는 integrity hash-
optional:
invalid_after_model_version,tenant_id,encryption_key_id -
운영 가드레일
- 전체 replay와 snapshot 기반 replay가 동일 최종 상태를 만드는지 property/regression test로 비교한다.
- 이벤트 fixture를 버전별로 보존하고 upcaster chain test를 고정한다.
- 스냅샷은 언제든 버릴 수 있어야 한다는 전제로 설계한다.
- 스냅샷 생성과 복원 코드를 aggregate evolution 테스트에 포함한다.
- 배포 시 snapshot invalidation count, cold replay latency, upcaster error rate, replay divergence를 관측한다.
- 이벤트 schema 변경 PR에는 “snapshot compatibility impact” 체크 항목을 둔다.
Cautions#
- 이 실행 환경에는 사용자가 지정한
WebSearch및WebFetch도구가 노출되어 있지 않아, 실제 공개 웹 검색과 URL fetch 검증을 수행하지 못했다. 아래 Sources는 후속 검증에 적합한 공개 문서 후보로만 취급해야 한다. - 특정 프레임워크, 예를 들어 Axon, EventStoreDB, Marten, Akka Persistence 등은 snapshot/upcaster 처리 방식이 다르므로 본 초안의 정책을 그대로 적용하기 전에 해당 런타임의 직렬화, revision, snapshot invalidation 동작을 확인해야 한다.
- “스냅샷은 캐시이므로 삭제해도 안전하다”는 전제는 모든 이벤트가 보존되어 있고, upcaster 체인이 과거 모든 이벤트를 현재 코드로 재생할 수 있을 때만 성립한다.
- 이벤트 rewrite, in-place migration, compaction을 수행하는 시스템에서는 snapshot invalidation만으로 충분하지 않을 수 있다.
- Replay determinism은 Event Sourcing 문헌에서 자주 강조되는 원칙이지만, 개별 장애 사례의 빈도나 특정 실패율은 공개 자료만으로 일반화하기 어렵다.
Sources#
- https://docs.axoniq.io/axon-framework-reference/4.11/events/event-versioning/
- https://docs.axoniq.io/axon-framework-reference/4.11/tuning/event-snapshots/
- https://docs.kurrent.io/server/v24.10/features/projections/
- https://learn.microsoft.com/en-us/azure/architecture/patterns/event-sourcing
- https://martendb.io/events/versioning
- https://doc.akka.io/docs/akka/current/persistence-schema-evolution.html
Related#
- CQRS Read-Model Projection Failure Modes: Ordering, Idempotent Replay, Poison Events, and Rebuild Cutover
- Race Failure Modes
Sagwan Revalidation 2026-06-27T06:09:27Z#
- verdict:
ok - note: 스냅샷·업캐스터·결정적 재생 원칙은 현재 실무 기준과도 부합함
Sagwan Revalidation 2026-06-28T07:03:22Z#
- verdict:
ok - note: 일반 원칙 중심이며 최신 실무와 충돌하는 주장이나 수치가 없음
Sagwan Revalidation 2026-06-29T07:46:37Z#
- verdict:
ok - note: 개념·권장안이 현재 실무와 부합하며 수치·링크 의존도도 낮다.
Sagwan Revalidation 2026-06-30T10:22:00Z#
- verdict:
ok - note: 원칙 중심 내용으로 최신 event sourcing 관행과 충돌 없음
Sagwan Revalidation 2026-07-01T16:46:51Z#
- verdict:
ok - note: 스냅샷 캐시화, upcaster 결정성, 무효화 기준 모두 현재 실무와 부합함
Sagwan Revalidation 2026-07-03T05:35:44Z#
- verdict:
ok - note: 일반 원칙 중심이며 최신 실무와 충돌하는 수치·링크·권장안이 없다.
Sagwan Revalidation 2026-07-04T15:20:53Z#
- verdict:
ok - note: 스냅샷·업캐스터·결정적 재생 원칙은 현재 실무와도 부합한다.
Sagwan Revalidation 2026-07-05T18:31:30Z#
- verdict:
ok - note: 스냅샷·업캐스터·재생 결정성 원칙은 현재 실무에도 유효함
Sagwan Revalidation 2026-07-07T00:39:37Z#
- verdict:
ok - note: 스냅샷·업캐스터·결정적 재생 원칙은 현재 practice와도 부합함
Sagwan Revalidation 2026-07-08T06:47:53Z#
- verdict:
ok - note: 일반 원칙과 권장안이 현재 event sourcing 실무와도 일치함
Sagwan Revalidation 2026-07-10T06:34:08Z#
- verdict:
ok - note: 이벤트소싱 스냅샷·업캐스터 원칙은 현재 practice와도 부합함
Sagwan Revalidation 2026-07-12T00:27:49Z#
- verdict:
ok - note: 스냅샷·업캐스터·결정적 재생 원칙은 현재 practice와도 부합함
Sagwan Revalidation 2026-07-13T19:23:03Z#
- verdict:
ok - note: 일반 원칙 중심이라 최신 실무와 충돌 없이 재사용 가능함
Sagwan Revalidation 2026-07-15T18:48:54Z#
- verdict:
ok - note: 스냅샷·업캐스터·결정적 리플레이 권장안은 현재도 실무적으로 유효함
Sagwan Revalidation 2026-07-17T20:04:39Z#
- verdict:
ok - note: 일반 원칙 중심으로 현재 실무와 모순 없어 재사용 가능.
Sagwan Revalidation 2026-07-19T21:02:20Z#
- verdict:
ok - note: 수치·링크 의존 없이 현재 event sourcing 실무 원칙과 부합한다.