1. 2PL (Two-Phase Locking) - 2단계 잠금

목적 : 트랜잭션의 일관성직렬 가능성(Serializability) 보장

동작방식 : 트랜젝션이 자원(데이터)에 접근할때 락을 걸고 트랜젝션이 완료될 때까지 락을 유지 

단계 락 획득(확장) → 락 해제(축소)

장점:

직렬 가능성 보장: 트랜잭션 간의 충돌을 방지하여 데이터 일관성 유지

단점:

교착 상태(Deadlock) 발생 가능성: 트랜잭션이 서로의 락을 기다리며 멈추는 상황 발생

성능 저하: 락으로 인한 병목 현상

 

2. 2PC (Two-Phase Commit) - 2단계 커밋

목적 : 분산 트랜잭션 환경에서 원자성(Atomicity) 보장

여러 노드(데이터베이스) 간의 트랜잭션이 모두 성공하거나 모두 실패하도록 하는 프로토콜

동작방식 : Coordinator(조정자)와 여러 Participant(참여자) 간의 두 단계 절차로 진행

단계 준비(Prepare) → 커밋/롤백(Commit/Rollback)

장점:

원자성 보장: 모든 노드가 동일한 상태로 유지됨

데이터 일관성 유지: 분산 환경에서도 데이터 불일치 방지

 

단점:

Coordinator 장애 시 문제 발생: 장애 복구가 복잡

성능 저하: 네트워크 지연, 트랜잭션 대기 시간 증가

더보기

2PL은 데이터베이스 트랜잭션의 동시성 제어에 초점을 맞춘 기술

주로 단일 데이터베이스 환경에서 사용

2PC분산 환경에서 트랜잭션의 원자성을 보장하는 프로토콜

여러 데이터베이스 간의 트랜잭션 일관성을 유지할 때 사용

 

둘 다 데이터 일관성을 유지하기 위한 방법이지만, 적용되는 환경과 중점이 다름 

'Database' 카테고리의 다른 글

CQRS 패턴  (0) 2025.02.05
더보기

command (write) > 마스터만 보게 ,

쿼리 (조회) > 슬레이브만 보게

 

"프로젝트의 패키지 구조 및 컨벤션"

ex . PaymentService = paymentCommandService + paymentQueryService

DB > M / S Application > CQRS

 

부하를 줄여준다

1. CQRS패턴이란 ?

명령(Command)과 질의(Query)의 책임(Responsebilitiy)을 분리(Segregation)하여 시스템의 복잡성을 관리하는 아키텍쳐 패턴

쓰기를 위한 데이터 모델(Write Model)과 읽기를 위한 데이터 모델(Read Model)을 분리하는 패턴

복잡한 도메인 로직과 읽기/쓰기 요구사항이 뚜렷하게 다른 시스템에서 유용

 

1-1. 명령 모델(Command Model)

- 데이터를 변경하는 작업(쓰기 작업)을 처리

- 특정 명령을 받아서 비즈니스 로직과 유효성 검사를 수행하고, 데이터를 변경

- 일반적으로 서비스 로직과 관련이 있고, 데이터 생성, 수정, 삭제와 같은 작업을 담당

1-2. 쿼리 모델(Query Model)

- 데이터를 조회하는 작업(읽기 작업)을 처리

- 최적화된 읽기 작업을 위해 종종 데이터를 별도의 형태로 저장

- 데이터베이스나 다른 저장소에서 데이터를 읽고 결과를 반환하는 역할을 담당

 

2. 적용 방법

- 1단계 : 단일 Data Store 에 단일 어플리케이션 내에서 분리된 계층으로 나누는 방식

- 2단계 : 다중 DB , Broker를 통해서 이중화 된 데이터베이스를 동기화

- 3단계 : 이벤트 소싱(Event Sourcing) 패턴  (어플리케이션 내의 모든 처리 내용을 이벤트로 전환해서 이벤트 스트림을 별도의 DB에 저장하는 방식)

 

 

