Во втором десятилетии XXI века почта — это не только переписка между людьми. Пользователи ожидают, что почта будет помогать им решать ежедневные задачи, экономить время, подсказывать недостающую информацию. Мы постоянно добавляем в Яндекс.Почту новые штрихи, которые делают жизнь пользователей немного проще. Сегодня мы бы хотели вместе с вами заново пройти тот путь, который Яндекс.Почта проделала за 13 лет, уделяя особое внимание развитию архитектуры и инфраструктуры сервиса.
Сейчас мало кто помнит, что самая первая версия Яндекс.Почты была написана на PHP, а письма хранились прямо в реляционной БД рядом с мета-информацией. В том не таком уж и далёком 2000 году весь почтовый сервис умещался на десятке серверов. Сами сервера обслуживались полностью в ручном режиме: от конфигурации дисков до установки операционной системы, никакой автоматизации не было.
2002 год
Первым, от чего пришлось отказаться, стал язык PHP. В то время он чаще мешал, чем помогал развиваться.
Вокруг было много первоклассных Perl-специалистов, под сам Perl уже тогда существовало огромное количество библиотек, и мы переписали почту на связке Apache + Perl. Стало быстрее и проще.
2005 год
Прошло еще немного времени, и существующая многопроцессная модель Apache перестала справляться с нагрузкой. Отдельную проблему создавал интерпретатор Perl и особенности его подключения к хранилищу мета-информации. В результате после серии экспериментов, в том числе с бета-версией тредного Apache 2, мы написали собственный модульный сервер приложений под названием Baida. Он может использовать как тредовую, так и event-loop модель обработки запросов, очень удобен для подключения расширений, в том числе интерпретаторов языков — например, JS. Сервер, как и большая часть кода Яндекс.Почты, написан на C++. Во многом это библиотека для сетевого обмена и работы с тредами, которая была нужна для того, чтобы обеспечить работу сервиса при росте нагрузок.
В этот сервер для облегчения эксплуатации встроен real-time мониторинг его состояния. Вдобавок мы полностью отказались от Perl. Вместо него был создан отдельный Baida-модуль — Web Mail Interface, который внутри себя содержал интерпретатор XScript: парсер XML и движок XSLT-преобразований. Другая особенность — пул соединений с реляционным мета-хранилищем и эффективное управление этим пулом.
2006 год
Стало понятно, что хранить тела писем в реляционном хранилище с растущими объемами данных не получится. Так появился заказ на специализированное хранилище писем, которое получило название Mulca. Технология за восемь лет развития претерпела не так много архитектурных изменений, хотя хранилище многократно выросло в размерах. Сейчас, кроме Почты, оно используется для хранения файлов в Яндекс.Диске.
С момента запуска отдельного хранилища, мы экспериментировали с конфигурацией дисковой подсистемы на серверах: пробовали разные уровни RAID и объединяли устройства в большие разделы. Дольше всего просуществовала конфигурация RAID5, но у нее были недостатки, которые нужно было устранять: RAID5 требует вычисления контрольных сумм, а также повторного чтения блока при его дозаписи, что снижает скорость записи. В случае, если необходимо пересобрать массив, его производительность так же деградирует на долгое время.
Тогда же мы начали проводить эксперименты с SATA дисками вместо SCSI. Оказалось, что без RAID5 SATA диски дают приблизительно ту же скорость доступа к данным, что и SCSI, собранные в RAID5 в нашей конфигурации. Нужно было или оптимизировать конфигурацию, или же придумать своё решение для обеспечения отказоустойчивости.
2007 год
Мы приняли решение полностью отказаться от RAID массивов на Mulca, и обеспечивать отказоустойчивость на уровне хранилища, а не дисковой подсистемы отдельного сервера. Некоторое время спустя высокопроизводительные SCSI диски небольшой емкости мы заменили на большие SATA-диски. Переход на отдельные файловые системы и отказ от избыточности на уровне дисков дал неплохую экономию ресурсов по месту. Вкупе с переходом на SATA ввод в строй новых объемов хранилища заметно ускорился. В случае выхода диска из строя мы просто копировали данные из второй копии в другом дата-центре. В это же время впервые появилась наша знаменитая почтовая стена.
Разработка этого dashboard была инициирована системными администраторами и служила тому, чтобы сводить воедино восприятие ситуации эксплуатацией, разработкой и менеджерами. Мы выделили самые важные числа и повесили их на видное место, чтобы все причастные к продукту видели, как он себя чувствует. К слову, внешний вид стены почти не поменялся с годами. С этой стены во всем Яндексе пошла традиция вешать панели и проекторы с важной информацией.
Традиционный POP3 со временем эволюционировал: из модуля Baida превратился в самостоятельный демон и научился читать данные из реплики мета-хранилища. Примерно в это же время стало понятно, что нам нужен протокол IMAP, и мы, используя опыт, полученный при разработке POP3, начали писать его с нуля. Текущая версия нашего IMAP — четвертая по счету, и мы не планируем на этом останавливаться.
Для доставки почты использовался SMTP-сервер zMailer, и мы начали чувствовать его ограничения: в нашей архитектуре он плохо принимал входящие соединения, так как на каждое входящее подключение созавал новый процесс, и очень быстро деградировал при росте очереди. Мы накладывали на него свои патчи, но это не сильно помогало в решении проблем. Стало понятно, что нам нужна другая технология. После долгих обсуждений мы решили переключиться на Postfix, он намного лучше работает с большими очередями. Пришлось, конечно, переписать агент доставки из Postfix в наше хранилище.
2008 год
Мы поставили перед собой задачу обеспечения скорости доставки писем. На то время письмо в среднем доставлялось за несколько секунд, и такое время доставки считалось хорошим. Нам же было нужно, чтобы почта была сравнима по скорости с системами мгновенной доставки сообщений.
Сначала мы написали новый агент доставки — Fastsrv, и встроили его сначала в zMailer, а затем и в Postfix. Fastsrv практически не имеет очереди и держит постоянное соединение в мета-базу. Его установили на кластерах приема почты. Любое входящее письмо старались мгновенно положить пользователю в ящик, и только если не получилось, откидывали в очередь на доставку. Так большая часть писем стала доставляться практически мгновенно. Очереди на доставку из привычной картинки на графиках стали символом проблемы, и мы отразили это в мониторингах.
Дополнительно мы разделили очереди на отправку и приём писем, чтобы в случае каких-либо проблем с одной частью, сохранять работоспособность части сервиса.
Теперь пришла пора заменить Postfix на приеме почты. Свой собственный SMTP-сервер мы назвали NwSMTP. Он был задуман как event-based сервер, способный обрабатывать неограниченно большое число соединений. Аналогично устроен небезызвестный web-сервер NGINX, но на тот момент в нем не было поддержки SMTP-proxy. Так мы начали принимать письма практически мгновенно. Разработка NwSMTP была устроена довольно интересно: выкатки происходили очень часто — иногда по версии в час. Сразу после сборки новой версии ее выкатывали на одну production-машину и смотрели, что происходит. Такая оперативность позволила очень быстро выпустить продукт. Отсюда пошло название NwSMTP, это сокращение от Next Week SMTP: почти любая задача в нем за семь дней проходит полный цикл разработки и на вопрос «Когда вы это сделаете?» группа разработки сервера отвечает: «На следующей неделе».
В середине 2008 года, когда у нас запустился Jabber-сервер, мы в качестве эксперимента сделали real-time уведомления о новых письмах. Чтобы не тормозить систему покладки, нотификации работали по UDP-протоколу, а внутри содержали XML-данные, удобные для превращения в XMPP-пакет. Сегодня шутки про «XML по UDP» вызывают улыбку, но в то время это работало, хотя и с большими ограничениями и потерями части нотификаций.
2009 год
К этому времени в Яндекс.Почте одновременно работало несколько интерфейсов. Neo не был интерактивным: HTML-страница генерировалась внутри WMI. Modern содержал интерактив, но был построен на той же архитектуре.
Мы решли придумать интерфейс, который загружает только самое необходимое — то, что изменилось прямо сейчас. После серии экспериментов удалось подготовить платформу и доказать, что такой сервис может работать. Так на свет появился интерфейс Daria, его можно видеть в Почте и сейчас.
С переходом на динамику очень сильно поменялась структура запросов. К этому времени сервер nginx достаточно развился и мы решили поставить его перед Baida для отдачи статики в Почте (к этому времени он уже использовался, например, в Народе). Одновременно с Daria мы экспериментировали с запуском интерпретируемых языков на стороне сервера. Остановились на Javascript в основном из-за удобства, так как на клиенте и сервере используется один и тот же язык программирования. Под сервер Baidu написали модуль с Gecko, встроить V8, к сожалению было невозможно. Он уже был популярен, но V8 на тот момент не мог работать с тредной моделью программирования (в последних версиях V8 этот недостаток исправлен).
Nginx позволил обрабатывать разные URL-ы по-разному, и мы разнесли собственно логику, раздачу вложений, а также вынесли старые интерфейсы на отдельные кластера. Это значительно упростило развертывание обновлений и эксплуатацию, а также позволило декомпозировать целостную систему на отдельные компоненты. Основные методы работы почты стали независимы от второстепенных, вся система в целом стала стабильнее.
В этом году мы сделали треды, что безусловно, сильно отразилось на структуре БД и нагрузке.
Традиционно размер ящика был ограниченного размера, и Яндекс.Почта не была исключением. Но мы решили, что пора отменить это ограничение. Такое решение изменило наш регламент. Если раньше мы могли рассчитывать нагрузку и размер хранилищя, то с бесконечным ящиком все немного сложнее. Мы уже не могли в каждый момент времени сказать, сколько данных нам нужно положить на хранение. В это время мы складывали примерно по терабайту данных в день. Для сравнения, сегодя мы сохраняем по 120 Тб в сутки.
Отдельная история про просмотрщик документов
Как-то мы захотели проверить, насколько востребованным будет сервис просмотра документов. Удалось очень быстро разработать прототип на python и поднять ферму OpenOffice, который конвертировал документы в HTML. Перед сервисом поставили nginx для защиты от всплесков нагрузки, добавили модуль обращения в хранилище за документами и отдали в эксплуатацию. В таком виде прототип просуществовал несколько лет, оброс мониторингами, оптимизациями и второстепенными возможностями. Сейчас эксплуатируется уже вторая версия просмотрщика, которая впрочем работает примерно на тех же технологиях.
2010 год
В этот год мы полностью переделали поиск по почте. Существовавшая на тот момент реализация не устраивала нас как скоростью работы, так и качеством результата поиска. В результате переработки поиска получилась система, на базе которой работает не только собственно поиск писем, обслуживая десятки миллионов запросов в сутки, но также некоторые другие функции Яндекс.Почты.
Нас всё чаще стали просить сделать, чтобы наш почтовый сервис можно было подключить к собственному домену. Так появился сервис Почта для доменов, о котором мы уже писали. Примечателен он тем, что был разработан и запущен на базе уже существующих компонент с минимальными доработками. Это полностью интеграционный сервис, собирающий информацию по кусочкам из разных мест, чтобы затем показать ее администратору домена.
Тогда же в 2010 году мы проделали большую работу, чтобы перевести внутреннюю переписку Яндекса (наши коллеги пишут очень много писем) на технологии Яндекс.Почты. Она работает практически так же, как Почта для доменов, но интегрирована с другими внутренними сервисами компании. Практически все новые функции сначала проходят обкатку на корпоративной почте, отлаживаются, уточняются функционально, и только после этого становятся доступны всем пользователям.
2011 год
Мы активно начали предлагать нашим пользователям использовать HTTPS для защиты передаваемых данных, а затем включили защищенную работу с почтой по умолчанию. Это решение, с одной стороны, сделало работу с Яндекс.Почтой более безопасной, а с другой — потребовало от нас работы по настройке параметров соединения. Классически почта работает на длинных HTTPS-подключениях с большим значением keepalive. Однако в смартфонах этот режим подключения часто ограничен или работает странно. При HTTPS-соединении возникают дополнительные накладные расходы на рукопожатие, а если браузер не хочет или не может держать открытым соединение, то каждый запрос будет вызывать дополнительные расходы. На узких каналах и слабых процессорах телефонов это время становится заметным. Сразу после включения HTTPS по умолчанию мы увидели, как выросли графики времени загрузки интерфейса почты, и потребовалось некоторое время на поиск причин и решение проблемы. Другой проблемой стало отображение HTTP-содержимого писем по HTTPS, например, изображений, добавленных через тег <img>
. Мы построили отдельный сервис, который кеширует изображения и способен отдавать их по HTTPS, после чего, заменили вставленные в письма изображения на ссылки нашего прокси. При проектировании подобных сервисов важно не допустить появления открытого редиректа — возможности открыть любой URL с доверенного хоста, а добавление уровней защиты не должно приводить к заметному снижению производительности. Мы справились и с этой задачей.
Тогда же начались первые эксперименты с нереляционными хранилищами данных. Первым сервисом, который был переведен на MoSQL (MongoDB), стала адресная книга. До этого момента у эксплуатации почты не было боевого опыта работы с внешними нереляционными технологиями хранения. Этот эксперимент удался — адресная книга и сегодня хранит книжки контактов в MongoDB.
Тем временем Яндекс готовился к запуску в Турции. Для сервиса это означало обязательную поддержку локализации, причем перевод интерфейса — это только малая часть работы. Фактически мы подготовили и запустили отдельный продукт — турецкую Яндекс.Почту — на той же кодовой базе. Они несколько различаются функционально, о чем теперь нужно помнить при разработке. Для ускорения доступа мы установили в Европе сервера, с которых отдаем статический контент, — так наша сеть стала еще разветвленнее.
Произошли изменения и в процессах разработки. Web Mail Interface, о котором говорилось выше, начал использовать Scrum и гибкие технологии разработки. Нам удалось реализовать цикл непрерывной выкладки новой функциональности, при котором каждая фича или исправление дефекта выкладывается отдельно, но при этом проходит полный производственный цикл: разработку, автоматическое тестирование, функциональное тестирование, нагрузочное тестирование, и, наконец, двухэтапная выкладка в бой — сначала на один сервер, а потом уже на весь кластер. Такой процесс позволяет очень быстро реагировать на появление новых продуктовых требований и устранять дефекты.
Наши дни
Запуск Яндекс.Диска значительно изменил наши протоколы эксплуатации оборудования. Диск, так же как и Почта, использует Mulca, чтобы хранить файлы пользователей, но при этом объемы загружаемой информации превосходят почтовые в несколько раз. Каждый месяц мы добавляем не менее пяти стоек серверов в Mulca, чтобы обеспечить надежное хранение ваших писем и файлов. Пропорционально выросли и потребности в пропускной способности опорной сети и сети внутри ДЦ. Объемы данных таковы, что в долгосрочной перспективе мы перешли от планирования установки стоек к планированию открытия новых дата-центров.
Чтобы оживить почтовый ящик, мы разработали и запустили технологию «Ева», которая из открытых источников собирает аватары пользователей и показывает их. Все аватары масштабируются, обрезаются и кешируются в специальном хранилище, в основе которого лежит другая наша разработка, — Elliptics — отказоустойчивое распределенное key-value хранилище, распространяемое под лицензией GPL.
Карточки организаций, которые можно увидеть в письмах, это еще один пример быстрого решения продуктовой задачи. Информация о компаниях обновляется не так часто, примерно один раз в две недели. Все остальное время — это просто статическая выдача, причем число этих организаций невелико — всего несколько десятков тысяч. Для решения задачи отображения карточек мы решили использовать кешированные статические html-файлы, которые доступны по хешу от имени домена организации. Поставленную задачу решили быстро и обеспечили высокую производительность и отказоустойчивость.
Технология «Маркер» позволила автоматически выделять полезную информацию из писем определенных типов. На этой технологии, например, работает извлечение информации из авиабилетов и выделение события из письма. За этим сервисом стоит большая работа эксплуатации, около сотни серверов и десятки миллионов запросов каждый день.
Тем временем в интернете назрели крупные перемены. Пространство адресов IPv4 подошло к концу, а 6 июня 2012 года считается Днем IPv6. К этому событию мы подготовили нашу внутреннюю архитектуру к работе в сетях IPv6. Сегодня IPv6 работает для домена mail.yandex.com и для отправки почты. Мы активно работаем над полной поддержкой IPv6 во всех компонентах и для всех наших доменов.
XScript, устраивавший нас долгое время, был окончательно исключен из работы почты. Теперь почта предстваляет собой статическое web-приложение, которое общается с бекендом посредством коротких вызовов API. Вызовы по-прежнему обрабатываются внутри WMI сервером Baida и транслируются через один из его модулей.
Почтовые сборщики научились собирать почту с использованием протокола IMAP. По IMAP передается значительно больше полезной информации, а значит, процесс сбора почты стал намного эффективнее.
За каждой из наших больших и маленьких, прошлых, существующих и будущих технологий стоят люди, настоящие профессионалы-инженеры: системные администраторы, разработчики, менеджеры. Мы всегда рады, когда к нам приходят те, кто любит задачи, которые еще никто не решал, кто готов быть на самом переднем краю технологий и не прочь вписать несколько страниц в историю развития Яндекс.Почты.
Автор: vsadm