9 октября

Как мы создаём отказоустойчивую почту для высоких нагрузок. Go, RethinkDB, Cloud Native архитектура и немного магии

Блог компании МойОфисПрограммированиеАнализ и проектирование системУправление проектамиУправление продуктом
Привет, Хабр! Меня зовут Антон Герасимов, я руковожу департаментом разработки в московском центре компании МойОфис. Почти четыре года мы с командой создаём новую высоконагруженную и отказоустойчивую почтовую систему Mailion. Она предназначена для корпоративных коммуникаций и построена на Cloud Native микросервисной архитектуре. В этой статье я расскажу, как мы создавали продукт с момента замысла до текущей бета-версии, как затачивали почтовый движок под работу с контентом и как справлялись с вызовом — поддержать совместную работу даже 1 000 000 пользователей и масштабироваться на такое количество рабочих мест.

Чего не хватает почтовым сервисам?

Вы задумывались, почему в большинстве почтовых систем сделать операцию, отличную от базовой, — это нетривиальная задача? Нужно залезть в неочевидное место и там найти нужный пункт, а настройка совместного доступа обычно требует сертифицированного специалиста. Так быть не должно, но таких примеров масса.
С конца 80-х годов в области совместной работы с электронной почтой мало что менялось. Конечно, появились новые функции и клиентские протоколы, но ничего принципиально иного разработчики почтовых систем не предложили. В решениях, которые появились за это время, уделялось мало внимания деталям — простым пользовательским вещам, которые делают жизнь намного удобнее и экономят время пользователей. Это не так заметно при домашнем использовании, но для организаций с большим количеством сотрудников уже становится ощутимым.
В 2014 году компания Google попыталась сделать революционный шаг и запустила Inbox, который был построен не по принципу папок, а по принципу тегов. В основе сервиса лежала концепция сканирования входящих сообщений, их группировка по темам и автоматическим обогащением недостающей дополнительной информации.
Сервис предлагал и ряд корпоративных функций: календарь событий организации, сохранение ссылок для дальнейшей работы с ними, функцию задержки отправки писем, а также «умные ответы», которые значительно ускоряли коммуникацию с мобильных устройств. Спустя четыре года проект закрыли. Я тогда был очень расстроен, а 11 000 человек даже петицию подписали, что говорит о реальной потребности пользователей.
Внимательно проанализировав эту ситуацию, мы поняли, что Inbox просто опередил своё время. Людям, особенно в корпоративном мире, нужен простой и понятный интерфейс для решения типовых задач с возможностью быстрого доступа ко всем элементам деловой переписки — вложениям, ссылкам, различным отчётам и функциям, — который будет интуитивно понятным и одновременно функциональным, не вызывающим вопросов. А корпорациям необходимо обеспечить технологии одновременной работы сотен тысяч пользователей, высокие показатели по отказоустойчивости, а также встроенные механизмы самостоятельного восстановления системы.
Чтобы сделать корпоративную почту удобной как для пользователя, так и для администратора, с самого начала работы над Mailion мы провели множество фокус-групп и опросов. Они помогли нам выявить типовые сценарии использования корпоративной почты и составить перечень востребованных функций, а также спроектировать систему календарного планирования и дизайн интерфейсов.

Фокусируемся на совместной работе с данными

Изначально мы ориентировались на компании, где в совместной работе участвуют десятки или сотни тысяч активных пользователей. И мы разрабатывали не сервис, а продукт, который устанавливается на серверах, в частном облаке клиента, что связано с требованиями безопасности в корпорациях. Это существенно повлияло на ключевые требования к архитектуре:
  • экономическая эффективность решения;
  • производительность, необходимая для работы с большим количеством пользователей;
  • масштабируемость и изоляция компонентов.
Мы сразу сделали акцент на коллаборацию и решили не просто хранить сообщения, вложения и события календаря в почтовой системе, а ещё и оптимизировать их для одновременной работы сотен тысяч пользователей.
Обмен сообщениями происходит в любой организации. В среднем количество адресатов в одном сообщении — от двух до шести в зависимости от компании, и всё это копии. Файлы нужно хранить одним способом, почтовые сообщения — другим, и всем им требуется дедупликация данных. Не стоит забывать, что взаимодействие порождает большое количество операций ввода-вывода, которые существенно влияют на время отклика и в целом недёшевы.
Чтобы реализовать эти контент-зависимости и оптимизировать операции ввода и вывода именно для взаимодействия пользователей, мы разработали движок, который оперирует любыми сущностями как объектами, обеспечивая совместный доступ и контроль прав. И делает это всё над предметами, которые имеют разную природу. Например, у календарного события и почтового сообщения разные жизненные циклы, но обитают все они, по сути, в одной системе.
Мы разработали специализированное хранилище, которое снижает объём физического пространства, занимаемого данными, — тем самым эффективность операций ввода-вывода над «горячими» данными повышается.

