Article/피드 한 줌
데이터 일관성 문제 회고
조금씩 차근차근
2025. 3. 1. 22:58
팀 프로젝트 일정 관리에서의 데이터 일관성 유지 회고
프로젝트를 진행하면서 겪은 가장 큰 도전 중 하나는 팀 프로젝트 기간과 개별 일정 간의 일관성 문제였습니다. 우리 서비스는 단순 피드백을 넘어서 대학생들이 팀 내에서 자유롭게 일정과 할 일을 관리하며 능동적으로 소통할 수 있도록 설계되었는데요, 그만큼 비즈니스 로직에 따른 세밀한 제약 조건을 고려해야 했습니다.
문제 발견 계기
- 한 팀에, 같은 시작 시간을 갖는 일정은 존재하지 않아야 한다는 요구사항이 존재했습니다.
- 프로젝트의 동시성 문제 검토 기간에, 검증 과정을 시뮬레이션하는 중, 이 검증을 WAS에서는 진행할 수 없고, 반드시 DB 레벨 검증이 필요하고, 이것이 “Unique 제약 조건”의 핵심 기능이라는 사실을 학습하였습니다.
- 그런데, 팀 정보 수정/일정 생성 간에도, 검증을 위한 양방향 연관관계가 존재한다는 사실을 떠올렸고, 일정에 대한 검증이 단순 WAS에서 이루어진다면, 문제가 발생할 수 있다는 가정을 세우게 되었습니다.
- 실제 테스트 결과, 해당 문제가 발생할 수 있음을 확인할 수 있었습니다.
비즈니스 로직의 핵심 요구사항
- 팀 프로젝트 기간 수정: 오직 팀장만 프로젝트 기간을 수정할 수 있습니다.
- 일정 추가: 팀원 누구나 일정을 추가할 수 있습니다.
- 팀-일정 관계: 팀 프로젝트 기간은 반드시 모든 일정을 포함해야 합니다.
이러한 제약은 우리 서비스가 팀장에게서 탑-다운으로 내려오는 단순한 피드백 시스템이 아니라, 팀원들이 스스로 일정 관리 및 피드백을 주고받음으로써 리텐션을 높이는 핵심 기능을 수행하도록 돕기 위해 고안되었습니다.
하지만 이 요구사항 때문에 두 가지 중요한 문제에 직면했습니다.
- 동시성 문제: 팀장이 프로젝트 기간을 수정하는 순간, 팀원이 일정을 추가하면 일정이 팀 프로젝트 기간 범위를 벗어날 위험이 있습니다.
- 검증의 최신성 문제: 일정 생성 시, 팀 프로젝트 기간을 조회해 검증하는 사이 값이 변경되면, 유효하지 않은 일정이 생성될 수 있습니다.
문제의 재정의:
- 일정 생성 중에는 프로젝트 기간이 변경되면 안 된다.
- 프로젝트 기간 변경 시에는 새로운 일정 생성이 없어야 한다.
데이터 일관성 문제 해결 전략
두 애그리거트 간의 일관성을 유지하기 위해 다양한 전략을 고민했습니다.
1. 도메인 이벤트 방식
- 장점: 여러 엔티티 간의 이벤트 기반 연동 가능
- 단점: 상태 전이, 롤백, 트랜잭션 커밋 후 재검증 등 복잡성이 증가하여 오히려 모놀리식의 장점을 잃게 됨
- 상태 패턴과 도메인 이벤트, Transition 시 이벤트 발행 방식으로 구현하게 될 경우, 구현해야 하는 상태 기계들. 매우 양이 방대하다.
2. 도메인 서비스 도입
결국 TeamPlanOrchestrator라는 도메인 서비스를 도입하여 스프링 트랜잭션으로 간단하게 관리하는 방식을 선택했습니다.
일관성 유지 전략: 다양한 Lock 전략 비교
여러 트랜잭션 격리 수준과 락 전략을 고민한 결과, 최종적으로 select for update/share
방식을 선택하게 되었습니다.
- Serializable
- 장점: 팀 정보의 최신성을 보장
- 단점: 성능 저하, 롤백 가능성 증가
- 결론: 폐기
- select for update 시 LockModeType.OPTIMISTIC 사용
- 기능: 일반 낙관적 락과 달리, 업데이트 쿼리가 없어도 버전을 검사한다. 버전을 증가시키진 않는다.
- 장점: 버전 기반 충돌 감지 가능
- 단점: 일정 생성 시 팀의 변경 사항을 반영할 방법이 없음
- 결론: 폐기
- select for update 시 LockModeType.OPTIMISTIC_FORCE_INCREMENT 사용
- 기능: LockModeType.OPTIMISTIC과 달리, 업데이트 쿼리가 없어도 버전을 증가시킨다.
- 장점
- 일정 생성 사실을 팀 도메인에 알릴 수 있음
- 낙관적 락으로 동작하여, 팀 레코드에 걸릴 락 관리 부하를 억제 가능
- 단점
- 두개의 일정이 생성되어도 발생하는 불필요한 충돌
- 사이드 이펙트로 인한 코드의 직관성 감소
- 롤백 발생으로 인한 재시도 로직 추가 작성 필요
- 두개의 일정이 생성되어도 발생하는 불필요한 충돌
- 결론: 폐기
- DB 레벨 Check
- 단점: 특정 DB 기능에 종속되어 이식성 문제 발생
- 결론: 폐기
- select for update/share (Shared Lock, Exclusive Lock) 사용
- 장점
- 명시적이고 단순한 구현
- 2PL(두 단계 락킹)을 통해 일관성 보장
- 팀 레코드에 Shared Lock(일정 생성 시)과 Exclusive Lock(팀 정보 수정 시)을 통해 필요한 동시성 제어 수행
- 장점
- 단점
- 락 관리 오버헤드
- 결론: 해당 구조로 결정
- 애초에 아직 서비스가 크지 않으므로, 락 관리 오버헤드가 큰 영향 없을 것이라 예상.
실행 전략:
- 일정 생성 시: 먼저 팀에 Shared Lock을 걸어 일정 생성 가능 여부를 확인
- 팀 정보 수정 시: 팀에 Exclusive Lock을 걸어 다른 일정 생성과의 충돌을 차단
- TeamPlanOrchestrationService에서 반드시 팀 레코드에 락을 먼저 획득하여 데드락 발생 가능성을 최소화