- 좋은 설계는 운영 관리의 편의성, 비용, 개선 및 개발 용이성 등의 다양한 주제를 오랜 시간 동안 고단하고 탐구한 끝에 탄생함
- 문제 이해 및 설계 범위 확정
- 비기능 요구사항
- 낮은 응답 지연(latency) : 사용자는 주변 사업장을 신속히 검색할 수 있어야 함
- 데이터 보호(data privacy) : 사용자 위치는 민감한 정보. 위치 기반 서비스(LBS)를 설계할 때는 언제나 사용자의 정보를 보호할 방법을 고려해야 함. GDPR,CCPA 같은 데이터 사생활 보호 법안을 준수하도록 해야 함
- 고가용성(high availability) 및 규모 확장성(scalability) 요구사항 : 인구 밀집 지역에서 이용자가 집중되는 시간에 트래픽이 급증해도 감당할 수 있도록 시스템을 설계해야 함
- 비기능 요구사항
- 개략적 설계안 제시 및 동의 구하기
- API 설계
- 사업장 관련 API
- GET : 특정 사업장의 상세 정보 반환
- POST : 새로운 사업장 추가
- PUT : 사업장 상세 정보 갱신
- DELETE : 특정 사업장 정보 삭제
- 사업장 관련 API
- 데이터 모델
- 읽기 연산이 압도적인 시스템에는 MySQL 같은 관계형 데이터베이스가 바람직할 수 있음
- 개략적 설계
- 로드밸런서
- 유입 트래픽을 자동으로 여러 서비스에 분산시키는 컴포넌트
- 통상적으로 로드밸런서를 사용하는 회사는 로드밸런서에 단일 DNS 진입점(entry point)을 지정하고, URL 경로를 분석하여 어느 서비스에 트래픽을 전달할지 결정함
- 데이터베이스 클러스터
- 주 데이터베이스는 쓰기 요청을 처리하며, 부 데이터 베이스, 즉 사본 데이터베이스는 읽기 요청을 처리함
- 주변 사업장 검색 알고리즘
- 해시 기반 방안: 균등 격자, 지오해시, 카르테시안 계층 등
- 트리 기반 방안 : 쿼드트리, 구글 S2, R 트리 등
- 지도를 작은 영역으로 분할하고 고속 검색이 가능하도록 색인을 만드는것. 지오해시, 쿼드트리, 구글 S2는 실제로 가장 널리 사용되는 방안
- 로드밸런서
- API 설계
- 상세 설계
- 지역 및 가용성 구역
- 기대 효과
- 사용자와 시스템 사이의 물리적 거리를 최소한으로 줄일 수 있음. 미국 서부 사용자는 해당 지역 데이터 센터로 연결될 것이고, 유럽 사용자는 유럽 데이터 센터로 연결될 것
- 트래픽을 인구에 따라 고르게 분산하는 유연성을 확보할 수 있음. 일본과 한국 같은 지역은 인구 밀도가 아주 높음. 그런 국가는 별도 지역으로 빼거나, 아예 한 지역 안에서도 여러 가용성 구역을 활용하여 부하를 분산시키는 것이 바람직할 수 있음
- 어떤 국가는 사용자 데이터를 해당 국가 이외의 지역으로 전송하지 못하도록 함. 그런 경우에는 해당 국가를 별도 지역으로 빼고, 해당 국가에서 발생하는 모든 트래픽은 DNS 라우팅을 통해 해당 지역 내 서비스가 처리하도록 해야 함
- 기대 효과
- 지역 및 가용성 구역
- 개략적 설계안 제시 및 동의 구하기
- RESTful API 서버
- 무상태(stateless) API 서버의 클러스터로서, 통상적인 요청/응답 트래픽을 처리함
- 레디스 위치 정보 캐시
- 레디스에 보관하는 캐시 항목에는 TTL(Time-To-Live) 필드가 있음. 이 기간이 지나면 해당 사용자는 비활성 상태로 바뀌고 그 위치 정보는 캐시에서 삭제됨
- 레디스 펍/섭 서버
- 레디스 펍/섭은 초경량 메시지 버스. 레디스 펍/섭에 새로운 채널을 생성하는 것은 아주 값싼 연산
- RESTful API 서버
- 상세 설계
- 레디스 펍/섭 서버
- 구독자가 없는 채널로 전송된 메시지는 그대로 버려지는데, 그 과정에서 서버에 가해지는 부하는 거의 없음
- 채널 하나를 유지하기 위해서는 구독자 관계를 추적하기 위해 해시 테이블과 연결 리스트가 필요한데 아주 소량의 메모리만을 사용함
- 레디스 펍/섭 서버
- 상세 설계
- 카프카는 응답 지연이 낮고 많은 데이터를 동시에 처리할 수 있는 데이터 스트리밍 플랫폼으로, 실시간 데이터 피드를 지원하기 위해 고안되었음
- 메시지 큐를 사용하면 이득
- 결합도 완화(decoupling) : 메시지 큐를 사용하면 컴포넌트 사이의 강한 결합이 사라지므로 각각을 독립적으로 갱신할 수 있음
- 규모 확장성 개선 : 메시지 큐에 데이터를 생산하는 생산자와 큐에서 메시지를 소비하는 소비자 시스템 규모를 트래픽 부하에 맞게 독립적으로 늘릴 수 있음
- 가용성 개선 : 시스템의 특정 컴포넌트에 장애가 발생해도 다른 컴포넌트는 큐와 계속 상호작용을 이어갈 수 있음
- 성능 개선 : 메시지 큐를 사용하면 비동기 통신이 쉽게 가능함. 생산자는 응답을 기다리지 않고도 메시지를 보낼 수 있고, 소비자는 읽을 메시지가 있을 때만 해당 메시지를 소비하면 됨
- 유명 분산 메시지 큐
- 아파치 카프카
- 아파치 RocketMQ
- 아파치 RabbitMQ
- 아파치 펄사
- 아파치 ActiveMQ
- ZeroMQ
- 메시지 큐 대 이벤트 스트리밍 플랫폼
- 전형적인 메시지 큐 RabbitMQ는 옵션으로 제공되는 스트리밍 기능을 추가하면 메시지를 반복적으로 소비할 수 있는 동시에 데이터의 장기 보관도 가능함. 그 기능은 데이터 추가만 가능한 로그를 통해 구현되어 있는데, 이벤트 스트리밍 플랫폼 구현과 유사함
- 아파치 펄사는 기본적으로 카프카의 경쟁자이지만, 분산 메시지 큐로도 사용이 가능할 정도로 유연하고 성능도 좋다
- 데이터 장기 보관, 메시지 반복 소비 등의 부가 기능을 갖춘 분산 메시지 큐를 설계
- 문제 이해 및 설계 범위 확정
- 메시지 큐의 기본 기능 - 생산자는 메시지를 큐에 보내고, 소비자는 큐에서 메시지를 꺼낼 수 있으면됨
- 메시지 전달방식, 데이터 보관기간 등 고려할 사항은 다양함
- 메시지의 형태와 평균 크기, 텍스트 메시지만 지원하면 됨? 멀티미디어도 지원?
- 메시지는 반복적으로 소비될 수 있어야 하나요? 메시지를 여러 소비자에게 수신하는 것이 가능해야 함
- 메시지는 큐에 전달된 순서대로 소비되어야 하나요?
- 데이터의 지속성이 보장되어야 하나요? 기간은 얼마 동안인가요?
- 지원해야 하는 생산자와 소비자 수는 어느 정도입니까?
- 어던 메시지 전달 방식을 지원해야 하나요? 최대 한 번, 최소 한 번, 정확히 한번
- 목표로 삼아야 할 대역폭과 단대단 지연 시간을 알려주 실 수 있으실 까요?
- 기능 요구사항
- 생산자는 메시지 큐에 메시지를 보낼 수 있어야 함
- 소비자는 메시지 큐를 통해 메시지를 수신할 수 있어야 함
- 메시지는 반복적으로 수신할 수도 있어야 하고, 단 한 번만 수신하도록 설정될 수도 있어야 함
- 오래된 이력 데이터는 삭제될 수 있음
- 메시지 크기는 킬로바이트 수준
- 메시지가 생산된 순서대로 소비자에게 전달할 수 있어야 함
- 메시지 전달 방식은 최소 한 번, 최대 한 번, 정확히 한 번 가운데 설정할 수 있어야 함
- 비기능 요구사항
- 높은 대역폭과 낮은 전송 지연 가운데 하나를 설정으로 선택 가능하게 하는 기능
- 규모 확장성, 이 시스템은 특성상 분산 시스템일 수밖에 없음. 메시지 양이 급증해도 처리 가능해야 함
- 지속성 및 내구성, 데이터는 디스크에 지속적으로 보관되어야 하며 여러 노드에 복제되어야 함
- 전통적 메시지 큐와 다른점
- RabitMQ와 같은 전통적인 메시지 큐는 이벤트 스트리밍 플랫폼처럼 메시지 보관 문제를 중요하게 다루지 않음
- 개략적 설계안 제시 및 동의 구하기
- 메시지 큐의 기본 기능
- 생산자는 메시지를 메시지 큐에 발행
- 소비자는 큐를 구독하고 구독한 메시지를 소비
- 메시지 큐는 생산자와 소비자 사이의 결합을 느슨하게 하는 서비스로, 생산자와 소비자의 독립적인 운영 및 규모 확장을 가능하게 하는 역할 담당
- 생산자와 소비자는 모두 클라이언트/서버 모델 관점에서 보면 클라이언트고 서버 역할을 하는 것은 메시지 큐이며 이 클라이언트와 서버는 네트워크를 통해 통신
- 메시지 모델
- 메시지 모델은 일대일과 발행-구독 모델
- 일대일 모델
- 큐에 전송된 메시지는 오직 한 소비자만 가져갈 수 있음
- 어떤 소비자가 메시지를 가져갔다는 사실을 큐에 알리면 해당 메시지는 큐에서 삭제됨
- 이 모델은 데이터 보관을 지원하지 않음
- 발행-구독 모델
- 토픽은 메시지를 주제별로 정리하는 데 사용됨
- 각 토픽은 메시지 큐 서비스 전반에 고유한 이름을 가짐
- 메시지를 보내고 받을 때는 토픽에 보내고 받게 됨
- 토픽,파티션,브로커
- 토픽에 보관되는 데이터의 양이 커져서 서버 한 대로 감당하기 힘든 상황이 벌어지면 어떻게 될까?
- 파티션,즉 샤딩 기법을 활용. 토픽을 여러 파티션으로 분할한 다음에 메시지를 모든 파티션에 균등하게 나눠 보냄
- 파티션은 메시지 큐 클러스터 내의 서버에 고르게 분산 배치함. 파티션을 유지하는 서버는 보통 브로커라 부름.
- 파티션을 브로커에 분산하는 것이 높은 규모 확장성을 달성하는 비결. 토픽의 용량을 확장하고 싶으면 파티션 개수를 늘리면 되기 때문
- 소비자 그룹
- 같은 그룹 내의 소비자는 메시지를 병렬로 소비할 수 있음
- 데이터를 병렬로 읽으면 대역폭 측면에서는 좋지만 같은 파티션 안에 있는 메시지를 순서대로 소비할 수는 없음
- 한 가지 제약사항을 추가하면 이 문제를 해결. 어떤 파티션의 메시지는 한 그룹 안에서는 오직 한 소비자만 읽을 수 있도록 하는 것
- 그룹 내 소비자의 수가 구독하는 토픽의 파티션 수보다 크면 어떤 소비자는 해당 토픽에서 데이터를 읽지 못하게 됨
- 개략적 설계안
- 클라이언트
- 생산자 : 메시지를 특정 토픽으로 보냄
- 소비자 그룹 : 토픽을 구독하고 메시지를 소비함
- 브로커 : 파티션들을 유지함. 하나의 파티션은 특정 토픽에 대한 메시지의 부분 집합을 유지함
- 저장소
- 데이터 저장소 : 메시지는 파티션 내 데이터 저장소에 보관됨
- 상태 저장소 : 소비자 상태는 이 저장소에서 유지됨
- 메타데이터 저장소 : 토픽 설정, 토픽 속성 등은 이 저장소에 유지됨
- 조정 서비스
- 서비스 탐색 : 어떤 브로커가 살아있는지 알려줌
- 리더 선출 : 브로커 가운데 하나는 컨트롤러 역할을 담당해야 하며, 한 클러스터에는 반드시 활성 상태 컨트롤러가 하나 있어야 함. 이 컨트롤러가 파티션 배치를 책임짐
- 아파치 주키퍼나 etcd가 보통 컨트롤러 선출을 담당하는 컴포넌트로 널리 이용됨
- 클라이언트
- 메시지 큐의 기본 기능
- 상세 설계
- 데이터의 장기 보관 요구사항을 만족하면서 높은 대역폭을 제공
- 회전 디스크의 높은 순차 탐색 성능과 현대적 운영체제가 제공하는 적극적 디스크 캐시 전략을 잘 이용하는 디스크 기반 자료 구조를 활용할 것
- 메시지가 생산자로부터 소비자에게 전달되는 순간까지 아무 수정 없이도 전송이 가능하도록 하는 메시지 자료 구조를 설계하고 활용할 것
- 일괄 처리를 우선하는 시스템을 설계할 것
- 생산자는 메시지를 일괄 전송하고, 메시지 큐는 그 메시지들을 더 큰 단위로 묶어 보관함. 소비자도 가능하면 메시지를 일괄 수신하도록 함
- 데이터 저장소
- 메시지 큐의 트래픽 패턴
- 읽기와 쓰기가 빈번하게 일어남
- 갱신/삭제 연산은 발생하지 않음
- 순차적인 읽기/쓰기가 대부분
- 데이터베이스
- 관계형 데이터베이스 : 토픽별로 테이블을 만듬. 토픽에 보내는 메시지는 해당 테이블에 새로운 레코드로 추가함
- NoSQL 데이터베이스 : 토픽별로 컬렉션을 만듬. 토픽에 보내는 메시지는 하나의 문서가 됨
- 쓰기 우선 로그(Write-Ahead Log, WAL)
- WAL은 새로운 항목이 추가되기만 하는(append-only) 일반 파일
- WAL은 다양한 시스템에서 사용되는 기술인데, MySQL의 복구 로그(redo log)가 WAL로 구현되어 있고 아파치 주키퍼도 해당 기술을 활용함
- 메시지 큐의 트래픽 패턴
- 메시지 자료 구조
- 메시지 키
- 메시지의 키는 파티션을 정할 때 사용됨
- 키가 주어진 경우 파티션은 hash(key) % numPartitions의 공식에 따라 결정됨
- 메시지 값
- 메시지 값은 메시지의 내용, 즉 페이로드를 말함
- 메시지의 기타 필드
- 토픽 : 메시지가 속한 토픽의 이름
- 파티션 : 메시지가 속한 파티션의 ID
- 오프셋 : 파티션 내 메시지의 위치. 메시지는 토픽, 파티션, 오프셋 세 가지 정보를 알면 찾을 수 있음
- 타임스탬프 : 메시지가 저장된 시각
- 크기 : 메시지의 크기
- CRC: 순환 중복 검사의 약자로 주어진 데이터의 무결성을 보장하는 데 이용됨
- 메시지 키
- 일괄 처리
- 일괄 처리가 성능 개선에 중요한 이유
- 운영체제로 하여금 여러 메시지를 한 번의 네트워크 요청으로 전송할 수 있도록 하기 때문에 값비싼 네트워크 왕복 비용을 제거할 수 있음
- 브로커가 여러 메시지를 한 번에 로그에 기록하면 더 큰 규모의 순차 쓰기 연산이 발생하고 운영체제가 관리하는 디스크 캐시에서 더 큰 규모의 연속된 공간을 점유하게 됨. 그 결과로 더 높은 디스크 접근 대역폭을 달성할 수 있음
- 높은 대역폭과 낮은 응답 지연은 동시에 달성하기 어려운 목표. 시스템이 낮은 응답 지연이 중요한 전통적 메시지 큐로 이용된다면 일괄 처리 메시지 양은 낮춤
- 디스크 성능은 다소 낮아짐. 처리량을 높여야 한다면 토픽당 파티션의 수는 늘림. 그래야 낮아진 순차 쓰기 연산 대역폭을 벌충할 수 있음
- 일괄 처리가 성능 개선에 중요한 이유
- 생산자 측 작업 흐름
- 라우팅 계층은 적절한 브로커에 메시지를 보내는 역할을 담당함
- 소비자 측 작업 흐름
- 푸시 모델
- 장점
- 낮은 지연: 브로커는 메세지를 받는 즉시 소비자에게 보낼 수 있음
- 단점
- 소비자가 메시지를 처리하는 속도가 생산자가 메시지를 만드는 속도보다 느릴 경우, 소비자에게 큰 부하가 걸릴 가능성이 있음
- 생산자가 데이터 전송 속도를 좌우하므로, 소비자는 항상 그에 맞는 처리가 가능한 컴퓨팅 자원을 준비해 두어야 함
- 장점
- 풀 모델
- 장점
- 메시지를 소비하는 속도는 소비자가 알아서 결정함
- 메시지를 소비하는 속도가 생산 속도보다 느려지면 소비자를 늘려 해결할 수도 있고, 아니면 생산 속도를 따라잡을 때까지 기다려도 됨
- 일괄 처리에 적합함
- 단점
- 브로커에 메시지가 없어도 소비자는 계속 데이터를 끌어가려 시도할것. 그 덕에 소비자 측 컴퓨팅 자원이 낭비됨.
- 이 문제를 그복하기 위해 많은 메시지 큐가 롱 풀링 모드를 지원함. 당장은 가져갈 메시지가 없더라도 일정 시간은 기다리도록 하는 것
- 장점
- 푸시 모델
- 상태 저장소
- 메시지 큐 브로커의 상태 저장소(state storage)에는 다음과 같은 정보가 저장됨
- 소비자에 대한 파티션의 배치 관계
- 각 소비자 그룹이 각 파티션에서 마지막으로 가져간 메시지의 오프셋
- 소비자 상태 정보 데이터가 이용되는 패턴
- 읽기와 쓰기가 빈번하게 발생하지만 양은 많지 않음
- 데이터 갱신은 빈번하게 일어나지만 삭제되는 일은 거의 없음
- 읽기와 쓰기 연산은 무작위적 패턴을 보임
- 데이터의 일관성이 중요함
- 데이터 일관성 및 높은 읽기/쓰기 속도에 대한 요구사항을 고려하였을 때, 주키퍼 같은 키-값 저장소를 사용하는 것이 바람직해 보임
- 한편 카프카는 오프셋 저장소로 주키퍼를 사용하다가 카프카 브로커로 이전하였음
- 메시지 큐 브로커의 상태 저장소(state storage)에는 다음과 같은 정보가 저장됨
- 메타데이터 저장소
- 메타데이터 저장소에는 토픽 설정이나 속성 정보를 보관함. 파티션 수, 메시지 보관 기간, 사본 배치 정보 등이 이에 해당함
- 메타데이터는 자주 변경되지 않으며 양도 적다. 하지만 높은 일관성을 요구함. 이런 데이터의 보관에는 주키퍼가 적절함
- 주키퍼
- 주키퍼는 계층적 키-값 저장소 기능을 제공하는, 분산 시스템에 필수적인 서비스
- 분산 설정 서비스, 동기화 서비스 그리고 이름 레지스트리 등으로 이용됨
- 메타데이터와 상태 저장소는 주키퍼를 이용해 구현함
- 브로커는 이제 메시지 데이터 저장소만 유지하면 됨
- 주키퍼가 브로커 클러스터의 리더 선출 과정을 도움
- 규모 확장성
- 생산자 : 생산자의 규모 확장성은 새로운 생산자를 추가하거나 삭제함으로써 쉽게 달성할 수 있음
- 소비자 : 소비자 그룹은 서로 독립적이므로 새 소비자 그룹은 쉽게 추가하고 삭제할 수 있음
- 브로커 노드가 추가 되거나 삭제될 때 사본을 재배치 함. 더 나은 방법으로는 브로커 컨트롤러로 하여금 한시적으로 시스템에 설정된 사본 수보다 많은 사본을 허용하도록 하는 것
- 파티션
- 토픽의 규모를 늘리거나, 대역폭을 조정하거나, 가용성과 대역폭 사이의 균형을 맞추는 등의 운영상 이유로 파티션의 수를 조정해야 하는 일이 생길 수 있음
- 메시지 전달 방식
- 최대 한번(at-most once)
- 메시지를 최대 한 번만 전달하는 방식. 메시지가 전달 과정에서 소실되더라도 다시 전달되는 일은 없음
- 생산자는 토픽에 비동기적으로 메시지를 보내고 수신 응답을 기다리지 않음. 메시지 전달이 실패해도 다시 시도하지 않음
- 소비자는 메시지를 읽고 처리하기 전에 오프셋부터 갱신함. 오프셋이 갱신된 직후에 소비자가 장애로 죽으면 메시지는 다시 소비될 수 없음
- 지표 모니터링 등, 소량의 데이터 손실은 감수할 수 있는 애플리케이션에 적합함
- 메시지를 최대 한 번만 전달하는 방식. 메시지가 전달 과정에서 소실되더라도 다시 전달되는 일은 없음
- 최소 한 번(at-least once)
- 같은 메시지가 한 번 이상 전달될 수는 있으나 메시지 소실은 발생하지 않는 전달 방식
- 생산자는 메시지를 동기적/비동기적으로 보낼 수 있으며, ACK=1 또는 ACK=all 구성을 이용함. 즉 메시지가 브로커에게 전달되었음을 반드시 확인함
- 메시지 전달이 실패하거나 타임아웃이 발생한 경우에는 계속 재시도할 것
- 소비자는 데이터를 성공적으로 처리한 뒤에만 오프셋을 갱신함.
- 메시지 처리가 실패한 경우에는 메시지를 다시 가져오므로 데이터가 손실되는 일은 없음
- 한편 메시지를 처리한 소비자가 미처 오프셋을 갱신하지 못하고 죽었다가 다시 시작하면 메시지는 중복 처리될 것
- 메시지는 브로커나 소비자에게 한 번 이상 전달될 수 있음
- 생산자는 메시지를 동기적/비동기적으로 보낼 수 있으며, ACK=1 또는 ACK=all 구성을 이용함. 즉 메시지가 브로커에게 전달되었음을 반드시 확인함
- 같은 메시지가 여러 번 전송될 수 있음
- 같은 메시지가 한 번 이상 전달될 수는 있으나 메시지 소실은 발생하지 않는 전달 방식
- 정확히 한 번(exactly once)
- 정확히 한 번은 구현하기 가장 까다로운 전송 방식
- 지불, 매매, 회계 등 금융 관련 응용에는 이 전송 방식이 적합함
- 최대 한번(at-most once)
- 데이터의 장기 보관 요구사항을 만족하면서 높은 대역폭을 제공
- 마무리
- 프로토콜(protocol)
- 프로토콜은 노드 사이에 옹고 가는 데이터 관한 규칙, 문법, 그리고 API를 규정함.
- 분산 메시지 큐 시스템의 경우 프로토콜은 다음 사항을 기술해야만 함
- 메시지 생산과 소비, 박동 메시지 교환 등의 모든 활동을 설명해야 함
- 대용량 데이터를 효과적으로 전송할 방법을 설명해야 함
- 데이터의 무결성을 검증할 방법을 기술해야 함
- 유명한 프로토콜로는 AMQP, 카프카 프로토콜 등이 있음
- 메시지 소비 재시도
- 제대로 받아 처리하지 못한 메시지는 일정 시간 뒤에 다시 처리를 시도해야 함
- 새로 몰려드는 메시지들이 제대로 처리되지 못하는 일을 막으려면, 어떻게 재시도하는 것이 좋을까?
- 한 가지 방법은 실패한 메시지는 재시도 전용 토픽에 보낸 다음, 나중에 다시 소비하는 것
- 이력 데이터 아카이브
- 시간 기반 혹은 용량 기반 로그 보관 메커니즘이 있다고 가정할 때, 이미 삭제된 메시지를 다시 처리하길 원하는 소비자가 있다면 어떻게 해야 할까?
- 한 가지 방법은 오래된 데이터는 HDFS 같은 대용량 저장소 시스템이나 객체 저장소에 보관해 두는 것
- 프로토콜(protocol)
- 문제 이해 및 설계 범위 확정
- 시스템 운영 지표, CPU 부하, 메모리 사용률, 디스크 사용량 같은 저수준의 운영체제 사용률 지표
- 서버가 처리하는 초당 요청 수나 웹 서버 프로세스 개수 같은 고차원적 개념에 관계된 지표일 수도 있음
- 비기능 요구사항
- 규모 확장성 : 시스템은 늘어나는 지표 수와 경보의 양에 맞게 확장될 수 있어야 함
- 낮은 응답 지연 : 대시보드와 경보를 신속하게 처리할 수 있도록, 질의에 대한 낮은 응답 지연을 보장해야 함
- 안정성 : 높은 안정성을 제공하여 중요 겨옵를 놓치지 않도록 해야 함
- 우연성 : 기술은 계속 변화하므로 ,미래의 신기술을 쉽게 통합할 수 있도록 유연하게 변경 가능한 파이프라인을 이용해 구축한 시스템이어야 함
- 개략적 설계안 제시 및 동의 구하기
- 기본적 사항
- 데이터 수집 : 여러 출처로부터 지표 데이터를 수집함
- 데이터 전송 : 지표 데이터를 지표 모니터링 시스템으로 전송함
- 데이터 저장소 : 전송되어 오는 데이터를 정리하고 저장함
- 경보 : 밀려오는 데이터를 분석하고, 이상 징후를 감지하고, 경보를 발생시킴. 이 시스템은 다양한 통신 채널로 경보를 발송할 수 있어야 함
- 시각화 : 데이터를 차트나 그래프 등으로 제공함. 엔지니어는 데이터를 시각적으로 보여주면 패턴, 추이, 문제점을 더 쉽게 파악함
- 데이터 저장소 시스템
- 범용 데이터베이스는 이론적으로는 시계열 데이터를 처리할 수 있지만 이 설계안이 감당하려는 부하 규모에 맞추려면 전문가 수준의 튜닝이 필요함
- 시계열 데이터의 지수 이동 평균 값을 지속적으로 갱신하는 질의문을 SQL로 작성
- 복잡해서 읽기 까다로울 것
- 태그/레이블에 대한 질의를 지원하려면 태그마다 인덱스를 지정해야 한다는 문제도 있음
- 범용 관계형 데이터 베이스는 많은 양의 쓰기 연산이 지속적으로 발생하는 환경에서 좋은 성능을 보이지 못함
- 시장에서 가장 인기 있는 시계열 데이터베이스 두 가지는 InfluxDB 그리고 프로메테우스
- 다량의 시계열 데이터를 저장하고 빠른 실시간 분석을 지원하는 것이 특징
- 두 제품 모두 메모리 캐시와 디스크 저장소를 함께 사용함
- 지표 데이터는 본질적으로 시계열 데이터이므로 InfluxDB 같은 시계열 데이터베이스에 저장할 수 있음을 설명하는 것
- 좋은 시계열 데이터베이스는 막대한 양의 시계열 데이터를 레이블(어떤 데이터베이스에서는 태그라고 부르기도 함) 기준으로 집계하고 분석하는 기능을 제공함
- 개략적 설계안
- 지표 출처 : 지표 데이터가 만들어지는 곳으로 애플리케이션 서버, SQL 데이터베이스, 메시지 큐 어떤 것이든 가능함
- 지표 수집기 : 지표 데이터를 수집하고 시계열 데이터에 기록하는 역할을 함
- 시계열 데이터베이스 : 지표 데이터를 시계열 데이터 형태로 보관하는 저장소. 다량의 시계열 데이터를 분석하고 요약하는 데 적합하도록 설계된 질의 인터페이스를 제공함
- 질의 서비스 : 질의 서비스는 시계열 데이터베이스에 보관된 데이터를 질의하고 가져오는 과정을 돕는 서비스
- 경보 시스템 : 경보를 받아야 하는 다양한 대상으로 경보 알림을 전송하는 역할을 하는 시스템
- 시각화 시스템 : 지표를 다양한 형태의 그래프/차트로 시각화하는 기능을 제공하는 시스템
- 기본적 사항
- 상세 설계
- 지표 수집
- 풀 모델
- 지표 수집기 서버 안에 모든 서비스 엔드포인트의 DNS/IP 정보를 담은 파일을 두면 가장 간단함. 하지만 이 방안은 서버가 수시로 추가/삭제되는 대규모 운영 환경에는 적용하기 어려움
- etcd나 아파치 주키퍼 같은 서비스 탐색 기술을 활용하면 이 문제는 해결할 수 있음
- 서비스는 자신의 가용성 관련 정보를 서비스 탐색 서비스(이하 SDS)에 기록하고, SDS는 서비스 엔드포인트 목록에 변화가 생길 때마다 지표 수집기에 통보하는 것
- SDS에는 언제 어디서 지표를 수집하면 되는지에 관한 설정 정보를 기록함
- 안전 해시 링, 해시 링 구간마다 해당 구간에 속한 서버로부터 생산되는 지표의 수집을 담당하는 수집기 서버를 지정하는 것
- 푸시 모델
- 푸시 모델은 지표 출처에 해당하는 서버, 즉 웹 서버나 데이터베이스 서버 같은 서버가 직접 지표를 수집기에 전송하는 모델
- 푸시 모델의 경우, 모니터링 대상 서버에 통상 수집 에이전트라고 부르는 소프트웨어를 설치함
- 푸시 모델을 채택한 지표 수집기가 밀려드는 지표 데이터를 제때 처리하지 못하는 일을 방지하려면, 지표 수집기 클러스터 자체도 자동 규모 확장이 가능하도록 구성하고 그 앞에 로드밸런서를 두는 것이 바람직함
- 장단점 비교
- 풀 모델을 채택한 유명한 사례로는 프로메테우스가 있음
- 푸시 모델을 채택한 유명한 사례로는 아마존 클라우드와치, 그래파이트 등이 있음
-
풀 모델 푸시 모델 손쉬운 디버깅 애플리케이션 서버에 /metrics 엔드포인트를 두도록 강제하므로 필요하다면 언제든 지표 데이터를 볼 수 있으며, 심지어 랩톱에서도 간으함. 풀 모델이 더 낫다 상태 진단 애플리케이션 서버가 풀 요청에 응답하지 않으면 바로 해당 서버에 장애가 발생한 것으로 진단할 수 있음. 풀 모델 쪽이 쉽다 지표 수집기가 지표를 받지 못하면 네트워크 장애가 원인인지 서버 장애가 원인인지 알기 어렵다 생존 기간이 짧은 프로세스 생명 주기가 짧은 일괄 작업 프로세스의 수집기가 미처 지표를 끌어가기도 전에 종료되어 버릴 수 있다. 그런 점에서는 푸시 모델이 낫다. 풀 모델도 푸시 게이트웨이를 도입하면 해당 문제점을 해결할 수 있다 방화벽 등의 복잡한 네트워크 구성 수집기 서버가 지표 데이터를 제대로 끌어가려면 모든 /metrics 엔드포인트가 접근 가능하도록 구성되어야 함. 지표 수집기가 로드밸런서 및 자동 규모 확장 클러스터 형태로 구성되었다면 어디서 오는 지표라도 수집 가능함. 포시 모델이 낫다 성능 풀 모델은 일반적으로 TCP를 사용함 푸시 모델은 보통 UDP를 사용함. 푸시 모델의 지표 전송 지연이 더 낫다는 뜻.TCP 연결을 맺는 데 드는 오버헤드가 지표 데이터를 전송하는 것에 비해 낮다는 것 데이터 신빙성 지표데이터를 가져올 애플리케이션 서버의 목록이 이미 정의된 상태이므로 해당 서버에 수집한 데이터는 믿을 수 있음 아무나 지표 수집기에 데이터를 보낼 수 있다는 문제가 있음. 지표 전송을 허용할 서버의 목록을 수집 측에 유지하거나 인증을 강제하면 문제를 해결할 수 있음
- 시계열 데이터베이스에 장애가 생기면 데이터 손실이 발생할 가능성이 있음. 큐를 두면 그런 문제를 해소할 수 있음
- 지표 수집기는 지표 데이터를 카프카와 같은 큐 시스템에 전송함. 아파치 스톰이나 플링크, 스파크 같은 소비자, 즉 스트림 처리 서비스가 해당 데이터를 받아 시계열 데이터베이스에 저장함
- 장점
- 카프카는 고도로 안정적이고 규모 확장성이 뛰어난 분산 메시지 플랫폼
- 데이터 수집 컴포넌트와 처리 컴포넌트 사이의 결합도를 낮춤
- 데이터베이스에 장애가 생겨도 데이터는 소실되지 않음. 카프카에 보관해 두면 되기 때문
- 카프카를 통한 규모 확장
- 카프카에 내장된 파티션 메커니즘을 사용하면 시스템의 규모를 다양한 방법으로 확장할 수 있음
- 대역폭 요구사항에 따라 파티션의 수를 설정함
- 지표 이름에 따라 어떤 지표를 어느 파티션에 배치할지 결정하면 소비자는 지표 이름에 따라 데이터를 집계할 수 있음
- 태그/레이블에 따라 지표 데이터를 더욱 세분화한 파티션으로 나눔
- 중요 지표가 먼저 처리될 수 있도록 지표를 분류하고 우선순위로 지정함
- 카프카에 내장된 파티션 메커니즘을 사용하면 시스템의 규모를 다양한 방법으로 확장할 수 있음
- 풀 모델
- 데이터 집계 지점
- 수집 에이전트가 집계하는 방안 : 어떤 카운터 값을 분 단위로 집계하여 지표 수집기에 보내는 정도는 가능함
- 데이터 수집 파이프라인에서 집계하는 방안 : 플링크 같은 스트림 프로세싱 엔진이 필요. 늦게 도착하는 지표 데이터의 처리가 어렵고, 원본 데이터를 보관하지 않기 때문에 정밀도나 유연성 측면에서 손해를 보게 된다는 문제가 있음
- 질의 시에 집계하는 방안 : 데이터 손실 문제는 없으나 질의를 처리하는 순간에 전체 데이터 세트를 대상으로 집계 결과를 계산해야 하므로 속도는 느릴것
- 저장소 계층
- 저장소 용량 최적화
- 데이터를 인코딩하고 압축하면 크기를 상당히 줄일 수 있음
- 다운샘플링
- 데이터의 햇아도를 낮춰 저장소 요구량을 줄이는 기법
- 낡은 데이터는 해상도를 줄여도 됨
- 7일 이내 데이터 : 샘플링을 적용하지 않음
- 30일 이내 데이터 : 1분 해상도로 낮춰 보관함
- 1년 이내 데이터 : 1시간 해상도로 낮춰 보관함
- 냉동 저장소
- 냉동 저장소는 잘 사용되지 않는 비활성 상태 데이터를 보관하는 곳
- 경보 시스템
- 경보 필터링, 병합, 중복 제거 : 가령 짧은 시간 동안 같은 인스턴스에서 발생한 경보는 다음과 같이 병합할 수 있음
- 접근 제어 : 사람의 실수로 빚어지는 장애를 막고 시스템의 보안을 유지하려면 특정한 경보 관리 작업은 반드시 특정한 개인만이 수행할 수 있도록 제한해야 함
- 재시도 : 경보 관리자는 경보 상태를 확인하고 알림이 최소 한 번은 전달됨을 보장해야 함
- 저장소 용량 최적화
- 지표 수집
- 개략적 설계안 제시 및 동의 구하기
- 데이터 모델
- 원시 데이터 vs 집계 결과 데이터
-
원시 데이터만 보관하는 방안 집계 결과 데이터만 보관하는 방안 장점 원본 데이터를 손실 없이 보관, 데이터 필터링 및 재계산 지원 데이터 용량 절감,빠른 질의 성능 단점 막대한 데이터 용량, 낮은 질의 성능 데이터 손실. 원본 데이터가 아닌 계산/유도된 데이터를 저장하는 데서 오는 결과 - 둘 다 저장할 것을 추천함
- 문제가 발생하면 디버깅에 활용할 수 있도록 원시 데이터도 보관하는 것이 좋음. 버그로 집계 데이터가 손상되면 버그 수정 후에 원시 데이터에서 집계 결과를 다시 만들 수 있음
- 원시 데이터는 양이 엄청나므로 직접 질의하는 것은 비효율적. 이 문제를 완화하려면 집계 결과 데이터를 질의하는 것이 바람직함
- 원시 데이터는 백업 데이터로 활용됨. 재계산을 하는 경우가 아니라면 일반적으로는 원시 데이터를 질의할 필요는 없음. 오래된 원시 데이터는 냉동 저장소로 옮기면 비용을 절감할 수 있음
- 집계 결과 데이터는 활성 데이터 구실을 함. 질의 성능을 높이기 위해 튜닝하는 것이 보통
-
- 원시 데이터 vs 집계 결과 데이터
- 올바른 데이터베이스 선택
- 발생하는 평균 쓰기 QPS는 10000이고 최대 QPS는 50000. 따라서 이 시스템은 쓰기 중심 시스템. 원시 데이터는 백업과 재계산 용도로만 이용되므로 이론적으로는 읽기 연산 빈도는 낮음
- 쓰기 및 시간 범위 질의에 최적화된 카산드라나 InfluxDB를 사용하는 것이 좀 더 바람직함
- ORC, 파케이, AVRO 같은 컬럼형 데이터 형식 가운데 하나를 사용하여 아마존 S3에 데이터를 저장하는 방법도 있음. 각 파일의 최대 크기를 제한하면(가령 10GB) 원시 데이터 기록 담당 스트림 프로세서는 최대 크기에 도달하면 자동으로 새 파일을 만듬
- 개략적 설계안
- 비동기 처리
- 트래픽이 갑자기 증가하여 발생하는 이벤트 수가 소비자의 처리 용량을 훨씬 넘어서는 경우 소비자는 메모리 부족 오류 등의 예기치 않은 문제를 겪게 될 수 있음. 동기식 시스템의 경우, 특정 컴포넌트의 장애는 전체 시스템 장애로 이어짐
- 카프카 같은 메시지 큐를 도입하여 생산자와 소비자의 결합을 끊는 것. 그 결과로 전체 프로세스는 비동기 방식으로 동작하게 되고, 생산자와 소비자의 규모를 독립적으로 확장해 나갈 수 있게 됨
- 스타스키마 장점
- 이해하기 쉽고 구축하기 간단
- 기존 집계 서비스를 재사용하여 스타 스키마에 더 많은 차원을 생성할 수 있음. 다른 추가 컴포넌트는 필요하지 않음
- 결과를 미리 계산해 두는 방식이므로, 필터링 기준에 따라 데이터에 빠르게 접근할 수 있음
- 이 접근법에는 많은 버킷과 레코드가 생성된다는 한계가 있음. 필터링 기준이 많으 경우에 더더욱 그렇다
- 비동기 처리
- 데이터 모델
- 상세 설계
- 스트리밍 vs 일괄처리
- 스트림 처리는 데이터를 오는 대로 처리하고 거의 실시간으로 집계된 결과를 생성하는 데 사용함. 일괄 처리는 이력 데이터를 백업하기 위해 활용함
- 일괄 및 스트리밍 처리 경로를 동시에 지원하는 시스템의 아키텍처를 람다라고 부름. 람다 아키텍처의 단점은 두 가지 처리 경로를 지원하므로 유지 관리해야 할 코드가 두 벌이라는 점
- 카파 아키텍처는 일괄 처리와 스트리밍 처리 경로를 하나로 결합하여 이 문제를 해결함. 핵심 아이디어는 단일 스트림 처리 엔진을 사용하여 실시간 데이터 처리 및 끊임없는 데이터 재처리 문제를 모두 해결하는 것
- 세 가지 유형의 시스템 비교
-
서비스(온라인 시스템) 일괄 처리 시스템(오프라인 시스템) 스트리밍 시스템(실시간에 가깝게 처리하는 시스템) 응답성 클라이언트에게 빠르게 응답 클라이언트에게 응답할 필요가 없음 클라이언트에게 응답할 필요가 없음 입력 사용자의 요청 유한한 크기를 갖는 입력, 큰 규모의 데이터 입력에 경게가 없음(무한 스트림) 출력 클라이언트에 대한 응답 구체화 뷰, 집계 결과 지표 등 구체화 뷰, 집계 결과 지표 등 성능 측정 기준 가용성, 지연 시간 처리량 처리량,지연시간 사례 온라인 쇼핑 맵리듀스 플링크
-
- 시간
- 이벤트 발생 시각을 이용하는 방안 vs 처리 시각을 이용하는 방안
-
장점 단점 이벤트 발생 시각 광고 클릭 시점을 정확히 아는 것은 클라이언트이므로 집계 결과가 보다 정확 클라이언트가 생성한 타임스탬프에 의존하는 방식이므로 클라이언트에 설정된 시각이 잘못되었거나 악성 사용자가 타임스탬프를 고의로 조직하는 문제에서 자유로울 수 없음 처리 시각 서버 타임스탬프가 클라이언트 타임스탬프보다 안정적 이벤트가 시스템에 도착한 시각이 한참 뒤인 경우에는 집계 결과가 부정확해짐
-
- 워터마크는 집계 윈도의 확장으로 봄. 이렇게 하면 집계 결과의 정확도를 높일 수 있음. 가령 15초 워터마크를 윈도우마다 붙이면 윈도 1은 이벤트 2를 집계할 수 있고 윈도 3은 이벤트 5를 집계할 수 있게 됨
- 집계 윈도
- 윈도에는 텀블링 윈도, 고정 윈도, 호핑 윈도, 슬라이딩 윈도, 세션 윈도의 네 종류가 있음
- 슬라이딩 윈도는 데이터 스트림을 미끄러져 나아가면서 같은 시간 구간 안에 있는 이벤트를 집계함
- 전달 보장
- 집계 결과는 과금 등에 활용될 수 있기 때문에 데이터의 정확성과 무결성이 아주 중요함. 시스템은 다음 질문에 답할 수 있어야 함
- 이벤트의 중복 처리를 어떻게 피할 수 있는가?
- 모든 이벤트의 처리를 어떻게 보장할 수 있는가?
- 데이터 중복 제거
- 사례
- 클라이언트 측 : 예를 들어, 한 클라이언트가 같은 이벤트를 여러 번 보내는 경우. 악의적인 의도로 전송되는 중복 이벤트를 처리하는 데는 광고 사기/위험 제어 컴포넌트가 적합함
- 서버 장애 : 집계 도중에 집계 서비스 노드에서 장애가 발생하였고 업스트림 서비스가 이벤트 메시지에 대해 응답을 받지 못하였다면, 같은 이벤트가 다시 전송되어 재차 집계될 가능성이 있음
- HDFS나 S3 같은 외부 파일 저장소에 오프셋을 기록하는 것
- 분산 트랜잭션은 여러 노드에서 작동하는 트랜잭션으로, 그 안에서 실행하는 작업 ㄱ가운데 하나라도 실패하면 모든 작업이 상태를 실행 전으로 되돌리게 됨
- 사례
- 집계 결과는 과금 등에 활용될 수 있기 때문에 데이터의 정확성과 무결성이 아주 중요함. 시스템은 다음 질문에 답할 수 있어야 함
- 결합 내성
- 집계 서비스의 결함 내성. 집계는 메모리에서 이루어지므로 집계 노드에 장애가 생기면 집계 결과도 손실됨
- 카프카 데이터를 원점부터 다시 재생하여 집계하면 시간이 오래 걸림. 그러니 업스트림 오프셋 같은 시스템 상태를 스냅숏으로 저장하고 마지막으로 저장된 상태부터 복구해 나가는 것이 바람직함
- 스냅숏을 이용하면 집계 서비스의 복구 절차가 단순해짐. 어떤 집계 서비스 노드 하나에 장애가 발생하면 해당 노드를 새 것으로 대체한 다음 마지막 스냅숏에서 데이터를 복구하면 됨
- 이벤트 발생 시각을 이용하는 방안 vs 처리 시각을 이용하는 방안
- 데이터 모니터링 및 정확성
- 지속적 모니터링
- 지연 시간
- 데이터를 처리하는 각 단계마다 지연시간이 추가될 수 있으므로, 시스템의 중요 부분마다 시각 추적이 가능하도록 해야 함
- 기록된 시각 사이의 차이를 지연 시간 지표로 변환해서 모니터링 하면 됨
- 메시지 큐 크기
- 큐의 크기가 갑자기 늘어난다면 더 많은 집계 서비스 노드를 추가해야 할 수 있음
- 카프카는 분산 커밋 로그 형태로 구현된 메시지 큐이므로, 카프카를 사용하는 경우에는 레코드 처리 지연 지표를 대신 추적하면 됨
- 집계 노드의 시스템 자원: CPU, 디스크, JVM 같은 것에 관계된 지표
- 지연 시간
- 지속적 모니터링
- 대략적 설계안
- 광고 클릭 데이터를 하이브에 저장한 다음 빠른 질의는 일래스틱서치 계층을 얹어서 처리하는 것.
- 집계는 클릭하우스나 드루이드 같은 OLAP 데이터베이스를 통해 처리할 수 있음 것
- 스트리밍 vs 일괄처리
- 개략적 설계안 제시 및 동의 구하기
- 데이터 모델
- 관계형 데이터베이스는 읽기 빈도가 쓰기 연산에 비해 높은 작업 흐름을 잘 지원함. NoSQL 데이터베이스는 대체로 쓰기 연산에 최적화되어 있음
- 관계형 데이터베이스는 ACID 속성(원자성, 일관성, 격리성, 영속성)을 보장함. 이 속성이 만족되지 않으면 잔액이 마이너스가 되는 문제, 이중 청구 문제, 이중 예약 문제 등을 방지하기 어려움
- 관계형 데이터베이스를 사용하면 데이터를 쉽게 모델링할 수 있음
- 데이터 모델
- 상세 설계
- 비관적 락
- 비관적 동시성 제어 방안이라고도 불리며, 사용자가 레코드를 갱신하려고 하는 순간 즉시 락을 걸어 동시 업데이트를 방지하는 기술. 해당 레코드를 갱신하려는 다른 사용자는 먼저 락을 건 사용자가 변경을 마치고 락을 해제할 때까지 기다려야 함
- MySQL의 경우 SELECT FOR UPDATE문을 실행하면 SELECT가 반환한 레코드에 락이 걸림
- 장점
- 애플리케이션이 변경 중이거나 변경이 끝난 데이터를 갱신하는 일을 막을 수 있음
- 구현이 쉽고 모든 갱신 연산을 직렬화하여 충돌을 막음. 비관적 락은 데이터에 대한 경합이 심할 때 유용함
- 단점
- 여러 레코드에 락을 걸면 교착 상태가 발생할 수 있음. 교착 상태가 생기지 않는 애플리케이션 코드 작성은 까다로울 수 있음
- 확장성이 낮음. 트랜잭션이 너무 오랫동안 락을 해제하지 않고 있으면 다른 트랜잭션은 락이 걸린 자원에 접근할 수 없음. 이는 특히 트랜잭션의 수명이 길거나 많은 엔티티에 관련된 경우, 데이터베이스 성능에 심각한 영향을 끼침
- 예약 시스템에 비관적 락 메커니즘을 사용하는 것은 권장하지 않음
- 낙관적 락
- 낙관적 동시성 제어라고도 불리는 방안으로 여러 사용자가 동시에 같은 자원을 갱신하려 시도하는 것을 허용함
- 낙관적 락은 일반적으로 버전 번호와 타임스탬프의 두 가지 방법으로 구현함. 서버 시계는 시간이 지남에 따라 부정확해질 수 있으므로 일반적으로는 버전 번호를 더 나은 선택지로 봄
- 낙관적 락은 일반적으로 비관적 락보다 빠름. 데이터베이스에 락을 걸지 않기 때문. 하지만 동시성 수준이 아주 높으면 성능이 급격하게 나빠짐
- 최종 결과는 정확하겠지만, 반복되는 재시도 때문에 사용자는 아주 불쾌한 경험을 하게 될 것
- 장점
- 애플리케이션이 유효하지 않은 데이터를 편집하는 일을 막음
- 데이터베이스 자원에 락을 걸 필요가 없음. 사실 데이터베이스 관점에서 보면 락은 없음. 버전 번호를 통해 일관성을 유지할 책임은 애플리케이션에 있음
- 낙관적 락은 데이터에 대한 경쟁이 치열하지 않은 상황에 적합함. 그런 상황에서는 락을 관리하는 비용 없이 트랜잭션을 실행할 수 있음
- 단점
- 데이터에 대한 경쟁이 치열한 상황에서는 성능이 좋지 못함
- 낙관적락은 호텔 예약 시스템에 적합한 선택지임. 예약 QPS가 일반적으로는 높지 않기 때문
- 데이터베이스 제약 조건
- 사용자가 객실을 예약하려 하면 total_reserved의 값이 101이 되므로 total_inventory - total_reserved >=0 의 제약 조건을 위반하게 됨(100-101 < 0) . 따라서 트랜잭션은 중단되고 데이터는 트랜잭션 실행 전 상태로 돌아감(rollback)
- 장점
- 구현이 쉬움
- 데이터에 대한 경쟁이 심하지 않을 때 잘 동작함
- 단점
- 낙관적 락과 마찬가지로 데이터에 대한 경쟁이 심하면 실패하는 연산 수가 엄청나게 늘어날 수 있음. 사용자는 객실이 있다고 보고 예약을 시도하겠지만 정작 예약하려고 하면 객실이 없습니다.라는 응답을 보게 될 것이다. 사용자 입장에서는 괴로운 경험
- 데이터베이스 제약 조건은 애플리케이션 코드와 달라서 버전을 통제하기 어려움
- 제약 조건을 허용하지 않은 데이터베이스도 있으므로, 데이터베이스를 다른 제품으로 교체하려고 하면 문제가 생길 수도 있음
- 이 접근법은 구현이 쉽고 호텔 예약의 경우에는 데이터에 대한 경쟁이 심하지 않으므로(낮은 QPS), 좋은 선택지라고도 할 수 있을 것임.
- 시스템 규모 확장
- 데이터베이스 샤딩
- 데이터베이스의 규모를 늘리는 한 가지 방법은 샤딩을 적용하는 것. 데이터베이스를 여러 대 두고 각각에 데이터의 일부만 보관하도록 하는 것이 기본적인 아이디어
- 데이터베이스 부하를 16개 샤드로 분산하는 사례. QPS가 30,000이면 샤딩 후에 각 샤드는 30000/16 = 1875 QPS를 처리하게 되는데, 한 대 MySQL 서버로 감당할 수 있는 부하
- 캐시
- 호텔 잔여 객실 데이터에는 재미있는 특성이 있음. 오직 현재 그리고 미래의 데이터만 중요하다는 것
- 데이터를 보관할 때 낡은 데이터는 자동적으로 소멸되도록 TTL을 설정할 수 있다면 바람직함. 이력 데이터느 다른 데이터베이스를 통해 질의하도록 하면 됨
- 레디스는 이런 상황에 적합한데 TTL과 LRU 캐시 교체 정책을 사용하여 메모리를 최적으로 활용할 수 있기 때문
- 데이터베이스 샤딩
- 비관적 락
- 개략적 설계안 제시 및 동의 구하기
- 이메일 프로토콜
- SMTP : 이메일을 한 서버에서 다른 서버로 보내는 표준 프로토콜
- POP : 이메일 클라이언트가 원격 메일 서버에서 이메일을 수신하고 다운로드하기 위해 사용되는 표준 프로토콜
- IMAP : 이메일 클라이언트가 원격 메일 서버에서 이메일을 수신하는 데 사용되는 또 다른 표준 프로토콜
- HTTPS : 웹 기반 이메일 시스템의 메일함 접속에 이용될 수 있음
- 도메인 이름 서비스(DNS)
- DNS 서버는 수신자 도메인의 메일 교환기 레코드(MX) 검색에 이용됨
- 이메일 프로토콜
- 상세 설계
- 올바른 데이터베이스의 선정
- 지메일이나 아웃룩 정도의 규모가 되면 보통 초당 입/출력 연산 빈도(IOPS)를 낮추기 위해 맞춤 제작한 데이터베이스를 사용하는데 시스템에 큰 부담이 되기 때문. 올바른 데이터베이스 선택은 쉽지 않음. 가능한 모든 선택지를 미리 살펴보면 도움이 됨
- 관계형 데이터베이스
- 관계형 데이터베이스를 고르는 주된 동기는 이메일을 효율적으로 검색할 수 있기 때문. 이메일 헤더와 본문에 대한 인덱스를 만들어 두면 간단한 검색 질의는 빠르게 처리할 수 있음. 하지만 관계형 데이터베이스는 데이터 크기가 작을 때 적합함
- MySQL이나 PostgreSQL 같은 관계형 데이터베이스는 바람직하지 않음
- 분산 객체 저장소
- S3 같은 객체 저장소. 객체 저장소는 백업 데이터를 보관하기에는 좋지만 이메일의 읽음 표시, 키워드 검색, 이메일 타래 등의 기능을 구현하기에는 그다지 좋지 않음
- 대형 이메일 서비스 업체는 대체로 독자적인 데이터베이스 시스템을 만들어 사용함
- 어떤 단일 칼럼의 크기는 한 자릿수 MB 정도일 수 있음
- 강력한 데이터 일관성이 보장되어야 함
- 디스크 I/O 최소화되도록 설계되어야 함
- 가용성이 아주 높아야 하고 일부 장애를 감내할 수 있어야 함
- 증분 백업이 쉬워야 함
- 데이터 모델
- 데이터를 저장하는 한 가지 방법은 user_id를 파티션 키로 사용하여 특정한 사용자의 데이터는 항상 같은 샤드에 보관하는 것
- 파티션 키 : 데이터를 여러 노드에 분산하는 구실을 함. 일반적으로 통용 되는 규칙은 데이터가 모든 노드에 균등하게 분산되도록 하는 파티션 키를 골라야 한다는 것
- 클러스터 키 : 같은 파티션에 속한 데이터를 정렬하는 구실을 함
- 검색
- 검색 기능을 제공하려면 이메일이 전송, 수신, 삭제될 때마다 색인 작업을 수행해야 함
- 이메일 시스템의 검색 기능에서는 쓰기 연산이 읽기 연산보다 훨씬 많이 발생함
- 올바른 데이터베이스의 선정
- 마무리
- 추가로 논의해 볼 만한 주제
- 결함 내성
- 시스템의 만흔 부분에 장애가 발생할 수 있음. 노드 장애, 네트워크 문제, 이벤트 전달 지연 등의 문제에 어떻게 대처할지 살펴보면 좋을 것
- 규정 준수
- 이메일 서비스는 전 세계 다양한 시스템과 연동해야 하고 각 나라에는 준수해야 할 법규가 있음. 예를 들어 유럽에서는 GDPR 기준에 따라 개인 식별 정보를 처리하고 저장해야 함. 합법적 감청은 이 분야의 또 다른 대표적 특징
- 보안
- 이메일 보안은 중요함. 이메일에는 민감한 정보가 포함되기 때문. 지메일은 파싱이나 멀웨어 공격을 방지하는 파싱 방지, 안전하지 않은 사이트를 경고하는 안전 브라우징, 보안 결함이 있는 첨부 파일에 대한 사전 경고, 의심스로운 로그인 시도를 차단하는 계정 안전, 송신자가 메시지에 대한 보안 정책을 설정할 수 있도록 하는 기밀 모드, 타인이 이메일 내용을 엿보지 못하도록 하는 이메일 암호화 등의 보안 관련 기능을 제공함
- 최적화
- 때로는 같은 이메일이 여러 수신자에게 전송되기 때문에 똑같은 첨부 파일이 그룹 이메일 객체 저장소(S3)에 여러 번 저장되는 경우가 있음. 저장하기 전에 저장소에 이미 동일한 첨부 파일이 있는지 확인하면 저장 연산 실행 비용을 최적화할 수 있음
- 결함 내성
- 추가로 논의해 볼 만한 주제
- S3는 AWS가 제공하는 서비스로 RESTful API 기반 인터페이스로 이용 가능한 객체 저장소
- 저장소 시스템 101
- 블록 저장소
- HDD나 SSD처럼 서버에 물리적으로 연결되는 형태의 드라이브는 블록 저장소의 가장 흔한 형태
- 블록 저장소는 원시 블록을 서버에 볼륨 형태로 제공함. 가장 유연하고 융통성이 높은 저장소
- 블록 저장소는 서버에 물리적으로 직접 연결되는 저장소에 국한되지 않음
- 파일 저장소
- 파일 저장소는 블록 저장소 위에 구현됨
- 파일 저장소는 가장 널리 사용되는 범용 저장소 솔루션
- SMB/CIFS이나 NFS와 같은 파일 수준 네트워크 프로토콜을 사용하면 하나의 저장소를 여러 서버에 동시에 붙일 수도 있음
- 파일 저장소를 사용하는 서버는 블록을 직접 제어하고, 볼륨을 포맷하는 등의 까다로운 작업을 신결 쓸 필요가 없음
- 파일 저장소는 단순하기 때문에 폴더나 파일을 같은 조직 구성원에 공유하는 솔루션으로 사용하기 좋음
- 객체 저장소
- 데이터 영속성을 높이고 대규모 애플리케이션을 지원하며 비용을 낮추기 위해 의도적으로 성능을 희생함
- 실시간으로 갱신할 필요가 없는 상대적으로 차가운 데이터 보관에 초점을 맞추며 데이터 아카이브나 백업에 주로 쓰임
- 모든 데이터를 수평적 구조 내에 객체로 보관함
- 데이터 접근은 보통 RESTful API를 통함. 다른 유형의 저장소에 비해 상대적으로 느림
- 저장소 유형별 특성
-
블록 저장소 파일 저장소 객체 저장소 저장된 내용의 변경 가능성 Y Y N(직접 변경은 불가능 하지만 객체 버전을 통해 새로운 버전의 객체를 추가하는 것은 가능) 비용 고 중~고 저 성능 중~고 혹은 최상 중~고 저~중 데이터 일관성 강력 강력 강력 데이터 접근 SAS/iSCI/FC 표준 파일 접근,CIFS/SMB,NFS RESTful API 규모 확장성 중 고 최상 적합한 응용 가상 머신, 데이터 베이스 같은 높은 성능이 필요한 애플리케이션 범용적 파일 시스템 접근 이진 데이터, 구조화되지 않은 데이터
-
- 용어 정리
- 버킷
- 객체를 보관하는 논리적 컨테이너
- 버킷 이름은 전역적으로 유일해야 함
- 데이터를 S3에 업로드하려면 우선 버킷부터 만들어야 함
- 객체
- 객체는 버킷에 저장하는 개별 데이터를 말함
- 객체는 데이터(페이로드라고도 한다)와 메타데이터를 갖음
- 객체 데이터로드는 어떤 것도 가능함
- 메타데이터는 객체를 기술하는 이름-값 쌍의 집합
- 버전
- 한 객체의 여러 버전을 같은 버킷 안에 둘 수 있도록 하는 기능
- 버킷마다 별도 설정이 가능함. 실수로 지웠거나 덮어 쓴 객체를 복구할 수 있도록 함
- URI
- 객체 저장소는 버킷과 객체에 접근할 수 있도록 하는 RESTful API를 제공함
- 각 객체는 해당 API URI를 통해 고유하게 식별할 수 있음
- SLA
- 서비스 수준 협약은 서비스 제공자와 클라이언트 사이에 맺어지는 계약
- 아마존 S3 저장소 클래스의 SLA
- 여러 가용성 구역에 걸쳐 99.999999999%의 객체 내구성을 제공하도록 설계
- 하나의 가용성 구역 전체가 소실되어도 데이터 복원 가능
- 연간 99.9%의 가용성 제공
- 버킷
- 블록 저장소
- 1단계: 문제 이해 및 설계 범위 확정
- 객체 저장소는 디스크 용량이나 초당 디스크 IO(IOPS)가 병목이 될 가능성이 높음
- 2단계: 개략적 설계안 제시 및 동의 구하기
- 객체 불변성
- 객체 저장소와 다른 두 가지 유형의 저장소 시스템의 가장 큰 차이는 객체 저장소에 보관되는 객체들은 변경이 불가능하다는 것
- 삭제한 다음 새 버전 객체로 완전히 대체할 수는 있어도 그 값을 점진적으로 변경할 수는 없음
- 키-값 저장소
- 객체 저장소를 사용하는 경우 해당 객체의 URI를 사용하여 데이터를 가져올 수 있음
- 이때 URI는 키이고 데이터는 값에 해당하므로 키-값 저장소라고 볼 수 있음
- 저장은 1회, 읽기는 여러 번
- 데이터 접근 패턴 측면에서 보면 쓰기는 1회, 읽기는 여러 번 발생함. 링크드인 사에서 조사한 결과에 따르면 객체 저장소에 대한 요청 가운데 95% 가량이 읽기 요청
- 소형 및 대형 객체 동시 지원
- 다양한 크기의 객체를 문제 없이 저장할 수 있음
- 개략적 설계안
- 시스템의 주요 컴포넌트
- 로드밸런서 : RESTful API에 대한 요청을 API 서버들에 분산하는 역할을 담당함
- API 서비스 : IAM 서비스, 메타데이터 서비스, 저장소 서비스에 대한 호출을 조율하는 역할을 담당함. 무상태 서비스이므로 수평적인 규모 확장이 가능함
- IAM 서비스 : 인증, 권한 부여, 접근 제어 등을 중앙에서 맡아 처리함. 인증은 호출 주체가 누구인지 확인하는 작업이고, 권한 부여는 인증된 사용자가 어떤 작업을 수행할 수 있는지 검증하는 과정
- 데이터 저장소 : 실제 데이터를 보관하고 필요할 때마다 읽어가는 장소. 모든 데이터 관련 연산은 객체 ID(UUID)를 통함
- 메타데이터 저장소 : 객체 메타데이터를 보관하는 장소
- 시스템의 주요 컴포넌트
- 객체 불변성
- 3단계 상세 설계
- 정확성 검증
- 메모리 데이터가 훼손되는 문제는 프로세스 경계에 데이터 검증을 위한 체크섬을 두어 해결할 수 있음. 체크섬은 데이터 에러를 발견하는 데 사용되는 작은 크기의 데이터 블록
- 원본 데이터의 체크섬을 알면 전송 받은 데이터의 정확성은 해당 데이텅의 체크섬을 다시 계산한 후 다음과 같은 절차로 확인 가능함
- 새로 계산한 체크섬이 원본 체크섬과 다르면 데이터가 망가진 것
- 같은 경우에는 아주 높은 확률로 데이터는 온전하다고 볼 수 있음.
- 체크섬 알고리즘은 MD5, SHA1, HMAC 등 다양함. 좋은 체크섬 알고리즘은 입력이 조금이라도 달라지면 크게 달리진 체크섬을 내놓음
- 객체 버전
- 객체 버전은 버킷 안에 한 객체의 여러 버전을 둘 수 있도록 하는 기능. 이 기능이 있으면 실수로 지우거나 덮어 쓴 객체를 쉽게 복구할 수 있음
- 큰 파일의 업로드 성능 최적화
- 큰 객체를 작게 쪼갠 다음 독립적으로 업로드하는 것. 모든 조각이 업로드되고 나면 객체 저장소는 그 조각을 모아서 원본 객체를 복원함. 이 과정을 멀티파트 업로드라고 부름
- 쓰레기 수집
- 더 이상 사용되지 않는 데이터에 할당된 저장 공간을 자동으로 회수하는 절차
- 객체의 지연된 삭제 : 삭제했다고 표시는 하지만 실제로 지우지는 않음
- 갈 곳 없는 데이터 : 반ㅈ쯤 업로드된 데이터, 또는 취소된 멀티파트 업로드 데이터
- 훼손된 데이터 : 체크섬 검사에 실패한 데이터
- 더 이상 사용되지 않는 데이터에 할당된 저장 공간을 자동으로 회수하는 절차
- 정확성 검증
- 마무리
- 객체 저장소를 설계하는 것이므로, 객체 업로드, 다운로드, 버킷 내 객체 목록 표시, 객체 버전 등의 기능이 보통 어떻게 구현되는지도 살펴봤음
- 개략적 설계안 제시 및 동의 구하기
- 데이터 모델
- 관계형 데이터베이스
- 규모 확장성이 그다지 중요하지 않고 사용자수가 많지 않다면 관계형 데이터베이스 시스템을 이용할 가능성이 높음
- SQL 데이터베이스는 지속적으로 변화하는 대량의 정보를 신속하게 처리하지 못함. 수백만 개 레코드에 순위를 매기려면 대략 수십 초 정도가 걸리므로, 실시간성을 요구하는 애플리케이션에는 적합하지 않음
- 데이터가 지속적으로 변경되기 때문에 캐시 도입도 불가능함
- 관계형 데이터베이스는 본 시스템에 요구되는 다량의 읽기 부하를 처리하기 어려움
- 할 수 있는 한 가지 최적화는 색인을 추가하고 LIMIT 절을 사용하여 스캔할 페이지 수를 제한하는 것
- 레디스
- 수백만 명의 사용자에 대해서도 예측 가능한 성능을 제공하고 복잡한 DB 쿼리 없이도 일반적인 순위표 작업을 쉽게 수행할 방법은 레디스를 사용하는 것
- 레디스는 메모리 기반 키-값 저장소 시스템. 메모리에서 동작하므로 빠른 읽기 및 쓰기가 가능함. 아울러 순위표 시스템 설계 문제를 해결하는 데 이상적인 정렬 집합이라는 자료형을 제공함
- 해시테이블은 사용자의 점수를 저장하기 위해서, 스킵 리스트는 특정 점수를 딴 사용자들의 목록을 저장하기 위해 쓰임
- 저장소 요구사항
- 레디스는 데이터를 디스크에 영속적으로 보관하는 옵션 지원
- 디스크에서 데이터를 읽어 대규모 레디스 인스턴스를 재시작하려면 시간이 많이 걸림. 그래서 보통은 레디스에 읽기 사본을 두는 식으로 구성함
- 주 서버에 장애가 생기면 읽기 사본을 승격시켜 주 서버로 만들고, 새로운 읽기 사본을 만들어 연결하는 것
- 관계형 데이터베이스
- 데이터 모델
- 상세 설계
- 클라우드 서비스 사용 여부
- API 게이트웨이를 사용하면 RESTful API의 HTTP 엔드포인트를 정의하고 아무 백엔드 서비스에나 연결할 수 있음
- 람다는 서버리스 접근 방식이라 인프라 규모가 필요에 맞게 자동으로 확장되므로 좋음. 규모 확장, 환경 설정, 유지 보수 등의 문제를 직접 관리할 필요가 없음
- 레디스 규모 확장
- 데이터 샤딩 방안
- 고정 파티션
- 고정 파티션은 순위표에 등장하는 점수의 범위에 따라 파티션을 나누는 방안
- 해시 파티션
- 고정 파티션
- 데이터 샤딩 방안
- NosQL
- 다음과 같은 데이터베이스에 이상적
- 쓰기 연산에 최적화
- 같은 파티션 내의 항목을 점수에 따라 효율적으로 정렬 가능함
- 기본 키 이외의 속성을 활용하여 데이터를 효과적으로 질의할 수 있도록, 전역 보조 색인을 제공함. 전역 보조 색인은 부모 테이블의 속성들로 구성되지만 기본 키는 부모 테이블과는 다름
- 데이터를 n개 파티션으로 분할하고 파티션 번호를 파티션 키에 추가하는 것. 쓰기 샤딩이라고 부르는 패턴
- 파티션이 많으면 각 파티션의 부하는 줄지만 최종 순위표를 만들기 위해 읽어야 하는 파티션은 더 많으므로 복잡성은 증가함. 벤치마킹을 통해 장단점을 보다 명확하게 파악할 수 있음
- 다음과 같은 데이터베이스에 이상적
- 클라우드 서비스 사용 여부
- 상세 설계
- 내부 서비스 간 커뮤니케이션
- 동기식 통신
- 동기식 통신에서 한 요청에 응답을 만드는 처리 주기는 관련된 서비스가 많을수록 길어짐
- 단점
- 성능 저하 : 요청 처리에 관계된 서비스 가운데 하나에 발생한 성능 문제가 전체 시스템의 성능에 영향을 끼침
- 장애 격리 곤란 : PSP 등의 서비스 장애가 발생하면 클라이언트는 더 이상 응답을 받지 못함
- 높은 결합도 : 요청 발신자는 수신자를 알아야만 함
- 낮은 확장성 : 큐를 버퍼로 사용하지 않고서는 갑작스러운 트래픽 증가에 대응할 수 있도록 시스템을 확장하기 어려움
- 비동기 통신
- 단일 수신자
- 각 요청(메시지)는 하나의 수신자 또는 서비스가 처리함
- 일반적으로 공유 메시지 큐를 사용해 구현함
- 다중 수신자
- 각 요청(메시지)은 여러 수신자 또는 서버가 처리함
- 일반적으로 보자면 동기식 통신은 설계하기는 쉽지만 서비스의 자율성을 높이기에는 적합하지 않음. 의존성 그래프가 커지면 전반적으로 성능은 낮아짐
- 비동기 통신은 설계의 단순성과 데이터 일관성을 시스템 확장성 및 장애 감내 능력과 맞바꾼 결과. 비즈니스 로직이 복잡하고 타사 서비스 의존성이 높은 대규모 결제 시스템에는 비동기 통신이 더 나은 선택
- 단일 수신자
- 결제 실패 처리
- 재시도 큐 및 실패 메시지 큐
- 실패를 우아하게 처리하기 위해서는 재시도 큐와 실패 메시지 큐를 두는것이 바람직함
- 재시도 큐 : 일시적 오류 같은 재시도 가능 오류는 재시도 큐에 보냄
- 실패 메시지 큐 : 반복적으로 처리에 실패한 메시지는 결국에는 실패 메시지 큐로 보냄. 이 큐는 문제가 있는 메시지를 디버깅하고 격리하여 성공적으로 처리되지 않은 이유를 파악하기 위한 검사에 유용함
- 실패를 우아하게 처리하기 위해서는 재시도 큐와 실패 메시지 큐를 두는것이 바람직함
- 정확히 한 번 전달
- 최소 한 번은 실행됨
- 최대 한 번 실행됨
- 재시도를 통해 최소 한 번 실행을 보증하는 방법과, 멱등성 검사를 통해 최대 한 번 실행을 보증하는 방법
- 재시도
- 즉시 재시도 : 클라이언트는 즉시 요청을 다시 보냄
- 고정 간격 : 재시도 전에 일정 시간 기다리는 방안
- 증분 간격 : 재시도 전에 기다리는 시간을 특정한 양 만큼 점진적으로 늘려 나가는 방안
- 지수적 백오프 : 재시도 전에 기다리는 시간을 직전 재시도 대비 두 배씩 늘려 나가는 방안
- 취소 : 요청을 철회하는 방안. 실패가 영구적이거나 재시도를 하더라도 성공 가능성이 낮은 경우에 흔히 사용되는 방안
- 일반적으로 적용 가능한 지침은, 네트워크 문제가 단시간 내에 해결될 것 같지 않다면 지수적 백오프를 사용하라는 것. 지나치게 공격적인 재시도 전략은 컴퓨팅 자원을 낭비하고 서비스 과부하를 유발함
- 최대 한 번 실행 - 멱등성
- 멱등성
- 최대 한 번 실행을 보장하기 위한 핵심 개념
- 연산을 여러 번 실행하여도 최초 실행 결과가 그대로 보존되는 특성을 일컫음
- 멱등성
- 일관성
- 분산 환경에서는 서비스 간 통신 실패로 데이터 불일치가 발생할 수 있음
- 내부 서비스 간에 데이터 일관성을 유지하려면 요청이 정확히 한 번 처리되도록 보장하는 것이 아주 중요함
- 내부 서비스와 외부 서비스(PSP) 간의 데이터 일관성 유지를 위해서는 일반적으로 멱등성 조정 프로세스를 활용함
- 데이터를 다중화하는 경우에는 복제 지연으로 인해 기본 데이터베이스와 사본 데이터가 불일치하는 일이 생길 수 있음
- 해결 방법
- 주 데이터베이스에서만 읽기와 쓰기 연산을 처리함. 이 접근법은 설정하기는 쉽지만 규모 확장성이 떨어진다는 단점. 사본은 데이터 안정성 보장에만 활용되고 트래픽은 처리하지 않음. 자원이 낭비됨
- 모든 사본이 항상 동기화되도록 함. 팩서스, 래프트 같은 합의 알고리즘을 사용하거나 YugabyteDB, CockroachDB 같은 합의 기반 분산 데이터베이스를 사용함
- 재시도 큐 및 실패 메시지 큐
- 동기식 통신
- 내부 서비스 간 커뮤니케이션
- 개략적 설계안 제시 및 동의 구하기
- 분산 트랜잭션 : 사가
- 선형적 명령 수행
- 사가는 유명한 분산 트랜잭션 솔루션 가운데 하나로 마이크로서비스 아키텍처에서는 사실상 표준
- 모든 연산은 순서대로 정렬됨. 각 연산은 자기 데이터베이스 독립 트랜잭션으로 실행됨
- 연산은 첫 번째부터 마지막 순서대로 실행됨. 한 연산이 완료되면 다음 연산이 개시됨
- 연산이 실패하면 전체 프로세스는 실패한 연산부터 맨 처음 연산까지 역순으로 보상 트랜잭션을 통해 롤백됨. 따라서 n개의 연산을 실행하는 분산 트랜잭션은, 보상 트랜잭션을 위한 n개 연산까지 총 2n개의 연산을 준비해야 함
- 연산 실행 순서 조율
- 분산 조율 : 마이크로서비스 아키텍처에서 사가 분산 트랜잭션에 관련된 모든 서비스가 다른 서비스의 이벤트를 구독하여 작업을 수행하는 방식. 완전히 탈 중앙화된 조율 방식
- 중앙 집중형 조율 : 하나의 조정자가 모든 서비스가 올바른 순서로 작업을 실행하도록 조율함
- 사가는 유명한 분산 트랜잭션 솔루션 가운데 하나로 마이크로서비스 아키텍처에서는 사실상 표준
- 선형적 명령 수행
- 이벤트 소싱
- 정의
- 명령
- 외부에서 전달되, 의도가 명확한 요청
- 이벤트
- 작업 이행 전에는 반드시 명령의 유효성을 검사해야 함. 그리고 검사를 통과환 명령은 반드시 이행되어야 함.
- 명령 이행 결과를 이벤트라 부름
- 상태
- 상태는 이벤트가 적용 될 때 변경되는 내용
- 상태 기계
- 이벤트 소싱 프로세스르 구동함
- 명령의 유효성을 검사하고 이벤트를 생성함
- 이벤트를 적용하여 상태를 갱신함
- 이벤트 소싱 프로세스르 구동함
- 명령
- 정의
- 분산 트랜잭션 : 사가
- 상세 설계
- 스냅숏
- 주기적으로 상태 기계를 멈추고 현재 상태를 파일에 저장한다면 시간을 절약할 수 있을 것. 스냅숏이라 부름
- 스냅숏은 과거 특정 시점의 상태로, 변경이 불가능함. 스냅숏을 저장하고나면 상태 기계는 더 이상 최초 이벤트에서 시작할 필요가 없음. 스냅숏을 읽고, 어느 시점에 만들어졌는지 확인한 다음, 그 시점부터 이벤트 처리를 시작하면 됨
- 스냅숏
- 마무리
- 여러 노드에 걸친 분산 트랜잭션을 지원하기 위한 2PC. TC/C, 사가와 같은 다양한 트랜잭션 프로토콜을 살펴봤음. 트랜잭션 기반 솔루션의 가장 큰 문제는 데이터 감사가 어렵다는 것
- 이벤트 소싱 방안. 외부 데이터베이스와 큐를 사용하는 것이었는데, 성능이 좋지 않다는 문제. 명령, 이벤트, 상태 데이터를 로컬 파일 시스템에 저장하도록 하여 성능을 개선하는 방안을 제시하였음
- 데이터를 한곳에 두면 SPOF가 되는 문제가 있으므로, 시스템 안정성을 높이기 위해 래프트 합의 알고리즘을 사용하여 이벤트 목록을 여러 노드에 복제하는 방안을 도입하였음
- 이벤트 소싱에 CQRS개념을 도입
- 상세 설계
- 멀티캐스트
- 유니캐스트 : 하나의 출처에서 하나의 목적지로만 보내는 전송 프로토콜
- 브로드캐스트 : 하나의 출처에서 전체 하위 네트워크로 보내는 방식
- 멀티캐스트 : 하나의 출처에서 다양한 하위 네트워크상의 호스트들로 보내는 방식
- 거래소 설계에 보편적으로 이용되는 것은 멀티캐스트. 같은 멀티캐스트 그룹에 속한 수신자는 이론적으로는 동시에 데이터를 수신함
- 멀티캐스트