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): 메일 전송 프로토콜은 아니며, 웹 기반 메일 시스템 접속에 사용되는 프로토콜

전통적 메일 서버 동작

전통적 메일 서버의 아키텍처는 간단했으며, 메일을 전송하는 과정을 다음과 같이 요약할 수 있다.

  1. A가 아웃룩 클라이언트에 로그인 후 B에게 전송

  2. 해당 이메일은 아웃룩 SMTP 메일 서버로 전송(SMTP 프로토콜 사용)

  3. 아웃룩 서버는 DNS 질의를 통해 수신사 SMTP 서버 주소 조회

  4. 알아낸 주소의 해당 SMTP 메일 서버로 이메일 전송(SMTP 프로토콜 사용)

  5. 수신한 지메일 서버는 이메일을 저장

  6. B가 로그인한 지메일 클라이언트에서 IMAP/POP 서버에 이메일 확인 요청

  7. IMAP/POP 서버는 저장된 이메일을 조회 후 클라이언트로 전송

이메일 저장도 시스템의 파일과 디렉터리를 활용하는 간단한 방식으로 이루어졌다.

home
    user1
        Maildir
            new
            cur
            tmp
            ...
            
    user2
        Maildir
            new
            cur
            tmp
            ...
                 
    ...

하지만 이 구조는 수 십억 개의 이메일을 검색하고 백업하는 목적으로 활용하기엔 디스크 I/O가 병목이 되어 부적절하다. 때문에 많은 사용자와 많은 데이터를 처리하기 위해 현재는 분산 메일 서버 아키텍처를 사용하고 있다.

이메일 API

웹 메일 통신에는 일반적으로 HTTP 프로토콜이 사용되며, 핵심 API는 다음과 같다.

  1. POST /message: To, Tc, Bcc 헤더에 명시된 수신자에게 메시지 전송

  2. GET /folders: 주어진 이메일 계정에 존재하는 모든 폴더 목록 반환

  3. GET /folders/{:folder_id}/message: 주어진 폴더 아래 모든 메시지 반환

  4. GET /message/{:message_id}: 주어진 특정 메시지에 대한 모든 정보 반환

분산 메일 서버 아키텍처

컴포넌트

여러 서버 사이에 데이터 동기화와, 수신자 메일 서버의 이메일 스팸 구분 등 많은 문제를 해결하기 위해 여러 컴포넌트로 구성된 분산 메일 서버 아키텍처를 사용한다.

      웹메일
    /       \
 https     웹소켓
  /           \
웹 서버      실시간 서버
  \           /
   \         /
    \       /
    저장소 계층
  • 웹메일: 사용자가 메일을 받고 보내는 인터페이스

  • 웹 서버: 사용자가 이용하는 요청/응답 서비스로, 사용자 인증, 메일 전송, 메일 수신 등의 모든 이메일 API를 처리

  • 실시간 서버: 새로운 이메일 내역을 클라이언트에 실시간으로 전달

  • 저장소 계층

    • 메타데이터 데이터베이스: 이메일 제목 / 본문 / 발신인 / 수신인 등 메타데이터 저장

    • 첨부 파일 저장소: 대용량 파일을 저장하는 데 적합한 데이터베이스 사용(아마존 S3)

    • 분산 캐시: 최근 수신 이메일은 자주 읽을 가능성이 높아 메모리에 캐싱(레디스)

    • 검색 저장소: 고속 텍스트 검색을 지원하는 역 인덱스를 자료구조로 한 저장소 사용

이메일 전송 절차

  1. 사용자가 웹 메일 환경에서 메일 작성 후 전송

  2. 웹 서버에 전달 받기 전 로드밸런서에서 처리율 제한에 따라 요청을 웹 서버에 전달

  3. 전달 받은 메일에 대해 아래 동작 수행

    1. 크기 및 한도 같은 기본적인 이메일 검증

    2. 스팸 여부와 바이러스 감염 여부 검사

  4. 메일을 외부 전송 큐로 전달

    • 첨부파일이 큰 경우엔 객체 저장소에 따로 저장 후 참조 정보만 큐에 전달

  5. 메시지 큐에서 외부 전송 SMTP 서버로 전달

  6. 외부 전송 SMTP 서버에서도 이메일 검증

  7. 수신자의 메일 서버로 메일 전송

    • 실패 시 지수적 백오프와 같은 전략으로 메일 전송 재시도

