Q.이벤트 드리븐 아키텍처란?
서비스가 서로를 직접 부르지 않고 일어난 사실을 알리고, 관심 있는 쪽이 반응하는 구조입니다.
| 항목 | 명령 방식 | 이벤트 방식 |
|---|
| 메시지 성격 | 이것을 해달라 | 이런 일이 있었다 |
| 아는 대상 | 누구에게 시키는지 안다 | 누가 듣는지 모른다 |
| 추가 | 부르는 쪽을 고쳐야 한다 | 구독자를 새로 붙이면 된다 |
| 흐름 파악 | 코드를 따라가면 보인다 | 흩어져 있어 어렵다 |
주문이 생겼을 때를 비교하면 이렇습니다.
| 방식 | 주문 서비스가 하는 일 |
|---|
| 명령 | 재고 차감을 호출하고, 알림 발송을 호출하고, 적립을 호출한다 |
| 이벤트 | "주문 생성됨" 을 발행한다. 나머지는 각자 구독한다 |
두 번째에서 적립 기능을 추가할 때 주문 서비스를 고치지 않는다는 것이 이 구조의 값입니다.
| 대가 | 내용 |
|---|
| 흐름이 보이지 않는다 | 누가 무엇에 반응하는지 코드에 안 나온다 |
| 결과적 일관성 | 즉시 반영되지 않는다 |
| 디버깅 | 트레이싱 없이는 추적이 어렵다 |
| 계약 관리 | 이벤트 형식을 바꾸면 모르는 구독자가 깨진다 |
흔한 실수: 이벤트에 명령을 담는 것. "재고를 차감하라"는 이벤트가 아니라 명령입니다. 이벤트는 이미 일어난 사실을 과거형으로 알리고, 무엇을 할지는 받는 쪽이 정합니다.
Q.동기 vs 비동기 통신 트레이드오프는?
| 항목 | 동기 | 비동기 |
|---|
| 결과 확인 | 즉시 | 나중에. 별도 경로 필요 |
| 지연 | 상대의 시간이 내 응답에 더해진다 | 내 응답은 빠르다 |
| 장애 전파 | 상대가 느리면 나도 느려진다 | 상대가 죽어도 메시지는 남는다 |
| 부하 완충 | 없다. 그대로 전달된다 | 큐가 받아 둔다 |
| 오류 처리 | 실패를 바로 알려준다 | 재시도와 실패 큐를 설계해야 한다 |
| 흐름 파악 | 쉽다 | 어렵다 |
| 일관성 | 즉시 | 결과적 |
판단 기준은 사용자가 그 결과를 지금 알아야 하는가입니다.
| 상황 | 선택 |
|---|
| 결제 승인 | 동기. 결과 없이는 다음 화면을 못 만든다 |
| 주문 확정 후 알림 | 비동기. 지금 알 필요가 없다 |
| 재고 차감 | 동기. 실패하면 주문을 받을 수 없다 |
| 통계 집계 | 비동기 |
한 요청 안에서 섞는 것이 보통입니다. 꼭 필요한 것만 동기로 처리하고 나머지를 큐로 넘기면, 응답은 빠르고 실패 지점은 줄어듭니다.
흔한 실수: 비동기가 더 빠르다고 답하는 것. 전체 처리 시간은 오히려 늡니다. 짧아지는 것은 사용자가 기다리는 구간입니다.
Q.이벤트 소싱(Event Sourcing)이란?
현재 상태를 저장하지 않고 변경 사건을 순서대로 저장하는 방식입니다. 상태는 그 사건들을 재생해서 만듭니다.
| 방식 | 저장하는 것 |
|---|
| 일반 | 잔액 = 8,000원 |
| 이벤트 소싱 | 입금 10,000 → 출금 3,000 → 입금 1,000 |
| 얻는 것 | 내용 |
|---|
| 완전한 이력 | 언제 왜 바뀌었는지 전부 남는다 |
| 과거 상태 재현 | 특정 시점으로 되돌려 볼 수 있다 |
| 감사 | 금융이나 회계에서 요구하는 추적성 |
| 사후 분석 | 나중에 필요해진 집계를 과거 데이터로 만들 수 있다 |
| 대가 | 내용 |
|---|
| 조회가 어렵다 | 현재 상태를 얻으려면 재생해야 한다 |
| 스냅샷 필요 | 사건이 많아지면 중간 상태를 저장해 둬야 한다 |
| 이벤트 변경 불가 | 저장된 사건은 못 고친다. 보정 사건을 추가한다 |
| 학습 비용 | 팀 전체가 이 모델을 이해해야 한다 |
그래서 전면 도입보다 이력과 감사가 중요한 일부 영역에만 쓰는 편이 현실적입니다. 잔액 변동, 주문 상태 변화 정도입니다.
흔한 실수: 이벤트 드리븐 아키텍처와 같은 것으로 보는 것. 전자는 저장 방식이고 후자는 서비스 간 통신 방식입니다. 각각 따로 쓸 수 있습니다.
Q.CQRS 패턴을 설명해주세요
쓰기 모델과 읽기 모델을 분리하는 패턴입니다. 같은 데이터를 다루지만 구조를 따로 둡니다.
| 측면 | 쓰기 모델 | 읽기 모델 |
|---|
| 최적화 대상 | 정합성과 규칙 검증 | 조회 속도 |
| 구조 | 정규화 | 화면에 맞게 미리 합쳐 둔 형태 |
| 저장소 | 관계형 DB | 검색 엔진, 캐시, 별도 테이블 |
분리하는 이유는 두 요구가 충돌하기 때문입니다. 쓰기는 정규화가 유리하고, 조회는 조인 없이 한 번에 읽는 편이 빠릅니다. 하나의 모델로는 둘 다 만족하기 어렵습니다.
동기화는 이벤트로 합니다. 쓰기가 일어나면 이벤트를 발행하고 읽기 모델을 갱신합니다. 그래서 읽기 모델은 항상 조금 뒤처집니다.
| 대가 | 내용 |
|---|
| 결과적 일관성 | 쓴 직후 조회에 반영되지 않을 수 있다 |
| 복잡도 | 모델이 둘, 동기화 경로가 하나 늘어난다 |
| 정합성 점검 | 두 모델이 어긋났는지 확인할 절차가 필요하다 |
흔한 실수: 읽기와 쓰기를 분리하니 무조건 도입하는 것. 조회 요구가 특별히 복잡하지 않으면 대가만 남습니다. 그리고 읽기 전용 복제본을 쓰는 것과 혼동하기 쉬운데, 복제본은 같은 모델의 사본이고 CQRS 는 모델 자체가 다릅니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
메시징 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.