Stream Highlights - это самодействующий генератор клипов, основанный на данных IRC-чата Twitch в реальном времени.

Я разработал этот проект, руководствуясь тремя ключевыми принципами:

  • Надежность
  • Масштабируемость
  • Отказоустойчивость

Наличие надежной системы при сохранении отказоустойчивости может показаться нелогичным. Я верю, что, применяя строгое разделение проблем, переплетенных без единой точки отказа, мое приложение будет гарантировать его безотказную работу.

Ниже представлена ​​общая архитектурная картина.

Эта архитектура разделена на две части:

  • Веб-приложение, состоящее из сервера рендеринга, веб-API и базы данных на основе документов.
  • Система обнаружения, состоящая из сервисов узлов, базы данных временных рядов и системы потокового движка.

Мы начнем с веб-приложения, где рассмотрим архитектуру, ее плюсы и минусы, а затем рассмотрим ее потенциальную масштабируемость.

Вторая часть будет следовать тому же плану с упором на систему обнаружения.

I - Веб-платформа

Платформа состоит из трех частей: сервера рендеринга, веб-API и базы данных на основе документов.

Сервер рендеринга - это объект, ответственный за получение клиентских запросов, их проксирование в API, если это необходимо, и создание правильных ресурсов для клиента. С технологической точки зрения он использует Node, Express, Server Side React и Redux.

Веб-API (названный Stream Highlights API) - это простой Express API, использующий mongoose для извлечения данных, содержащихся в нашей базе данных MongoDB. MongoDB - это наш постоянный уровень, отвечающий за агрегирование всех наших данных.

a - Отделение сервера рендеринга от API

При разработке приложения я следовал веб-стандарту, однако у него есть две особенности: автономный сервер рендеринга (использующий рендеринг на стороне сервера React), который передает запросы к API. Давайте посмотрим на эти две архитектуры.

Первым делом, чтобы сделать наше приложение масштабируемым, было отделить сервер рендеринга от веб-API. Этот выбор был сделан для того, чтобы мы могли распределять ресурсы на лету в зависимости от спроса. В основном это выбор масштабируемости.

Учитывая значительную нагрузку на наше приложение, если мы заметим, что сервер рендеринга становится медленнее, мы можем выделить больше ресурсов, не ослабляя и без того быстрый веб-API. То же самое и с API, если мы обнаружим, что это узкое место в нашем потоке.

b - Архитектура прокси и без прокси

Второй момент, который я хочу затронуть, - это использование прокси для перенаправления пользовательских запросов к API через сервер рендеринга. Давайте посмотрим на эти две архитектуры.

Архитектура прокси - это та, которую мы используем прямо сейчас. Когда пользователь делает запрос к API (на стороне клиента), запрос фактически передается API через сервер рендеринга. Клиент напрямую не связывается с API.

Для архитектуры без прокси сервер рендеринга связывается с API при первом запросе. На стороне клиента приложение напрямую связывается с API.

Я решил использовать прокси-архитектуру в основном из соображений масштабируемости приложения. Архитектура без прокси вполне допустима; и наша платформа будет работать с ним точно так же. Однако я хотел убедиться, что платформа может легко масштабироваться до аутентификации пользователя.

Аутентификация пользователя позволит создавать учетные записи, поддерживать профиль, управлять избранным и так далее. Следовательно, доступ к защищенным ресурсам в API должен иметь только один пользователь. Пользователь перейдет к полной аутентификации, скорее всего, с помощью файлов cookie. Вот где у нас есть узкое место.

Если наш пользователь делает прямые запросы к API на стороне клиента, он будет аутентифицирован и ему будет доставлен файл cookie для его сеанса. Файл cookie будет отправляться в API при каждом последующем запросе к API. Если пользователь запрашивает защищенный маршрут на сервере, cookie не будет передан на сервер визуализации. Вот где у нас проблема. Даже если пользователь прошел аутентификацию через API, ему будет отказано в защищенных ресурсах, если он сделает запрос через сервер рендеринга.

Это причина, по которой мы используем прокси-архитектуру: чтобы обмануть пользователя, заставив его поверить в то, что он использует сервер рендеринга для аутентификации, но под капотом это не совсем так.

II - Представления

Давайте посмотрим на общую производительность архитектуры. Вот изображение всех сетевых запросов, выполненных при доступе к Stream Highlights.

Я обвел красным цветом время до первого байта приложения, которое составляет около 350 мс. Время взаимодействия намного больше, учитывая тот факт, что приложение повторно отображается на стороне клиента при получении пакета. Давайте посмотрим на запросы API на стороне клиента.

В диапазоне от 25 до 700 мс API работает довольно быстро.

III - Оптимизация

Архитектуру всегда можно улучшить в зависимости от потребностей и узких мест, с которыми она сталкивается. Что касается нашей архитектуры, на ум приходят два момента: использование кеширования и оптимизация пакетов.

Если мы сталкиваемся с все большим количеством запросов к нашему API, мы могли бы использовать систему кэширования, чтобы гарантировать, что все запросы фактически извлекаются не из API, а из кэширующей базы данных, такой как Redis. Архитектура будет выглядеть так.

При первом запросе сервер рендеринга будет передавать запрос API, но данные будут сохраняться в Redis для последующих запросов. TTFB, а также TTFI сильно упадут, поскольку данные в основном будут извлекаться из кэширующей базы данных.

Вторая оптимизация будет заключаться в использовании кеширования браузера, а также в уменьшении размера ресурсов, которые мы доставляем клиенту. Такие улучшения в основном стали возможными с помощью Webpack и передовых методов, таких как разделение кода и отложенная загрузка модуля.

IV - Резюме

В этой первой части основное внимание уделялось архитектуре веб-приложения и двум ее основным компонентам: отделению сервера визуализации от API и проксированию запросов через сервер визуализации. Мы проверили производительность нашей архитектуры и увидели, какие оптимизации можно применить к ней.

Перейдите ко второй части, чтобы ознакомиться с архитектурой обработки данных!