[Book - 가상 면접 사례로 배우는 대규모 시스템 설계 기초 2] 8. 분산 이메일 서비스
1단계: 문제 이해 및 설계 범위 확정
45분 안에 설계할 방법이 없기 때문에 설계를 시작하기 전에 질문을 던져 범위를 좁혀야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
얼마나 많은 사람들이 사용하는 제품?
>> 10억 명
다음 기능이 중요할 듯
- 인증
- 이메일 발송/수신
- 모든 이메일 가져오기
- 읽음 여부에 따른 이메일 필터링
- 제목, 발신인, 메일 내용에 따른 검색 기능
- 스팸 및 바이러스 방지 기능
>> good
>> 인증은 skip
사용자는 메일 서버에 어떻게 연결?
>> 전통적으로는 SMTP, POP, IMAP 등의 프로토콜과 서비스 제공자 전용 프로토콜을 사용해 접속
>> 이번에는 HTTP를 사용한다고 가정
첨부 파일도 지원?
>> yse
비기능 요구사항
- 안정성
- 이메일 데이터는 소실되면 안됨
- 가용성
- 이메일과 사용자 데이터를 여러 노드에 자동으로 복제하여 가용성 보장
- 부분적으로 장애가 발생해도 시스템은 계속 동작
- 확장성
- 사용자 수가 늘어나도 감당 가능
- 사용자나 이메일이 많아져도 시스템 성능은 저하X
- 유연성과 확장성
- 새 컴포넌트를 더하여 쉽게 기능을 추가하고 성능을 개선 할 수 있는 유연하고 확장성 높은 시스템
- POP나 IMAP 같은 기존 이메일 프로토콜은 기능이 매우 제한적이므로, 유연성과 확장성을 갖추려면 맞춤형 프로토콜이 필요
개략적인 규모 추정
- 10억 명의 사용자
- 한 사람이 하루에 보내는 평균 이메일 수는 10건 가정
- 이메일 전송 QPS = 10^9 X 10 / 10^5 = 100,000
- 한 사람이 하루에 수신하는 이메일 수는 평균 40건 가정
- 이메일 하나의 메타데이터는 평균 50KB로 가정
- 메타데이터는 주어진 이메일에 대한 모든 정보이며, 첨부 파일은 포함X
- 메타데이터는 DB에 저장 가정
- 1년간 메타데이터를 유지하기 위한 스토리지 요구사항은 10억 명 사용자 X 하루 40건의 이메일 X 365일 X 50KB = 730PB
- 첨부 파일을 포함하는 이메일의 비율은 20%
- 첨부 파일의 평균 크기는 500KB
- 1년간 첨부 파일을 보관하는 데 필요한 저장 용량은 10억 명 사용자 X 하루 40개 이메일 X 365일 X 20% X 500KB = 1,460PB
많은 데이터를 처리해야 하기 때문에 분산 DB 솔루션이 필요하다.
2단계: 개략적 설계안 제시 및 동의 구하기
이메일 101
이메일을 주고받는 프로토콜은 여러 가지가 있다.
이메일 프로토콜
- SMTP
- Simple Mail Transfer Protocol
- 이메일을 한 서버에서 다른 서버로 보내는 표준 프로토콜
- POP
- 이메일 클라이언트가 원격 메일 서버에서 이메일을 수신하고 다운로드하기 위해 사용하는 표준 프로토콜
- 일단 단말로 다운로드된 이메일은 서버에서 삭제됨
- 결과적으로 한 대 단말에서만 이메일 읽기 가능
- 이메일을 확인하려면 전부 내려 받아야 하므로, 용량이 큰 첨부 파일이 붙은 이메일은 읽으려면 시간이 오래 걸림
- IMAP
- 이메일 클라이언트가 원격 메일 서버에서 이메일을 수신하는 데 사용되는 프로토콜
- POP와 달리 클릭하지 않으면 메시지는 다운로드 되지 않으며, 메일 서버에서 지워지지도 않음
- 여러 단말에서 이메일 읽기 가능
- 개인 이메일 계정에서 가장 널리 사용되는 프로토콜
- 이메일을 실제로 열기 전에는 헤더만 다운로드하기 때문에 인터넷 속도가 느려도 잘 동작
- HTTPS
- 메일 전송 프로토콜 X
- 웹 기반 이메일 시스템의 메일함 접속에 이용 가능
도메인 이름 서비스(DNS)
DNS 서버는 수신자 도메인의 메일 교환기 레코드(Mail Exchange, MX) 검색에 이용된다.
첨부 파일
이메일 첨부 파일은 이메일 메시지와 함께 전송되며 일반적으로 Base64 인코딩을 사용한다.
일반적으로 첨부 파일에는 크기 제한이 있다.
전통적 메일 서버
전통적 메일 서버 아키텍처
- 엘리스는 아웃룩 클라이언트에 로그인하여 이메일을 작성하고 ‘보내기’ 버튼 클릭
- 이메일은 아웃룩 메일 서버로 전송
- 아웃룩 클라이언트와 메일 서버 사이의 통신 프로토콜은 SMTP
- 아웃룩 메일 서버는 DNS 질의를 통해 수신자 SMTP 서버 주소 조회
- 이 경우에는 지메일의 SMTP 서버 주소
- 주소를 알고 나면 해당 메일 서버로 이메일 전송
- 메일 서버 간 통신 프로토콜도 SMTP
- 지메일 서버는 이메일을 저장하고 수신자인 밥이 읽어갈 수 있도록 함
- 밥이 지메일에 로그인하면 지메일 클라이언트는 IMAP/POP 서버를 통해 새 이메일을 가져옴
저장소
전통적 메일 서버는 이메일을 파일 시스템의 디렉터리에 저장하고, 이때 각각의 이메일은 고유한 이름을 가진 별도 파일로 보관한다.
각 사용자의 설정 데이터와 메일함은 사용자 디렉터리에 보관한다.
해당 목적으로 Maildir이라는 이름의 디렉터리가 널리 사용된다.
파일과 디렉터리를 활용하는 방안은 사용자가 많지 않을 때는 잘 동작하나 수 십억 개의 이메일을 검색하고 백업하는 목적으로 활용하기에는 곤란했다.
이메일의 양이 많아지고 파일 구조가 복잡해지면 디스크 I/O 병목이 되고 했다.
분산 메일 서버
분산 메일 서버는 현대적 사용 패턴을 지원하고 확장성과 안정성 문제를 해결한다.
이메일 API
메일 클라이언트마다, 그리고 이메일 생명주기 단계마다 달라질 수 있다.
- 모바일 단말 클라이언트를 위한 SMTP/POP/IMAP API
- 송신 측 메일 서버와 수신 측 메일 서버 간의 SMTP 통신
- 대화형 웹 기반 이메일 애플리케이션을 위한 HTTP 기반 RESTful API
분산 메일 서버 아키텍처
여러 서버 사이에 데이터를 동기화 하는 것은 어려운 작업이고, 수신자 메일 서버에서 이메일이 스팸으로 잘못 분류되지 않도록 하려면 아주 까다로운 문제들을 풀어야 한다.
- 웹메일
- 사용자는 웹브라우저를 사용해 메일을 받고 보냄
- 웹서버
- 사용자가 이용하는 요청/응답 서비스로, 로그, 가입, 사용자 프로파일 등에 대한 관리 기능을 담당
- 실시간 서버
- 새로운 이메일 내역을 클라이언트에 실시간으로 전달하는 역할을 담당
- 지속성 연결을 맺고 유지해야 하므로 stateful 서버
- 실시간 통신 지원 방안: long polling, WebSocket 등
- 메타데이터 DB
- 이메일, 제목, 본문, 발신인, 수신인 목록 등의 메타데이터를 저장하는 DB
- 첨부 파일 저장소
- 아마존 S3 같은 객체 저장소를 사용
- 카산드라 같은 컬럼 기반 NoSQL DB는 이 용도로 적당하지 않은
- 카산드라가 BLOB 자료형을 지원하고 해당 자료형이 지원하는 데이터의 최대 크기가 2GB이긴 하지만 실질적으로 1MB 이상의 파일 지원 X
- 카산드라에 첨부 파일을 저장하면 첨부 파일이 너무 많은 메모리를 잡아먹을 것이기 때문에 레코드 캐시 사용이 어려움
- 분산 캐시
- 최근에 수신된 이메일은 자주 읽을 가능성이 높으므로 클라이언트로 하여금 메모리에 캐시해 두도록 하면 메일을 표시하는 시간 감소 가능
- list 같은 다양한 기능을 제공하는 데다 규모 확장도 용이하므로 본 설계안에서는 Redis 활용
- 검색 저장소
- 분산 문서 저장소
- 고속 텍스트 검색을 지원하는 역 인덱스를 자료 구조로 사용
이메일 전송 절차
- 사용자가 웹메일 환경에서 메일을 작성한 다음 전송 버튼 클릭
- 요청은 로드밸런서로 전송
- 로드밸런서는 처리율 제한 한도를 넘지 않는 선에서 요청을 웹 서버로 전달
- 웹 서버는 다음 역할을 담당
- 기본적인 이메일 검증
- 이메일 크기 한도처럼 사전에 미리 정의된 규칙을 사용하여 수신된 이메일 검사
- 수신지 이메일 주소 도메인이 송신자 이메일 주소 도메인과 같은지 검사
- 같아면 웹 서버는 이메일 내용의 스팸 여부와 바이러스 감염 여부 검사
- 검사를 문제없이 통과한 이메일은 송신인의 ‘보낸 편지함’과 수신인의 ‘받은 편지함’에 저장
- 수신인 측 클라이언트는 RESTful API를 사용하여 이메일을 바로 가져올 수 있으며, 4단계 이후는 수행할 필요 X
- 기본적인 이메일 검증
- 메시지 큐
- 기본적인 검증을 통과한 이메일은 외부 전송 큐로 전달
- 큐에 넣기에 첨부 파일의 크기가 너무 큰 이메일의 경우, 첨부 파일은 객체 저장소에 따로 저장
- 큐에 전달하는 이메일 안에는 해당 저장 위치에 대한 참조 정보만 보관
- 기본적인 검증에 실패한 이메일은 에러 큐에 보관
- 기본적인 검증을 통과한 이메일은 외부 전송 큐로 전달
- 외부 전송 담당 SMTP 작업 프로세스는 외부 전송 큐에서 메시지를 꺼내어 이메일의 스팸 및 바이러스 감염 여부를 확인
- 검증 절차를 통과한 이메일은 저장소 계층 내의 ‘보낸 편지함’에 저장
- 외부 전송 담당 SMTP 작업 프로세스가 수신자의 메일 서버로 메일을 전송
외부 전송 큐에 보관되는 모든 메시지에는 이메일을 생성하는 데 필요한 모든 메타데이터가 포함되어 있다.
분산 QM는 비동기적 메일 처리를 가능케하는 핵심적 컴포넌트다.
웹 서버에서 외부 전송 담당 SMTP 프로세스를 분리함으로써 전송용 SMTP 프로세스의 규모를 독립적으로 조정 가능하다.
외부 전송 큐의 크기를 모니터링할 때는 각별히 주의해야 한다.
메일이 처리되지 않고 오랫동안 남아있으면 그 이유를 분산해야 한다.
아래와 같은 문제가 있을 수 있다.
- 수신자 측 메일 서버에 장애 발생
- 나중에 메일을 다시 전송
- 지수적 백오프가 좋은 전략
- 이메일을 보낼 큐의 소비자 수가 불충분
- 더 많은 소비자를 추가하여 처리 시간을 단축하는 방법을 생각
이메일 수신 절차
- 이메일이 SMTP 로드밸런서에 도착
- 로드밸런서는 트래픽을 여러 SMTP 서버로 분산
- SMTP 연결에는 이메일 수락 정책을 구성하여 적용 가능
- 예를 들어 유효하지 않은 이메일은 반송하도록 하면 불필요한 이메일 처리 회피 가능
- 이메일의 첨부 파일이 큐에 들어가기 너무 큰 경우에는 첨부 파일 저장소(S3)에 보관
- 이메일을 수신 이메일 큐에 발행
- 이 큐는 메일 처리 작업 프로세스와 SMTP 서버 간의 결합도를 낮추어 각자 독립적으로 규모 확장 가능
- 갑자기 수신되는 이메일의 양이 폭증하는 경우 버퍼 역할
- 메일 처리 작업 프로세스(worker)는 스팸 메일을 걸러내고 바이러스를 차단하는 등의 다양한 역할
- 이메일을 메일 저장소, 캐시, 객체 저장소 등에 보관
- 수신자가 온라인 상태인 경우 이메일을 실시간 서버로 전달
- 실시간 서버는 수신자 클라이언트가 새 이메일을 실시간으로 받을 수 있도록 하는 웹소켓 서버
- 오프라인 상태 사용자의 이메일은 저장소 계층에 보관
- 해당 사용자가 온라인 상태가 되면 웹메일 클라이언트는 웹 서버에 RESTFul API를 통해 연결
- 웹 서버는 새로운 이메일을 저장소 계층에서 가져와 클라이언트에 반환
3단계: 상세 설계
메타데이터 DB
이메일 메타데이터의 특성
- 이메일 헤더는 일반적으로 작고, 빈번하게 이용됨
- 이메일 본문의 크기는 작은 것부터 큰 것까지 다양하지만 사용 빈도는 낮으므로, 일반적으로 사용자는 이메일을 한 번만 읽는다.
- 이메일 가져오기, 읽은 메일로 표시, 검색 등의 이메일 관련 작업은 사용자별로 격리 수행되어야 함
- 어떤 사용자의 이메일은 해당 사용자만 읽을 수 있어야 하고, 그 이메일에 대한 작업도 그 사용자만이 수행 가능
- 데이터의 신선도는 데이터 사용 패턴에 영향
- 사용자는 보통 최근 메일만 조회
- 만들어진 지 16일 이하 데이터에 발생하는 읽기 질의 비율은 전체 질의의 82%
- 데이터의 높은 안정성이 보장되어야 함
- 데이터 손실은 용납X
올바른 DB 선정
- RDB
- 이메일을 효율적으로 검색 가능
- 이메일 헤더와 본문에 대한 인덱스를 만들어 두면 간단한 검색 질의는 빠르게 처리 가능
- 하지만 RDB는 데이터 크기가 작을 때 적합
- 분산 객체 저장소
- 이메일의 원시 데이터를 그대로 S3 같은 객체 저장소에 보관
- 백업 데이터를 보관하기에는 좋지만 이메일의 읽음 표시, 키워드 검색, 이메일 타래 등의 기능 구현 어려움
- NoSQL
- 지메일은 구글 Bigtable을 저장소로 사용
대형 이메일 서비스 업체는 대체로 독자적인 DB 시스템을 만들어 사용한다.
제한된 면접 시간에 새로운 분산 DB를 설계하고 구현할 시간은 없으니 해당 DB가 아래 조건을 충족해야 한다는 점은 설명하자.
- 어떤 단일 컬럼의 크기는 한 자릿수 MB 정도
- 강력한 데이터 일관성 보장
- 디스크 I/O가 최소화되도록 설계
- 가용성이 아주 높아야 하고 일부 장애 감내 가능
- 증분 백업
데이터 모델
데이터를 저장하는 한 가지 방법은 user_id를 파티션 키로 사용하여 특정한 사용자의 데이터는 항상 같은 샤드에 보관하는 것이다.
이 데이터 모델의 한 가지 문제는 메시지를 여러 사용자와 공유할 수 없다는 것이다.
(본 요구사항과는 관계 없으므로, 걱정X)
기본 키는 파티션 키와 클러스터 키의 두 가지 부분으로 구성된다.
- 파티션 키
- 데이터를 여러 노드에 분산하는 구실
- 일반적으로 통용되는 규칙은 데이터가 모든 노드에 균등하게 분산되도록 하는 파티션 키를 골라야 함
- 클러스터 키
- 같은 파티션에 속한 데이터를 정렬하는 구실
개략적으로 보자면 이메일 서비스의 데이터 계층은 다음과 같은 질의를 지원해야 한다.
- 주어진 사용자의 모든 폴더를 구함
- 특정 폴더 내의 모든 이메일 표시
- 메일을 새로 만들거나, 삭제하거나, 가져옴
- 이미 읽은 메일 전부, 또는 아직 읽지 않은 메일 전부를 가져옴
- 보너스 점수를 받을 수 있는 질의
- 이메일 타래를 전부 가져옴
잘의 1: 특정 사용자의 모든 폴더 질의
파티션 키는 user_id 이므로, 어떤 사용자의 모든 폴더는 같은 파티션 안에 있다.
질의 2: 특정 폴더에 속한 모든 이메일 표시
사용자가 자기 메일 폴더를 열면 이메일은 가장 최근 이메일부터 오래된 것 순서로 정렬되어 표시된다.
같은 폴더에 속한 모든 이메일이 같은 파티션에 속하도록 하려면 user_id, folder_id로 복합 파티션 키를 사용해야 한다.
또한, 이메일을 시간순으로 정렬하는 데 사용되는 클러스터 키인 email.id도 눈여겨볼 필요가 있다.
질의 3: 이메일 생성/삭제/수신
한 이메일에는 여러 첨부 파일이 있을 수 있다.
email_id와 filename 필드를 같이 사용하면 모든 첨부 파일을 질의할 수 있다.
질의 4: 읽은, 또는 읽지 않은 모든 메일
NoSQL DB는 보통 파티션 키와 클러스터 키에 대한 질의만 허용한다.
NoSQL DB 테이블을 아래 두 테이블로 비정규화하여 분할한다.
- read_emails: 읽은 상태의 모든 이메일을 보관하는 테이블
- unread_emails: 읽지 않은 모든 이메일을 보관하는 테이블
애플리케이션 코드가 좀 더 복잡해야지고 관리하기 까다로워지겠지만, 질의 성능은 대규모 서비스에 어울리는 수준으로 개선한다.
보너스: 이메일 threads 가져오기
많은 이메일 클라이언트가 지원하는 기능으로, 모든 답장을 최초 메시지에 threads로 엮어 보여주는 기능이다.
사용자는 특정한 대화에 관련된 모든 메일을 한 번에 확인할 수 있게 된다.
전통적으로 이메일 threads는 JWZ 같은 알고리즘을 통해 구현한다.
일관성 문제
높은 가용성을 달성하기 위해 다중화(replication)에 의존하는 분산 DB는 데이터 일관성과 가용성 사이에서 타협적인 결정을 내릴 수밖에 없다.
이메일 시스템의 경우에는 데이터의 정확성이 아주 중요하므로, 모든 메일함은 반드시 하나의 주 사본을 통해 서비스된다고 가정해야 한다.
따라서 장애가 발생하면 클라이언트는 다른 사본을 통해 주 사본이 복원될 때까지 동기화/갱신 작업을 완료할 수 없다.
데이터 일관성을 위해 가용성을 희생하는 것이다.
이메일 전송 가능성
메일 서버를 구성하고 이메일을 보내는 것은 쉽다.
하지만 특정 사용자의 메일함에 실제로 메일이 전달되도록 하는 것은 어려운 문제다.(예: 스팸 메일)
이메일의 전송 가능성을 높이기 위해서는 다음과 같은 요소들을 고려해야만 한다.
- 전용 IP
- 이메일을 보낼 때는 전용 IP 주소를 사용
- 대부분의 이메일 서비스 사업자는 아무 이력이 없는 새로운 IP 주소에서 온 메일을 무시
- 범주화
- 범주가 다른 이메일(마케팅 목적의 이메일)은 다른 IP 주소를 통해 송신
- 발신인 평판
- 새로운 이메일 서버의 IP 주소는 사용 빈도를 서서히 올리는 것이 좋음
- 스팸으로 분류될 가능성이 낮아짐
- 스팸 발송자의 신속한 차단
- 스팸을 뿌리는 사용자는 서버 평판을 심각하게 훼손하기 전에 시스템에서 신속히 차단
- 피드백 처리
- 이메일 인증
- 피싱에 대응하는 보편적 전략: SPF, DKIM, DMARC 등
명심해야 할 것은 이메일이 목적지에 성공적으로 도착하도록 하기가 어렵다는 사실이다.
도메인 지식이 필요한 것은 물론이고, ISP와 좋은 관계를 유지할 필요도 있다.
검색
기본적인 이메일 검색은 보통 이메일 제목이나 본문에 특정 키워드가 포함되었는지 찾는 것을 뜻한다.
고급 기능에는 ‘발신인(From)’, ‘제목(Subject)’, ‘읽지 않음’ 같이 메일 속성에 따른 필터링 기능이 포함된다.
검색 기능을 제공하려면 이메일이 전송, 수신, 삭제될 때마다 색인 작업을 수행해야 한다.
그에 반해 검색은 사용자가 ‘검색’ 버튼을 누를 때만 실행된다.
따라서 이메일 시스템의 검색 기능에서는 쓰기 연산이 읽기 연산보다 후러씬 많이 발생한다.
검색 기능을 지원하기 위해 ElasticSearch를 이용하는 방안과 데이터 저장소에 내장된 기본 검색 기능을 활용하는 방안이 있다.
방안 1: ElasticSearch
질의가 대부분 사용자의 이메일 서버에서 실행되므로 user_id를 파티션 키로 사용하여 같은 사용자의 이메일은 같은 노드에 묶어 놓는다.
사용자는 검색 버튼을 누른 다음 결과가 수신될 떄까지 기다린다.
따라서 검색 요청은 동기 방식으로 처리되어야 한다.
하지만 ‘이메일 전송’, ‘이메일 수신’, ‘이메일 삭제’ 같은 이벤트는 처리 결과를 클라이언트로 전달할 필요는 없다.
필요한 것은 색인 작업인데, 이 프로세스는 background 작업 형태로 처리될 수 있다.
본 설계안은 Kafka를 활용하여 색인 작업을 시작하는 서비스와 실제로 색인을 수행할 서비스 사이의 결합도를 낮추는 방안을 채택했다.
ElasticSearch는 검색 엔진 DB이며, 이메일 검색에 필요한 텍스트 기반 검색을 잘 지원한다.
까다로운 문제는 주 이메일 저장소와 동기화를 맞추는 부분이다.
방안 2: 맞춤형 검색 솔루션
대규모 이메일 서비스 사업자는 보통 자기 제품에 고유한 요구사항을 만족시키기 위해 검색 엔진을 자체적으로 개발해 사용한다.
자체적으로 검색 솔루션을 구현하는 경우에 마주하게 될 주요 과제인 디스크 I/O 병목 문제만 간단하게 다뤄보자.
매일 저장소에 추가되는 메타데이터와 첨부 파일의 양은 PB 수준이다.
한편, 하나의 이메일 계정에 오십 만개가 넘는 이메일이 저장되는 것도 드문 일은 아니다.
그러니 이메일 색인 서버의 주된 병목은 보통 디스크 I/O다.
색인을 구축하는 프로세스는 다량의 쓰기 연산을 발생시킬 수밖에 없으므로 LSM 트리를 사용하여 디스크에 저장되는 색인을 구조화하는 것이 바람직한 전략일 것이다.
쓰기 경로는 순차적 쓰기 연산(sequential write)만 수행하도록 최적화되어 있다.
LSM 트리는 빅테이블이나 카산드라, RocksDB 같은 DB의 핵심 자료 구조다.
새로운 이메일이 도착하면 우선 메모리 캐시로 구현되는 0번 계층에 추가된다.
메모리에 보관된 데이터의 양이 사전에 정의된 임계치를 넘으면 데이터는 다음 계층에 병합된다.
LSM을 사용하는 또 다른 이유는 자주 바뀌는 데이터를 그렇지 않은 데이터와 분리하기 위해서다.
예를 들어 이메일 데이터는 보통 바뀌지 않지만 이메일 폴더의 정보는 상이한 필터링 규칙들 때문에 자주 바뀌는 경향이 있다.
따라서 데이터를 두 개 파트로 나누고, 어떤 요청이 폴더 변경에 관한 것이면 폴더 정보만 바꾸고 이메일 데이터는 내버려 둔다.
| 비교항목 | 일래스틱서치 | 맞춤형 검색 엔진 |
|---|---|---|
| 규모 확장성 | 어느 정도까지 확장 가능 | 이메일 사용 패턴에 따라 시스템을 최적화할 수 있으므로 규모 확장이 용이 |
| 시스템 복잡도 | 두 가지 상이한 시스템을 동시에 유지해야 함: 데이터 저장소와 일래스틱서치 | 하나의 시스템 |
| 데이터 일관성 | 한 데이터의 두 사본이 존재. 하나는 메타데이터 저장소에 있고 다른 하나는 일래스틱서치 내에 있다. 따라서 데이터 일관성을 유지하기 까다롭다. | 메타데이터 저장소에 하나의 사본만 유지됨 |
| 데이터 손실 가능성 | 없다. 색인이 손상되면 주 저장소의 데이터를 사용해 복구한다. | 없다. |
| 개발 비용 | 통합하기 쉬운 편이지만 대규모 이메일 검색이 필요한 경우 일래스틱서치를 전담하는 팀이 필요할 수 있다. | 맞춤형 검색 솔루션 구현이 필요하므로 굉장히 많은 엔지니어링 노력이 필요하다. |
소규모의 이메일 시스템을 구축하는 경우에는 ElasticSearch가 좋은 선택지다.
통합하기 쉽고 엔지니어링에 많은 노력이 필요하지도 않다.
규모 확장성 및 가용성
각 사용자의 데이터 접근 패턴은 다른 사용자와 무관하므로, 시스템의 대부분 컴포넌트는 수평적으로 규모 확장이 가능할 것으로 기대할 수 있다.
가용성을 향상시키기 위해서는 데이터를 여러 데이터센터에 다중화하는 것이 필요하다.
사용자는 네트워크 토폴로지 측면에서 봤을 때 자신과 물리적으로 가까운 메일 서버와 통신한다.
장애 때문에 네트워크 파티션, 즉 통신이 불가능한 네트워크 영역이 생기게 되면 사용자는 다른 데이터센터에 보관된 메시지를 이용한다.
4단계: 마무리
추가로 논의해 볼 만한 주제로는 다음과 같다.
- 결함 내성(fault tolerance)
- 노드 장애, 네트워크 문제, 이벤트 전달 지연 등의 문제에 어떻게 대처할지
- 규정 준수(compliance)
- 각 나라에 준수해야 할 법규가 있음
- 보안(security)
- 최적화(optimization)
- 저장하기 전에 저장소에 이미 동일한 첨부 파일이 있는지 확인하면 저장 연산 실행 비용 최적화 가능