-
도메인 주도 개발 시작하기 CH.8 ~ CH.9DESIGN PATTERN & ARCHITECTURE 2024. 7. 3. 23:40
Ch. 8 : 애그리거트 트랜잭션 관리
8.1- 애그리거트와 트랜잭션
- 동시에 한 데이터를 수정하고자 하는 경우 (동시성 이슈 발생)
- 애그리거트의 일관성이 깨짐
- 해결 방안
- 선점 잠금
- 한 스레드가 애그리거트를 수정하는 동안 다른 스레드가 변경 불가능하게 방지
- 동시에 애그리거트를 수정할 때 발생하는 데이터 충돌 해소 가능
- DBMS의 행단위 잠금 사용하여 구현
- ex) JPA Entity Manager의 LockModeType, 스프링데이터 JPA의 @Lock 애너테이션, 하이버네이트 PESSIMISTIC_WRITE 잠금 모드 (for update 쿼리)
- 잠금 순서에 따른 교착 상태를 주의
- 다른 스레드가 대기 상태에 빠질 수 있어 대기 시간 설정이 필요
- ex) JPA lock.timeout, 스프링 데이터 JPA의 @QueryHints 애너테이션
- Hints를 사용하면 사용하는 DBMS가 관련 기능을 제공하는지 확인해야함
- ex) JPA lock.timeout, 스프링 데이터 JPA의 @QueryHints 애너테이션
- 다른 스레드가 대기 상태에 빠질 수 있어 대기 시간 설정이 필요
- 한 스레드가 애그리거트를 수정하는 동안 다른 스레드가 변경 불가능하게 방지
- 비선점 잠금
- 한 스레드가 데이터를 조회하고 작업하는 동안 변경이 일어나면 다시 조회 후 수정하도록 강제
- = 동시 접근을 막는 대신 변경한 데이터를 실제 DBMS에 반영하는 시점에 변경 가능 여부를 확인
- 애그리거트 버전으로 사용할 숫자 타입 프로퍼티를 추가해야 함 (version)
- ex) JPA 의 @Version
- 응용 서비스는 버전에 대해 알 필요 없음
- 비선점 잠금 쿼리 수행시 실행 결과로 수정된 행의 갯수가 0으로 이미 앞서 데이터가 수정되었으면 OptimisticLockingFailureException이 발생
- 해당 예외로 트랜잭션 충돌 확인 가능
- 비선점 잠금을 여러 트랜잭션으로 확장하려면 애그리거트 정보를 뷰로 보여줄때 버전 정보도 함께 화면에 전달
- 발생 가능한 예외
- 이미 누군가가 애그리거트를 수정했다면 VersionConflictException 발생
- 누군가가 거의 동시에 애그리거트를 수정한다면 OptimisticLockingFailureException
- 항상 후에 수행하는 업데이트를 반영하기 위해 LockModeType.OPTIMISTIC_FORCE_INCREMENT를 통해 강제로 버전을 업데이트할 수도 있음
- 한 스레드가 데이터를 조회하고 작업하는 동안 변경이 일어나면 다시 조회 후 수정하도록 강제
- 오프라인 선점 잠금
- 동시에 여러 트랜잭션에 걸쳐 동시 변경을 방지
- 첫번째 트랜잭션을 시작할 때 오프라인 잠금을 선점하고 마지막 트랜잭션에서 잠금을 해제
- 잠금을 해제하기 전까지 다른 사용자는 잠금을 구할 수 없음
- = 수정 폼을 보여주는 트랜잭션과 수정하는 트랜잭션에 걸쳐 잠금을 가짐
- => 잠금을 해제하지 않는 경우를 방지하기 위해 잠금 유효 시간이 필요함
- 선점 시도, 잠금 확인, 작금 해제, 잠금 유효시간 연장의 네가지 기능이 필요
- 잠금이 유효한지 확인 후 반영 해야 함
- 잠금 유효 시간이 지났으면 이미 다른 사용자가 잠금을 선점
- 잠금을 선점하지 않은 사용자가 기능을 실행했다면 이를 막아야 함
- 잠금이 유효한지 확인 후 반영 해야 함
- 동시에 여러 트랜잭션에 걸쳐 동시 변경을 방지
- 선점 잠금
- 동시에 한 데이터를 수정하고자 하는 경우 (동시성 이슈 발생)
Ch. 9 : 도메인 모델과 바운디드 컨텍스트
9.1
- 한개의 모델로 모든 하위 도메인을 표현할 수는 없음
- 모델은 특정한 컨텍스트(문맥) 하에서 다른 의미를 가짐
- ex) 상품 정보의 상품 vs 주문정보 에서의 상품
- 바운디드 컨텍스트
- 구분되는 경계를 갖는 컨텍스트
- 모델의 경계를 결정하며 논리적으로 한개의 모델을 가짐
- 여러 하위 도메인을 하나의 바운디드 컨텍스트에서 개발할 때는 하위 도메인의 모델이 섞이지 않도록 주의
- 바운디드 컨텍스트는 구현하는 하위 도메인에 알맞은 모델을 포함
- 도메인 기능을 사용자에게 제공하는데 필요한 표현 영역, 응용 서비스, 인프라스트럭쳐 영역을 모두 포함
- 도메인모델의 데이터 구조가 바뀌면 DB테이블 스키마도 함께 변경되므로 테이블도 포함됨
- 도메인 기능 자체가 단순한 경우 서비스 - DAO로 구현된 CRUD 방식으로도 코드 유지보수가 가능
- ex) CQRS 패턴
- Command Query Responsibility Segregation
- 상태를 변경하는 명령 기능과 내용을 조회하는 쿼리 기능을 위한 모델을 구분
- 상태변경과 관련된 기능은 도메일 모델 기반으로 구현하되 조회 기능은 서비스 - DAO로 구현 가능
- ex) CQRS 패턴
- 각 바운디드 컨텍스트는 서로 다른 구현 기술을 사용할 수도 있음
- 중간 단계의 서버를 두어 각 바운디드 컨텍스트의 파사드 역할을 수행하도록 할 수 있음
- 바운디드 컨텍스트 간 통합
- 다른 바운디드 컨텍스트의 접근이 필요한 경우 도메인 서비스를 구현한 클래스를 인프라스트럭쳐 영역에 위치시켜 외부 시스템과의 연동을 처리하고 외부 시스템 모델과 현재 도메인 모델 간의 변환을 담당하도록 구현
- 두 모델 간의 변환 과정이 복잡하면 변환 처리를 위한 별도 클래스를 만들수도 있음
- 통합 방법
- 직접 통합
- ex) REST API
- API를 사용하는 컨텍스트는 제공하는 컨텍스트에 의존하게 됨
- 간접 통합
- ex) 메세지 큐
- 비동기로 메세지를 처리하여 한 컨텍스트가 처리를 기다리지 않고 작업을 수행할 수 있음
- 메세지 큐의 데이터 구조는 제공하는 자에 의해 구조가 결정되게 됨
- MSA에 잘 어울림
- 직접 통합
- 통합 형태
- 공개 호스트 서비스 (OPEN HOST SERVICE)
- 여러 하류 팀의 요구사항을 수용할 수 있는 API를 만들고 이를 서비스 형태로 공개해서 서비스 일관성을 유지
- 하류 팀은 공개된 API를 이용해서 기능 구현
- 상류 컴포넌트의 서비스는 상류 바운디드 컨텍스트의 도메인 모델을 따름
- 안티코럽션 계층(ANTI CORRUPTION LAYER)
- 하류 컴포넌트가 상류 서비스 모델이 자신의 도메인 모델에 영향 주지 않도록 보호해주는 완충 지대를 만들어야 함
- 안티코럽션 계층(ANTI CORRUPTION LAYER)
- 공유 커널 (SHARED KERNEL)
- 두 바운디드 컨텍스트가 같은 모델을 공유
- 한 팀에서 임의로 모델을 변경하면 안되며 두 팀이 밀접한 관계를 유지해야 함
- 독립 방식 (SEPARATE WAY)
- 두 바운디드 컨텍스트 간에 통합하지 않고 독립적으로 모델 발전
- 두 바운디드 컨텍스트 간의 통합은 수동으로 이룸
- => 규모가 커질수록 한계가 있음
- 공개 호스트 서비스 (OPEN HOST SERVICE)
- 컨텍스트 맵
- 바운디드 컨텍스트 간의 관계를 표시
- ex) 오픈 호스트 서비스(OHS), 안티코럽션 계층(ACL)
- 시스템의 전체 구조를 보여줌
- 하위 도메인과 일치하지 않는 바운디드 컨텍스트를 찾아 도메인에 맞게 바운디드 컨텍스트를 조절하고 사업의 핵심 도메인을 위한 집중 컨텍스트 파악에 도움을 줌
- 컨텍스트 관계가 바뀌면 컨텍스트 맵도 함께 바뀌어야 함
- 바운디드 컨텍스트 간의 관계를 표시
'DESIGN PATTERN & ARCHITECTURE' 카테고리의 다른 글
가상 면접 사례로 배우는 대규모 시스템 설계 기초 - 2장) 개략적인 규모 추정 (0) 2024.10.21 가상 면접 사례로 배우는 대규모 시스템 설계 기초 - 1장) 사용자 수에 따른 규모 확장성 (2) 2024.10.21 도메인 주도 개발 시작하기 CH.6 ~ CH.7 (0) 2024.06.26 도메인 주도 개발 시작하기 CH.4 ~ CH.5 (0) 2024.06.19 도메인 주도 개발 시작하기 CH.1 ~ CH.3 (0) 2024.06.10 - 애그리거트와 트랜잭션