이메일 수신 절차

  1. 전송된 이메일이 로드밸런서에 도착

  2. 여러 SMTP 서버로 이메일 전달

  3. 수신 이메일 큐로 전달

    • 첨부파일이 큰 경우엔 객체 저장소에 따로 저장 후 참조 정보만 큐에 전달

  4. 메일 처리 서버로 보낸 후 메일 검증

  5. 검증된 이메일을 메일 저장소 / 캐시 / 객체 저장소 등에 보관

  6. 수신자가 온라인 상태인 경우 이메일을 실시가 서버인 웹 소켓 서버로 전달

  7. 수신자가 오프라인 상태인 경우 이메일을 저장소 계층에 저장

상세 설계

메타데이터 데이터베이스

이메일 메타데이터는 다음과 같은 특성을 가진다.

  • 이메일 헤더는 일반적으로 작고 빈번하게 이용

  • 본문의 크기는 작은 것 부터 큰 것까지 다양

  • 본문의 읽기는 일반적으로 한 번만 이루어짐

  • 이메일에 대한 권한 처리 필요(특정 사용자만 읽을 수 있도록)

  • 보통 최근의 이메일만 자주 읽음

  • 데이터 손실이 발생하면 안 됨

이러한 데이터 특성은 다음과 같은 요구 사항으로 정리할 수 있다.

  • 단일 컬럼의 크기가 클 수 있음

  • 디스크 I/O 최소화되도록 설계

  • 가용성이 높고 장애 감내가 가능해야 함

  • 증분 백업이 가능해야 함

  • 강력한 데이터 일관성 보장

이러한 특성을 고려하여 데이터베이스의 장단점을 비교해보면 다음과 같다.

  • RDBMS

    • 헤더와 본문에 대한 인덱스를 만들어 간단한 질의를 빠르게 처리 가능

    • 큰 이메일을 BLOB으로 저장하게 되는데, 그 경우 처리 시간이 길어짐

  • 분산 객체 저장소

    • 이메일의 원시 데이터 그대로 객체 저장소에 보관하여 데이터 백업에 용이

    • 읽음 표시 / 키워드 검색 등 기능 구현이 어려움

  • NoSQL

    • 지메일이 해당 방법을 사용하고 있으나, 구현 방법 알 수 없음(오픈 소스 X)

기능을 완벽하게 지원하는 데이터베이스는 없다고 볼 수 있고, 실제로 대형 이메일 서비스 업체는 독자적인 데이터베이스 시스템을 구축하고 있다.

검색

이메일 검색 기능은 다음과 같은 특성을 가진다.

  • 검색 기능 제공을 위해 이메일이 전송/수신/삭제 될 때 마다 인덱싱 작업 수행 필요

  • 반면에 검색은 사용자가 검색을 할 때만 실행되는데, 이는 빈번하지 않음

  • 쓰기 연산이 읽기 연산보다 더 많이 발생하게 됨

검색 기능을 제공하기 위해 맞춤형 검색 솔루션과 엘라스틱서치를 이용하는 방안이 존재한다.

  1. 엘라스틱서치

    • 처리 방법

      • 검색은 엘라스틱서치를 이용하여 동기적으로 수행

      • 전송/수신/삭제는 비동기식 호출하여 엘라스틱 클러스터에 반영

    • 특징

      • 엘라스틱은 검색에 최적화되어 있어, 검색 속도가 빠름

      • 비동기적으로 처리되는 엘라스틱 클러스터와 주 이메일저장소와 데이터 동기화가 까다로움

  2. 맞춤형 검색 솔루션

    • 특징

      • 인덱싱을 사용하는 경우 다량의 쓰기 연산에 대한 해결책 필요

참고자료

Last updated