Article/피드 한 줌

데이터 일관성 문제 회고

조금씩 차근차근 2025. 3. 1. 22:58

팀 프로젝트 일정 관리에서의 데이터 일관성 유지 회고

프로젝트를 진행하면서 겪은 가장 큰 도전 중 하나는 팀 프로젝트 기간과 개별 일정 간의 일관성 문제였습니다. 우리 서비스는 단순 피드백을 넘어서 대학생들이 팀 내에서 자유롭게 일정과 할 일을 관리하며 능동적으로 소통할 수 있도록 설계되었는데요, 그만큼 비즈니스 로직에 따른 세밀한 제약 조건을 고려해야 했습니다.


문제 발견 계기

  • 한 팀에, 같은 시작 시간을 갖는 일정은 존재하지 않아야 한다는 요구사항이 존재했습니다.
  • 프로젝트의 동시성 문제 검토 기간에, 검증 과정을 시뮬레이션하는 중, 이 검증을 WAS에서는 진행할 수 없고, 반드시 DB 레벨 검증이 필요하고, 이것이 “Unique 제약 조건”의 핵심 기능이라는 사실을 학습하였습니다.
  • 그런데, 팀 정보 수정/일정 생성 간에도, 검증을 위한 양방향 연관관계가 존재한다는 사실을 떠올렸고, 일정에 대한 검증이 단순 WAS에서 이루어진다면, 문제가 발생할 수 있다는 가정을 세우게 되었습니다.
  • 실제 테스트 결과, 해당 문제가 발생할 수 있음을 확인할 수 있었습니다.

비즈니스 로직의 핵심 요구사항

image

  • 팀 프로젝트 기간 수정: 오직 팀장만 프로젝트 기간을 수정할 수 있습니다.
  • 일정 추가: 팀원 누구나 일정을 추가할 수 있습니다.
  • 팀-일정 관계: 팀 프로젝트 기간은 반드시 모든 일정을 포함해야 합니다.

이러한 제약은 우리 서비스가 팀장에게서 탑-다운으로 내려오는 단순한 피드백 시스템이 아니라, 팀원들이 스스로 일정 관리 및 피드백을 주고받음으로써 리텐션을 높이는 핵심 기능을 수행하도록 돕기 위해 고안되었습니다.

image

하지만 이 요구사항 때문에 두 가지 중요한 문제에 직면했습니다.

  1. 동시성 문제: 팀장이 프로젝트 기간을 수정하는 순간, 팀원이 일정을 추가하면 일정이 팀 프로젝트 기간 범위를 벗어날 위험이 있습니다.
  2. 검증의 최신성 문제: 일정 생성 시, 팀 프로젝트 기간을 조회해 검증하는 사이 값이 변경되면, 유효하지 않은 일정이 생성될 수 있습니다.

image

문제의 재정의:

  • 일정 생성 중에는 프로젝트 기간이 변경되면 안 된다.
  • 프로젝트 기간 변경 시에는 새로운 일정 생성이 없어야 한다.

 


데이터 일관성 문제 해결 전략

두 애그리거트 간의 일관성을 유지하기 위해 다양한 전략을 고민했습니다.

1. 도메인 이벤트 방식

  • 장점: 여러 엔티티 간의 이벤트 기반 연동 가능
  • 단점: 상태 전이, 롤백, 트랜잭션 커밋 후 재검증 등 복잡성이 증가하여 오히려 모놀리식의 장점을 잃게 됨
    image
  • 상태 패턴과 도메인 이벤트, Transition 시 이벤트 발행 방식으로 구현하게 될 경우, 구현해야 하는 상태 기계들. 매우 양이 방대하다.

2. 도메인 서비스 도입

결국 TeamPlanOrchestrator라는 도메인 서비스를 도입하여 스프링 트랜잭션으로 간단하게 관리하는 방식을 선택했습니다.

image


일관성 유지 전략: 다양한 Lock 전략 비교

여러 트랜잭션 격리 수준과 락 전략을 고민한 결과, 최종적으로 select for update/share 방식을 선택하게 되었습니다.

  • Serializable
    • 장점: 팀 정보의 최신성을 보장
    • 단점: 성능 저하, 롤백 가능성 증가
    • 결론: 폐기
  • select for update 시 LockModeType.OPTIMISTIC 사용
    • 기능: 일반 낙관적 락과 달리, 업데이트 쿼리가 없어도 버전을 검사한다. 버전을 증가시키진 않는다.
    • 장점: 버전 기반 충돌 감지 가능
    • 단점: 일정 생성 시 팀의 변경 사항을 반영할 방법이 없음
    • 결론: 폐기
  • select for update 시 LockModeType.OPTIMISTIC_FORCE_INCREMENT 사용
    • 기능: LockModeType.OPTIMISTIC과 달리, 업데이트 쿼리가 없어도 버전을 증가시킨다.
    •  장점
      • 일정 생성 사실을 팀 도메인에 알릴 수 있음
      • 낙관적 락으로 동작하여, 팀 레코드에 걸릴 락 관리 부하를 억제 가능
    • 단점
      • 두개의 일정이 생성되어도 발생하는 불필요한 충돌
        • 사이드 이펙트로 인한 코드의 직관성 감소
      • 롤백 발생으로 인한 재시도 로직 추가 작성 필요
    • 결론: 폐기
  • DB 레벨 Check
    • 단점: 특정 DB 기능에 종속되어 이식성 문제 발생
    • 결론: 폐기

image

  • select for update/share (Shared Lock, Exclusive Lock) 사용
    • 장점
      • 명시적이고 단순한 구현
      • 2PL(두 단계 락킹)을 통해 일관성 보장
      • 팀 레코드에 Shared Lock(일정 생성 시)과 Exclusive Lock(팀 정보 수정 시)을 통해 필요한 동시성 제어 수행
      image
  • 단점
    • 락 관리 오버헤드
  • 결론: 해당 구조로 결정
    • 애초에 아직 서비스가 크지 않으므로, 락 관리 오버헤드가 큰 영향 없을 것이라 예상.

실행 전략:

  • 일정 생성 시: 먼저 팀에 Shared Lock을 걸어 일정 생성 가능 여부를 확인
  • 팀 정보 수정 시: 팀에 Exclusive Lock을 걸어 다른 일정 생성과의 충돌을 차단
  • TeamPlanOrchestrationService에서 반드시 팀 레코드에 락을 먼저 획득하여 데드락 발생 가능성을 최소화