Делаем реактивный бэкенд на Go

реактивный бэкенд на Go
Так как мы делаем продукт, который развёртывается на инфраструктуре клиента, то нам было важно предоставить инженерам возможность быстро, просто и удобно проводить эти действия, а также оперативно его обновлять. Для этого мы с самого начала выбрали микросервисную архитектуру по модели Cloud Native. Она предполагает разработку изолированных микросервисов, которые упаковываются в контейнеры и управляются через облако. Таким образом, у нас появляются персистентные хранилища и вокруг них работают сервисы, связанные между собой протоколом gRPC и обеспечивающие функциональность всей системы.
Для разработчиков Golang у нас есть разные задачи: от участия в создании архитектуры до оптимизации существующего кода и реализации новых фич / сервисов. В требованиях к системе, например, есть отказоустойчивость и самовосстанавливаемость. Это обусловлено тем, что мы создаем on-premise-решение, которое устанавливается у клиента, и с большой долей вероятности у нас не будет к нему доступа. Поэтому надо тщательно продумывать, как сделать так, чтобы в случае отказа система сама смогла быстро восстановиться. Наша команда проектирует сервис с нуля, поэтому нужно быть готовым к высокому уровню ответственности. Для нас важны знания кандидата о структурах данных и алгоритмах, опыт асинхронного программирования распределённых систем и работы в Linux-среде. Во время работы над продуктом можно существенно прокачать свои навыки и семимильными шагами вырасти как специалист, если человек, конечно, в этом заинтересован.
Алексей Бондаренко
Lead Calendar Team
В качестве серверного языка мы однозначно выбрали Go, на котором сейчас написано 98 % кода микросервисов. У него высокая производительность для решения наших задач, это позволяет быстро, в отличие от других языков, разрабатывать функциональность. У меня был опыт написания почтовых решений на других языках программирования, и по соотношению производительность / скорость разработки Go показал себя очень хорошо.
С самого начала разработки мы придерживаемся принципов, заложенных в архитектуру API First: все сервисы и клиенты используют для взаимодействия единый контракт на API. Мы очень любим кодогенерацию. Такой подход позволяет синхронизировать разработку интерфейсов между сервисами и их потребителями, в том числе фронтенд-командой, а также всегда иметь актуальную документацию ко всем компонентам.

Выбираем Polymer, а затем меняем подход на работу с нативными веб-компонентами

В качестве фронтенд-фреймворка мы выбрали Polymer. Когда Google его анонсировал, казалось, что он будет активно его продвигать в качестве стандарта. В итоге многие вещи из Polymer действительно вошли в стандарт и стали нативно поддерживаться браузерами. Мы выбрали это направление, но в какой-то момент Google приостановил развитие Polymer и сфокусировался на развитии веб-компонентов в консорциуме с производителями других браузеров. Мы в это время тоже скорректировали свой подход к использованию Polymer и сейчас в большей части компонентов уменьшаем зависимость от фреймворка, что в будущем позволит более гибко использовать подобные инструменты.
Практически каждый, даже самый простой на первый взгляд компонент интерфейса может менять поведение и внешний вид в зависимости от контекста, в котором он используется. Адаптивность почты представляет собой не только использование медиазапросов для описания стилевых свойств компонентов в зависимости от размеров экрана, но и расчёт максимальных и минимальных значений ширин структурных блоков лэйаута, определение блоков, которые должны быть показаны и скрыты. Нужно учитывать, что пользователь за секунды может передумать и выполнить совершенно противоречивые действия, которые система должна корректно обработать. Мы выжимаем из современных технологий всё, что можно применить при создании инновационного продукта. И поскольку мы участвуем не только в разработке компонентов, но и в их тестировании, фронтенд-разработчику важно уметь взаимодействовать с другими командами и постоянно учиться новому. У вас есть все шансы поработать над созданием высоконагруженного продукта в компании сильных специалистов.
Дмитрий Зайцев
Lead Frontend Team
Специально для Mailion мы создали новую дизайн-систему и на её базе построили UI-Kit. Так как мы применяем компонентный подход, то разрабатываем базовые блоки, из которых уже строим всё приложение. И это достаточно большая и необычная задача, которая усложняется тем, что наше приложение оперирует очень большим объёмом данных. Задача по созданию функционального, быстрого и современного интерфейса потребовала немалой ловкости наших фронтенд-мастеров.

Ищем zero-maintenance базу данных

