4. 설계는 결과
• 나는 JOIN 구문을 싫어하지 않음
• 나는 관계형 데이터베이스도 싫어하지 않음
• 데이터베이스 선택은 설계
• 설계의 목적은 도메인 요구사항
5. 새로운 설계 기법을 익히는 것은
• 기존 설계 기법을 배척하기 위함이 아님
• 도메인 요구사항을 만족시키기 위한 선택지를 늘리는 것
6. 기본 설계 원칙
• 높은 응집(High Cohesion)
• 낮은 결함(Low Coupling)
• 정보 숨김(Information Hiding)
7. 오마이랩 기술 팀 소개
• CTO 포함 프로그래머 4인
• 시니어 2인/ 주니어 2인(신입 1인)
• 글로벌 Multitenant 호텔 상품 관리 서비스 개발 중
• Multitenant 서비스 개발 경험자 없음
• 제품 관리자(Product Manager) 없음
• 디자이너 없음
• 거대 경쟁사들
• 경영진의 빠른 출시 요구
• Startup이 아님
9. 시스템 설계 요구사항
• 메시지 중심(Message-Driven)
• 다중입주(Multitenancy)
• 구독 모델(Subscription Business Model)
• 확장성(Scalability)
• 엄격한 인증 및 권한부여(Authentication and Authorization)
• 높은 반응성(Responsive)
• 다중 지역 배치(Multi-region Deployment)
• 감사 기록(Audit Log)
• 무중단(No Downtime)
11. 모놀리스(Monolith)
• 하나의 응용프로그램
• 하나의 데이터베이스
• 단순한 구조
• 만들기 쉬움
• 이해하기 쉬움
• 코드가 결합되기 쉬움
• 심각하지만 견딜만 함
• 데이터가 결합되기 쉬움
• 기능을 변경하거나 추가하기 여러움
• 매우 심각함
12. 사용자 관리
• 사용자 정보가 다른 기능과 결합되면 설계 변경이 어려움
• 직접 경험
• 적지 않은 간접 경험
• 다중입주를 위한 권한관리 기능을 분리하면 설계와 운영에 도움
• IAM(Identity and Access Management, IAM) 기능을 독립된 구성요소로 분리
13. 구독 모델
• 구독 모델은 ‘채널 관리자’보다는 ‘클라우드 서비스’와 관련
• 구독 수준에 따른 서비스 접근 관리
• 과금 청구
• 회계 시스템 연동
• 서비스 입주자(Tenant)의 구독에 따른 접근 관리가 핵심
• 서비스(채널 관리자)에 혼합되면 설계 복잡도와 변경 비용이 상승
• 서비스 구독 관리 기능을 독립된 구성요소로 분리
14. API Gateways
• 3개의 UI 응용프로그램
• 호텔 운영자 응용프로그램
• 채널 운영자 응용프로그램
• 내부 관리자 응용프로그램
• 시스템 통합(System Integration) 목적의 공개 API
• 사용자 및 입주자에 따른 서비스 접근 관리
19. 채널 관리자 – 채널 간 시스템 통합
질의에 의한 통합
• 채널이 채널 관리자에게
• “재고가 몇 개야?”
이벤트에 의한 통합
• 채널 관리자가 채널에게
• “재고가 n개로 변경되었어.”
20. Azure Event Hubs
• 실시간 대용량 데이터 스트림 서비스
• 소비자 그룹(Consumer Groups)
• 발행/ 구독 패턴
• 서비스 간 약한 결합
• 메시지 분할(Partitions)
• 분할 키
• 하나의 분할에 대해 하나의 소비자 그룹은 동시에 최대 하나의 처리기 등록 가능
• 메시지 순서 관리
• 동시성 처리
• 메시지 처리자 수평 규모 확장 고려
• 메시지 보존(Capture)
• Azure Blob Storage/ Azure Data Lake Store
• Apache Avro 구조
21. Service B
Service A
소비자 그룹과 분할
Instance
Instance
Instance
Instance
Instance
Partition 1
Partition 2
Partition 3
Partitioning
ConsumerGroupAConsumerGroupB
ScaleScale
23. 이벤트에 의한 외부 서비스 통합
Event
Publisher
Service
Service
Service
Service
Message
Broker
Service
Services Service
External
Service
External
Service
External
Service
Event Message
25. 안정적인 이벤트 발행
• 이벤트 수신자(채널) 장애 상황 고려
• 비동기(Asynchronous)
• 최소 일 회 배달(At-Least-Once Delivery)
26. 이벤트 소싱(Event Sourcing)
• 도메인에서 발생하는 모든 이벤트를 기록
• 동사(이벤트 이름) + 명사(이벤트 속성)
• 상태는 일련의 이벤트의 결과
• 특정 시점의 상태를 복원 가능
• 임피던스 불일치(Impedance Mismatch)가 존재하지 않음
• 최소 일 회 배달 구현 용이
• 가장 신뢰할 수 있는 감사 기록
• 이벤트 저장소
27. Azure Table Storage
• NoSQL 키-값 저장소
• 단순한 구조
• 데이터 분할(Partitioning)
• 높은 성능
• 상대적으로 저렴한 비용
• 최대 500TiB 테이블 크기
• 최대 1MiB 엔터티 크기
28. Azure SQL Database
• Database as a Service
• DTU
• 4TB maximum storage
• Singleton/ Elastic Pool
• Monitoring and Tuning
29. 이벤트 저장소
Azure Table Storage
• 500TiB
• 높은 가격 대 성능 비
• 키-값
• 키: {object-type}*{object-id}*{version}
• 값: 이벤트 데이터
• 우선 고려 대상
SQL Database
• 4TB
• 개체 속성에 Unique Index 적용
• 사용자 계정
• Username
• Email
• Unique Index가 정말로 필요한가?
30. 롤링 스냅샷(Rolling Snapshot)
• 역사가 긴(많은 이벤트를 가진) 집합체
• 개체 복원 성능을 높이기 위해 주기적으로 최근의 상태를 저장
• Memento Pattern
Event 3
Event 2
Event 1
…
Σ(i=1, N–2) Event i
Event N
Event N-1
Event N-2
Snapshot
31. 롤링 스냅샷 저장소
• 키-값
• 키: {object-id}
• 값
• 버전
• 직렬화 된 개체 상태
• Azure Blob Storage
33. CQRS(Command and Query Responsibility Segregation)
• 상태 변경 책임과 상태 질의 책임을 분리하는 설계 기법
• 책임을 분리하는 수준은 다양함
• 개체
• 도메인 논리
• 데이터베이스
• 서비스
• 이벤트 소싱
• 이벤트 소싱은 질의 기능에 대한 다양한 비즈니스 요구를 충족하지 못함
• 데이터베이스 이상 수준의 CQRS 조합이 사실상 필수
34. 채널 관리자 인벤토리 그리드(Inventory Grid)
• 지정한 기간 내 다수 엔터티의 상태를 한 번에 표시
• 2~4주 시간 범위(Time Window)
• 각 엔터티는 일 별 데이터를 포함
• 엔터티는 십 여 개에서 최대 천 개 이상도 가능
35. 채널 관리자 인벤토리 그리드(Inventory Grid)
Date Date Date Date Date Date Date Date Date Date
RoomType
RoomType
RoomRate
RoomRate
RoomRate
Channel
Channel
Channel
Channel
36. 인벤토리 그리드 전통적 데이터 설계
• 전통적 방식에서 데이터의 물리적 배치 기준은 엔터티
• 상태를 변경하는 작업에 유리
• 하나의 엔터티에 포함된 일 별 데이터는 다양한 속성을 공유
• 인벤토리 그리드 질의 기능에 불리
• 다수의 엔터티
• 물리적으로 분산된 데이터를 조회
• 관계형 데이터베이스를 사용할 경우 무거운 JOIN 구문 실행
37. 엔터티 단위 인벤토리 분리
Date Date Date Date Date Date Date Date Date Date
RoomType
RoomType
RoomRate
RoomRate
RoomRate
Channel
Channel
Channel
Channel
38. 인벤토리 그리드와 CQRS
Command Side
• 변경 작업 기준의 데이터 분리
• 집합체(Aggregate)
Query Side
• 1개월 단위 패키지
• 키-값
• 키: {tenant-id}*{year}*{month}
• 값: 직렬화 된 그리드 데이터
39. 월 단위 인벤토리 읽기 모델 분리
Date Date Date Date Date Date Date Date Date Date
RoomType
RoomType
RoomRate
RoomRate
RoomRate
Channel
Channel
Channel
Channel
Key-Value Key-Value
40. 낙관적 명령 검사와 낙관적 갱신
• 최종 일관성(Eventual Consistency)
• 읽기 데이터베이스 완전 신뢰 불가
• 읽기 데이터베이스 기준의 낙관적 명령 유효성 검사
• 클라이언트는 낙관적 명령 검사 결과 기준의 낙관적 뷰 갱신
• 확장성, 반응성, 복원성, 일관성 등 중 어떤 가치가 더 중요한 지
도메인 기준으로 판단
41. CQRS와 비동기 분산 명령 프로세스
UI
Read Model
Generator
Message BusAPI
Read Model
Database
Command
Processor
Event Store
Validate Command
Optimistically
Command
Command
Acceptance
Command Command
Raise Event
Update
Update View
Optimistically
1
2
4
5
3 6
7
8
45. 전역 트래픽 지연 최소화
• 코드 다중 지역 배치
• Azure Traffic Manager
• 위성 지역 명령 전달자
• 위성 지역 데이터 배치
• 데이터 읽기 지연 최소화
• 낙관적 명령 유효성 검사
46. 다중 지역 배치
Hub Region
Message Bus
Domain Model
Read Model
Satellite Region A
API
Command Forwarder
Read Database Replica
Satellite Region B
API
Command Forwarder
Read Database ReplicaReplicate Replicate
Commands Commands
47. Azure Cosmos DB
• 턴키 전역 배포(Turnkey Global Distribution)
• 다중 모델 API
SQL API, MongoDB API, Casandra API, Graph API, Table API and more …
• 쉬운 수평 규모 확장(Horizontal Scale)
• 데이터 분할(Partitioning)
• 컨테이너 별 과금
• 최대 2 MB SQL API 문서 크기
48. 전역 배치 비동기 분산 명령 프로세스
Command Forwarder
<< Service Bus >>
Message Broker
<< Event Hub >>
Processors
<< App Services >>
Event Store
<< Table Storage, SQL Database >>
Read Database
<< Cosmos DB >>
Read Database Replica
<< Cosmos DB >>
API
<< API App >>
UI(SPA)
<< Web App >>
Load Balancer
<< Traffic Manager >>
Satellite Region Hub Region
Validate Command
Optimistically
Replicate
Update Read Model
Command AcceptanceCommand
Update View Optimistically
1
2
3
4
5
6
7 8
9
10
11