Привет, Хабр! Меня зовут Антон Герасимов, я руковожу департаментом разработки в московском центре компании МойОфис. Почти четыре года мы с командой создаём новую высоконагруженную и отказоустойчивую почтовую систему Mailion. Она предназначена для корпоративных коммуникаций и построена на Cloud Native микросервисной архитектуре. В этой статье я расскажу, как мы создавали продукт с момента замысла до текущей бета-версии, как затачивали почтовый движок под работу с контентом и как справлялись с вызовом — поддержать совместную работу даже 1 000 000 пользователей и масштабироваться на такое количество рабочих мест.
Чего не хватает почтовым сервисам?
Вы задумывались, почему в большинстве почтовых систем сделать операцию, отличную от базовой, — это нетривиальная задача? Нужно залезть в неочевидное место и там найти нужный пункт, а настройка совместного доступа обычно требует сертифицированного специалиста. Так быть не должно, но таких примеров масса.
С конца 80-х годов в области совместной работы с электронной почтой мало что менялось. Конечно, появились новые функции и клиентские протоколы, но ничего принципиально иного разработчики почтовых систем не предложили. В решениях, которые появились за это время, уделялось мало внимания деталям — простым пользовательским вещам, которые делают жизнь намного удобнее и экономят время пользователей. Это не так заметно при домашнем использовании, но для организаций с большим количеством сотрудников уже становится ощутимым.
В 2014 году компания Google попыталась сделать революционный шаг и запустила Inbox, который был построен не по принципу папок, а по принципу тегов. В основе сервиса лежала концепция сканирования входящих сообщений, их группировка по темам и автоматическим обогащением недостающей дополнительной информации.
Сервис предлагал и ряд корпоративных функций: календарь событий организации, сохранение ссылок для дальнейшей работы с ними, функцию задержки отправки писем, а также «умные ответы», которые значительно ускоряли коммуникацию с мобильных устройств. Спустя четыре года проект закрыли. Я тогда был очень расстроен, а 11 000 человек даже петицию подписали, что говорит о реальной потребности пользователей.
Внимательно проанализировав эту ситуацию, мы поняли, что Inbox просто опередил своё время. Людям, особенно в корпоративном мире, нужен простой и понятный интерфейс для решения типовых задач с возможностью быстрого доступа ко всем элементам деловой переписки — вложениям, ссылкам, различным отчётам и функциям, — который будет интуитивно понятным и одновременно функциональным, не вызывающим вопросов. А корпорациям необходимо обеспечить технологии одновременной работы сотен тысяч пользователей, высокие показатели по отказоустойчивости, а также встроенные механизмы самостоятельного восстановления системы.
Чтобы сделать корпоративную почту удобной как для пользователя, так и для администратора, с самого начала работы над Mailion мы провели множество фокус-групп и опросов. Они помогли нам выявить типовые сценарии использования корпоративной почты и составить перечень востребованных функций, а также спроектировать систему календарного планирования и дизайн интерфейсов.
Фокусируемся на совместной работе с данными
![](https://habrastorage.org/getpro/tmtm/articles/tld/images/14351887/tild3638-3137-4431-b365-643131623231__1.png)
Изначально мы ориентировались на компании, где в совместной работе участвуют десятки или сотни тысяч активных пользователей. И мы разрабатывали не сервис, а продукт, который устанавливается на серверах, в частном облаке клиента, что связано с требованиями безопасности в корпорациях. Это существенно повлияло на ключевые требования к архитектуре:
- экономическая эффективность решения;
- производительность, необходимая для работы с большим количеством пользователей;
- масштабируемость и изоляция компонентов.
Мы сразу сделали акцент на коллаборацию и решили не просто хранить сообщения, вложения и события календаря в почтовой системе, а ещё и оптимизировать их для одновременной работы сотен тысяч пользователей.
Обмен сообщениями происходит в любой организации. В среднем количество адресатов в одном сообщении — от двух до шести в зависимости от компании, и всё это копии. Файлы нужно хранить одним способом, почтовые сообщения — другим, и всем им требуется дедупликация данных. Не стоит забывать, что взаимодействие порождает большое количество операций ввода-вывода, которые существенно влияют на время отклика и в целом недёшевы.
Чтобы реализовать эти контент-зависимости и оптимизировать операции ввода и вывода именно для взаимодействия пользователей, мы разработали движок, который оперирует любыми сущностями как объектами, обеспечивая совместный доступ и контроль прав. И делает это всё над предметами, которые имеют разную природу. Например, у календарного события и почтового сообщения разные жизненные циклы, но обитают все они, по сути, в одной системе.
Мы разработали специализированное хранилище, которое снижает объём физического пространства, занимаемого данными, — тем самым эффективность операций ввода-вывода над «горячими» данными повышается.
Делаем реактивный бэкенд на Go
![реактивный бэкенд на Go](https://habrastorage.org/getpro/tmtm/articles/tld/images/14351887/tild3161-3838-4431-a138-323137396464__2.png)
Так как мы делаем продукт, который развёртывается на инфраструктуре клиента, то нам было важно предоставить инженерам возможность быстро, просто и удобно проводить эти действия, а также оперативно его обновлять. Для этого мы с самого начала выбрали микросервисную архитектуру по модели Cloud Native. Она предполагает разработку изолированных микросервисов, которые упаковываются в контейнеры и управляются через облако. Таким образом, у нас появляются персистентные хранилища и вокруг них работают сервисы, связанные между собой протоколом gRPC и обеспечивающие функциональность всей системы.
Для разработчиков Golang у нас есть разные задачи: от участия в создании архитектуры до оптимизации существующего кода и реализации новых фич / сервисов. В требованиях к системе, например, есть отказоустойчивость и самовосстанавливаемость. Это обусловлено тем, что мы создаем on-premise-решение, которое устанавливается у клиента, и с большой долей вероятности у нас не будет к нему доступа. Поэтому надо тщательно продумывать, как сделать так, чтобы в случае отказа система сама смогла быстро восстановиться. Наша команда проектирует сервис с нуля, поэтому нужно быть готовым к высокому уровню ответственности. Для нас важны знания кандидата о структурах данных и алгоритмах, опыт асинхронного программирования распределённых систем и работы в Linux-среде. Во время работы над продуктом можно существенно прокачать свои навыки и семимильными шагами вырасти как специалист, если человек, конечно, в этом заинтересован.
Алексей Бондаренко
Lead Calendar Team
В качестве серверного языка мы однозначно выбрали Go, на котором сейчас написано 98 % кода микросервисов. У него высокая производительность для решения наших задач, это позволяет быстро, в отличие от других языков, разрабатывать функциональность. У меня был опыт написания почтовых решений на других языках программирования, и по соотношению производительность / скорость разработки Go показал себя очень хорошо.
С самого начала разработки мы придерживаемся принципов, заложенных в архитектуру API First: все сервисы и клиенты используют для взаимодействия единый контракт на API. Мы очень любим кодогенерацию. Такой подход позволяет синхронизировать разработку интерфейсов между сервисами и их потребителями, в том числе фронтенд-командой, а также всегда иметь актуальную документацию ко всем компонентам.
Выбираем Polymer, а затем меняем подход на работу с нативными веб-компонентами
![](https://habrastorage.org/getpro/tmtm/articles/tld/images/14351887/tild3939-3634-4737-b564-396433363965__3.png)
В качестве фронтенд-фреймворка мы выбрали Polymer. Когда Google его анонсировал, казалось, что он будет активно его продвигать в качестве стандарта. В итоге многие вещи из Polymer действительно вошли в стандарт и стали нативно поддерживаться браузерами. Мы выбрали это направление, но в какой-то момент Google приостановил развитие Polymer и сфокусировался на развитии веб-компонентов в консорциуме с производителями других браузеров. Мы в это время тоже скорректировали свой подход к использованию Polymer и сейчас в большей части компонентов уменьшаем зависимость от фреймворка, что в будущем позволит более гибко использовать подобные инструменты.
Практически каждый, даже самый простой на первый взгляд компонент интерфейса может менять поведение и внешний вид в зависимости от контекста, в котором он используется. Адаптивность почты представляет собой не только использование медиазапросов для описания стилевых свойств компонентов в зависимости от размеров экрана, но и расчёт максимальных и минимальных значений ширин структурных блоков лэйаута, определение блоков, которые должны быть показаны и скрыты. Нужно учитывать, что пользователь за секунды может передумать и выполнить совершенно противоречивые действия, которые система должна корректно обработать. Мы выжимаем из современных технологий всё, что можно применить при создании инновационного продукта. И поскольку мы участвуем не только в разработке компонентов, но и в их тестировании, фронтенд-разработчику важно уметь взаимодействовать с другими командами и постоянно учиться новому. У вас есть все шансы поработать над созданием высоконагруженного продукта в компании сильных специалистов.
Дмитрий Зайцев
Lead Frontend Team
Специально для Mailion мы создали новую дизайн-систему и на её базе построили UI-Kit. Так как мы применяем компонентный подход, то разрабатываем базовые блоки, из которых уже строим всё приложение. И это достаточно большая и необычная задача, которая усложняется тем, что наше приложение оперирует очень большим объёмом данных. Задача по созданию функционального, быстрого и современного интерфейса потребовала немалой ловкости наших фронтенд-мастеров.
Ищем zero-maintenance базу данных
![zero-maintenance база данных](https://habrastorage.org/getpro/tmtm/articles/tld/images/14351887/tild6633-3834-4236-b031-613234323432__4.png)
Наш продукт должен иметь возможность эксплуатироваться в условиях, где может не быть экспертов в управлении сложными кластерными системами. Из-за этого нам нужно было снизить сложности при масштабировании и управлении базой данных, поэтому одним из требований было 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 — это лишь первый шаг на пути к новой коммуникационной платформе. Впереди у нас ещё много задач, под которые мы будем расширять текущие команды.