3. 장점과 단점

3-1. 장점 

1. 확장성 (Scalability)

읽기 쓰기 분리로 각각 독립적으로 확장 가능

읽기 요청이 많은 시스템에서는 조회 부분만 별도로 최적화하거나 확장 가능 

2. 성능 최적화 (Performance Optimization) 

읽기 모델과 쓰기 모델을 각각 최적화 할 수 있음 

예를 들어 조회 쿼리는 캐싱(Redis) , 비정규화된 데이터 구조 등을 활용하여 빠르게 처리 가능 

3. 복잡성 관리(Separation of Concerns)

비즈니스 로직(쓰기)와 조회 로직을 분리하여 코드가 명확하고 유지보수가 쉬워짐 

4. 유연한 데이터 모델링

읽기와 쓰기에 서로 다른 데이터 모델을 사용할 수 있어 각 요구사항에 맞는 데이터 구조 설계가 가능 

5. 이벤트 소싱(Event Sourcing)과의 시너지  (이건 잘 이해가 안간다 ) 

데이터 변경 이력을 그대로 저장하고 재구성 가능 

감사추적 (Audit Trail) 이나 복구 기능에 유리 

6. 보안 강화

쓰기와 읽기 모델이 분리되므로 권한 제어를 더 정교하게 설정 가능 

예: 읽기 전용 API와 쓰기 전용 API 분리

 

3-2. 단점 

1. 복잡성 증가

읽기/쓰기 모델 간의 동기화 관리가 필요

2. 데이터 일관성 문제 

읽기 모델과 쓰기 모델 간의 최종 일관성(Eventual Consistency) 문제가 발생 가능 

실시간으로 데이터를 반영해야 하는 시스템에는 부적합할 수 있다 

3. 개발 및 유지보수 비용 증가

초기 개발 비용과 유지보수 비용이 증가

배포, 테스트, 디버깅 과정이 더 복잡해질 수도 있다 

4. 이벤트 관리의 어려움 

이벤트 소싱과 함께 사용할 경우, 이벤트 버전 관리나 이벤트 스토어 관리가 까다로울 수 있음

5. 적용이 불필요할 수도 있음

단순한 CRUD 기반 애플리케이션에서는 오히려 과한 설계가 될 수 있으며, 단순한 요구사항에 CQRS를 적용하면 오히려 개발 속도 저하로 이어질 수 있음

 

* CQRS가 적합한 경우

• 복잡한 도메인 로직을 다루는 시스템 (ex. 금융 거래 시스템, 전자상거래 플랫폼)

• 읽기/쓰기 비율이 불균형한 시스템 (ex. 읽기 요청이 월등히 많은 경우)

• 확장성과 성능이 중요한 시스템

• 이벤트 소싱을 필요로 하는 시스템

 

* CQRS가 불필요한 경우

• 단순한 CRUD 애플리케이션

• 작은 팀이나 짧은 개발 주기를 가진 프로젝트

• 실시간 강력한 일관성이 필요한 시스템

 

예시  

프로젝트 구조 

src/main/java/com/example/cqrs/
│
├── command/
│   ├── controller/
│   │   └── ProductCommandController.java
│   ├── service/
│   │   └── ProductCommandService.java
│   └── model/
│       └── Product.java
│
├── query/
│   ├── controller/
│   │   └── ProductQueryController.java
│   ├── service/
│   │   └── ProductQueryService.java
│   └── dto/
│       └── ProductDTO.java
└── repository/
    └── ProductRepository.java

	•	command/: 쓰기(등록, 수정, 삭제) 책임
	•	query/: 읽기(조회) 책임
	•	repository/: 데이터 저장소 (공통)

 

참고

https://terrys-tech-log.tisory.com/48

https://f-lab.kr/insight/understanding-cqrs

 

'Database' 카테고리의 다른 글

2PL (Two-Phase Locking) vs 2PC (Two-Phase Commit)  (0) 2025.02.05