Design Distributed Mail Service
요구사항
기능
이메일 발송/수신
모든 이메일 조회
읽음 여부 필터링
검색 기능
스팸 및 바이러스 방지 기능
첨부 파일 지원
SMTP / POP / IMAP 등 프로토콜 지원
규모
사용자 수: 10억 명
하루 평균 전송 이메일 건수: 10건
하루 평균 수신 이메일 건수: 40건
이메일 하나의 평균 메타데이터 크기: 50KB
첨부 파일 평균 크기: 500KB
첨부 파일 포함 비율: 20%
추정
이메일 전송 QPS = 10억 명 * 평균 10건 / 24시간 / 3600초 = 115,740
1년 메타데이터 용량 = 10억 명 * 평균 40건 * 365일 * 50KB = 730TB
1년 첨부 파일 용량 = 10억 명 * 평균 40건 * 365일 * 500KB * 20% = 1,460PB
배경 지식
이메일 프로토콜
이메일을 주고받는 프로토콜에는 여러 가지가 존재한다.
SMTP(Simple Mail Transfer Protocol): 이메일을 한 서버에서 다른 서버로 보내는 표준 프로토콜
POP(Post Office Protocol): 이메일 클라이언트가 원격 메일 서버에서 이메일을 수신하고 다운로드하기 위해 사용되는 표준 프로토콜
단말로 다운로드 된 이메일은 서버에서 삭제되어, 한 대 단말에서만 수신 가능
이메일을 일부만 읽을 수 없어, 용량이 큰 첨부 파일이 첨부 된 경우 많은 시간이 소요됨
IMAP(Internet Message Access Protocol): 이메일 클라이언트가 원격 메일 서버에서 이메일을 수신하고 다운로드하기 위해 사용되는 표준 프로토콜
POP와 달리 메일 서버에서 지워지지 않아 여러 대의 단말에서 메일을 읽을 수 있음
메시지를 열기 전엔 헤더만 다운 받고, 전체 메시지를 읽을 때만 다운로드
개인 이메일 계정에서 가장 많이 사용되는 프로토콜
HTTPS(HyperText Transfer Protocol Secure): 메일 전송 프로토콜은 아니며, 웹 기반 메일 시스템 접속에 사용되는 프로토콜
전통적 메일 서버 동작
전통적 메일 서버의 아키텍처는 간단했으며, 메일을 전송하는 과정을 다음과 같이 요약할 수 있다.
A가 아웃룩 클라이언트에 로그인 후 B에게 전송
해당 이메일은 아웃룩 SMTP 메일 서버로 전송(SMTP 프로토콜 사용)
아웃룩 서버는 DNS 질의를 통해 수신사 SMTP 서버 주소 조회
알아낸 주소의 해당 SMTP 메일 서버로 이메일 전송(SMTP 프로토콜 사용)
수신한 지메일 서버는 이메일을 저장
B가 로그인한 지메일 클라이언트에서 IMAP/POP 서버에 이메일 확인 요청
IMAP/POP 서버는 저장된 이메일을 조회 후 클라이언트로 전송
이메일 저장도 시스템의 파일과 디렉터리를 활용하는 간단한 방식으로 이루어졌다.
하지만 이 구조는 수 십억 개의 이메일을 검색하고 백업하는 목적으로 활용하기엔 디스크 I/O가 병목이 되어 부적절하다. 때문에 많은 사용자와 많은 데이터를 처리하기 위해 현재는 분산 메일 서버 아키텍처를 사용하고 있다.
이메일 API
웹 메일 통신에는 일반적으로 HTTP 프로토콜이 사용되며, 핵심 API는 다음과 같다.
POST /message
: To, Tc, Bcc 헤더에 명시된 수신자에게 메시지 전송GET /folders
: 주어진 이메일 계정에 존재하는 모든 폴더 목록 반환GET /folders/{:folder_id}/message
: 주어진 폴더 아래 모든 메시지 반환GET /message/{:message_id}
: 주어진 특정 메시지에 대한 모든 정보 반환
분산 메일 서버 아키텍처
컴포넌트
여러 서버 사이에 데이터 동기화와, 수신자 메일 서버의 이메일 스팸 구분 등 많은 문제를 해결하기 위해 여러 컴포넌트로 구성된 분산 메일 서버 아키텍처를 사용한다.
웹메일: 사용자가 메일을 받고 보내는 인터페이스
웹 서버: 사용자가 이용하는 요청/응답 서비스로, 사용자 인증, 메일 전송, 메일 수신 등의 모든 이메일 API를 처리
실시간 서버: 새로운 이메일 내역을 클라이언트에 실시간으로 전달
저장소 계층
메타데이터 데이터베이스: 이메일 제목 / 본문 / 발신인 / 수신인 등 메타데이터 저장
첨부 파일 저장소: 대용량 파일을 저장하는 데 적합한 데이터베이스 사용(아마존 S3)
분산 캐시: 최근 수신 이메일은 자주 읽을 가능성이 높아 메모리에 캐싱(레디스)
검색 저장소: 고속 텍스트 검색을 지원하는 역 인덱스를 자료구조로 한 저장소 사용
이메일 전송 절차
사용자가 웹 메일 환경에서 메일 작성 후 전송
웹 서버에 전달 받기 전 로드밸런서에서 처리율 제한에 따라 요청을 웹 서버에 전달
전달 받은 메일에 대해 아래 동작 수행
크기 및 한도 같은 기본적인 이메일 검증
스팸 여부와 바이러스 감염 여부 검사
메일을 외부 전송 큐로 전달
첨부파일이 큰 경우엔 객체 저장소에 따로 저장 후 참조 정보만 큐에 전달
메시지 큐에서 외부 전송 SMTP 서버로 전달
외부 전송 SMTP 서버에서도 이메일 검증
수신자의 메일 서버로 메일 전송
실패 시 지수적 백오프와 같은 전략으로 메일 전송 재시도
이메일 수신 절차
전송된 이메일이 로드밸런서에 도착
여러 SMTP 서버로 이메일 전달
수신 이메일 큐로 전달
첨부파일이 큰 경우엔 객체 저장소에 따로 저장 후 참조 정보만 큐에 전달
메일 처리 서버로 보낸 후 메일 검증
검증된 이메일을 메일 저장소 / 캐시 / 객체 저장소 등에 보관
수신자가 온라인 상태인 경우 이메일을 실시가 서버인 웹 소켓 서버로 전달
수신자가 오프라인 상태인 경우 이메일을 저장소 계층에 저장
상세 설계
메타데이터 데이터베이스
이메일 메타데이터는 다음과 같은 특성을 가진다.
이메일 헤더는 일반적으로 작고 빈번하게 이용
본문의 크기는 작은 것 부터 큰 것까지 다양
본문의 읽기는 일반적으로 한 번만 이루어짐
이메일에 대한 권한 처리 필요(특정 사용자만 읽을 수 있도록)
보통 최근의 이메일만 자주 읽음
데이터 손실이 발생하면 안 됨
이러한 데이터 특성은 다음과 같은 요구 사항으로 정리할 수 있다.
단일 컬럼의 크기가 클 수 있음
디스크 I/O 최소화되도록 설계
가용성이 높고 장애 감내가 가능해야 함
증분 백업이 가능해야 함
강력한 데이터 일관성 보장
이러한 특성을 고려하여 데이터베이스의 장단점을 비교해보면 다음과 같다.
RDBMS
헤더와 본문에 대한 인덱스를 만들어 간단한 질의를 빠르게 처리 가능
큰 이메일을 BLOB으로 저장하게 되는데, 그 경우 처리 시간이 길어짐
분산 객체 저장소
이메일의 원시 데이터 그대로 객체 저장소에 보관하여 데이터 백업에 용이
읽음 표시 / 키워드 검색 등 기능 구현이 어려움
NoSQL
지메일이 해당 방법을 사용하고 있으나, 구현 방법 알 수 없음(오픈 소스 X)
기능을 완벽하게 지원하는 데이터베이스는 없다고 볼 수 있고, 실제로 대형 이메일 서비스 업체는 독자적인 데이터베이스 시스템을 구축하고 있다.
검색
이메일 검색 기능은 다음과 같은 특성을 가진다.
검색 기능 제공을 위해 이메일이 전송/수신/삭제 될 때 마다 인덱싱 작업 수행 필요
반면에 검색은 사용자가 검색을 할 때만 실행되는데, 이는 빈번하지 않음
쓰기 연산이 읽기 연산보다 더 많이 발생하게 됨
검색 기능을 제공하기 위해 맞춤형 검색 솔루션과 엘라스틱서치를 이용하는 방안이 존재한다.
엘라스틱서치
처리 방법
검색은 엘라스틱서치를 이용하여 동기적으로 수행
전송/수신/삭제는 비동기식 호출하여 엘라스틱 클러스터에 반영
특징
엘라스틱은 검색에 최적화되어 있어, 검색 속도가 빠름
비동기적으로 처리되는 엘라스틱 클러스터와 주 이메일저장소와 데이터 동기화가 까다로움
맞춤형 검색 솔루션
특징
인덱싱을 사용하는 경우 다량의 쓰기 연산에 대한 해결책 필요
참고자료
Last updated