zero-maintenance база данных
Наш продукт должен иметь возможность эксплуатироваться в условиях, где может не быть экспертов в управлении сложными кластерными системами. Из-за этого нам нужно было снизить сложности при масштабировании и управлении базой данных, поэтому одним из требований было zero-maintenance. Мы выбрали RethinkDB — она не требует большого внимания к своей инфраструктуре.
Один из экспериментов, который я лично проводил, — решардинг кластера с мобильного телефона на 3G, сидя в кафе на обеде. Мало кто из производителей БД предоставляет настолько простой и стабильный интерфейс для подобного рода операций, не требующий глубоких познаний в том, как устроена инфраструктура, лежащая под капотом.
Наши DevOps-инженеры занимаются поддержкой и постоянным развитием системы CI/CD на различных платформах и ОС, построением продукта, сборкой дистрибутива. Будущего коллегу ждут также задачи по оптимизации текущих решений и их модернизации, написание скриптов, ролей и сценариев на ansible для автоматизации всего и вся. Скучать никогда не приходится, держать высокий ритм без потери качества — это, пожалуй, самое сложное и одновременно самое интересное в нашей работе. Мы приветствуем желание каждого влиять на развитие среды, в которую поставляется продукт, поощряем самостоятельность и даём сотруднику возможность предлагать технологии, с которыми он будет работать. Очень ценим тех, кто держит руку на пульсе, всегда в курсе самых последних тенденций и умеет применить их на деле. По сути, сотрудники нашего отдела являются связующим звеном между всеми участниками производства продукта. Когда оказываешься в эпицентре всех работ, можешь на это влиять и знаешь, что твоё мнение всегда учитывается, — это действительно здорово!
Александр Кочкин
Lead DevOps Team
Конечно, у RethinkDB есть свои ограничения, с которыми мы не раз сталкивались, например низкая активность сообщества. Одному нашему коллеге в какой-то момент пришлось стать мейнтейнером существующего драйвера для Go — он развивался не так активно и не обладал функцией, которая требовалась нам для работы с базой данных. Мы приняли решение и переработали часть кода самостоятельно, после чего изменения были переданы сообществу.

Проверяем код на всех уровнях

Кроме unit-тестирования, которое находится в зоне ответственности разработчиков, в процесс производства встроен CI, а инженеры тестирования постоянно поддерживают актуальность кейсов и прорабатывают всевозможные варианты ошибок.
Любая почта, в принципе, сложная система, где нужно учитывать множество факторов. Есть множество кейсов — допустим, письмо не пришло и нужно разобраться почему. Это не всегда быстро и просто — возможно, сообщение сочли спамом или где-то отвалилась сеть, а может, была какая-то другая причина. У нас несколько компонентов, и у каждого свои особенности. Например, в календаре есть рекуррентные события, при тестировании которых случается комбинаторный взрыв, требующий тщательной проработки дизайна тестов. А в объектном хранилище были реализованы графовые тесты для тестирования протоколов репликации и записи. Наша система очень обширна и требует тщательного тестирования. Много времени уходит на изучение, поиск оптимального решения, а иногда и переосмысление существующего подхода. Периодически мы перерабатываем текущие тесты, поскольку любой продукт развивается и со временем меняется. Инженерам AQA нужно непрерывно улучшать знания о сетевых протоколах, о паттернах программирования, о работе в Linux, об алгоритмах и структурах данных. Открывать новые нестандартные аспекты работы высоконагруженной отказоустойчивой системы — это уникальный опыт.
Александр Новичков
Developer / AQA Team Mentor
Микросервисная архитектура позволила безболезненно внедрить тестирование на всех уровнях — от компонентного до системного тестирования. Ежедневно инженеры-тестировщики актуализируют, пополняют базу тест-кейсов в TestRail. Этот инструмент помогает нам вести отчётность и в любой момент понимать уровень качества продукта.
Автоматизация тестирования помогает нам увеличивать оперативность проверки и не допускать код с логическими дефектами на стенды. AQA-инженеры разрабатывают тесты на Python с использованием PyTest и Allure для бэкенд-тестирования. Также мы широко используем ES6 для фронтенд-тестирования. За годы разработки тестов у нас накопилась целая библиотека хелперов, которая помогает решать типовые задачи тестирования в нашей инфраструктуре CI/CD.

Масштабируемся на ходу

За четыре года наш штат вырос в несколько раз, мы поменяли «классический водопад» на SCRUM и ввели команду, которая отвечает за вопросы интеграции компонентов продукта и внутреннее взаимодействие подразделений. Постоянное развитие сотрудников и процессов — это то, что позволяет создавать масштабный продукт.
В ближайшее время мы планируем внедрять технологии искусственного интеллекта в направлениях классификации и структурирования данных, оптимизации хранения и других прикладных задачах. Мы знаем, что пользователи не хотят делать рутинные операции самостоятельно. А ещё понимаем, как применить ИИ для решения оптимизационных задач, что в конечном счёте позволит организациям экономить время и повышать производительность своих сотрудников. Mailion — это лишь первый шаг на пути к новой коммуникационной платформе. Впереди у нас ещё много задач, под которые мы будем расширять текущие команды.
Теги:почтовые системыMailionGoRethinkDBCloud Native
Хабы: Блог компании МойОфис Программирование Анализ и проектирование систем Управление проектами Управление продуктом
+40
15,7k 39
Комментарии 19