В статье описан подход к построению высоконагруженных распределенных систем, который может быть полезен как reference при подготовке к интервью в FAANG по system design.

Обо мне

Software Engineer с опытом около 7 лет. Успел поработать в стартапах и крупных компаниях. Начинал с разработки прошивок для микроконтроллеров, а сейчас занимаюсь написанием высоконагруженных сервисов. На данный момент работаю в компании Yandex, где мы с командой строим Доставку для вас.

System design. Реальный проект vs Интервью

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

Note: Скоуп - это функциональные и нефункциональные требования; Ограничения - это то, что не будет реализовано в рамках проекта. Функциональные требования описывают поведение приложения, которые ожидает бизнес (expected result). К нефункциональным относятся технические ограничения системы (какую нагрузку оно должно держать, его доступность и прочее.

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

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

  • Сбор требований (3-4 минуты)

  • Оценка нагрузки (3-4 минуты)

  • Высокоуровневый дизайн (10 минут)

  • Компонентный дизайн (15 минут)

  • Повышение отзывчивости и отказоустойчивости (5 минут)

  • Мониторинг и алертинг (2-3 минуты)

  • Безопасность (1 минута)

Сбор требований

Для начала нужно определиться с тем, что мы собираемся реализовать в рамках проекта (scope): а именно функциональные и нефункциональные требования; и что оставляем за скобками (out of scope). Выделите пару-тройку основных фичей, которые отличают это приложение от остальных. На их основе стоит накидать черновик API, который поможет во время оценки нагрузки. 

Note: На интервью не стоит тратить много времени на сбор требований. Но на реальном проекте это один из важнейших этапов.

Оценка нагрузки

Определите, чем нагружено ваше приложение: вычислениями (compute intensive), данными (data intensive) или сетью (network intensive). Это и есть bottleneck сервиса, уделите ему наибольшее внимание при вычислениях.

Например, если стоит задача спроектировать сервис вроде Доставки, то можно рассуждать так:

  1. Сервис будет выполнять работу: создание заказа на доставку, поиск исполнителя (курьера), просмотр и трекинг заказа, оплата.

  2. Тогда у него будет 4 вида пользователей: отправитель, получатель, курьер и администратор. 

    1. Отправители создают заявки, получатели их трекают, а курьеры в основном принимают и перевозят заказ.

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

  3. Основная нагрузка идет на storage и network, потому что:

    1. заявки нужно хранить длительный период (storage),

    2. выполнение заказов нужно трекать (network).

  4. Из этого следует, что в перспективе 5 лет стоит подумать о таких параметрах, как:

    1. Daily active users (DAU) && Monthly active users (MAU).

    2. Read/Write баланс.

    3. Network (трафик, connections, rps).

    4. Storage (RAM, ssd/hard disks).

    5. Стоимость создания инфраструктуры и ее поддержки (опционально).

Посчитав все это, вы сможете понять: будет ли приложение держать нагрузку, грубо говоря, на одной машинке, либо же понадобится кластер, распределенный на несколько ДЦ, чтобы удовлетворять требованиям отказоустойчивости (fault tolerance), низкой задержки (low latency) и консистентности данных (обычно eventual consistency).

Высокоуровневый дизайн

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

  1. Вспомнить про оговоренные функциональные требования.

  2. На основе их выделить основные сервисы/компоненты системы.

  3. Определиться с основной БД (обычно выбор стоит между SQL и NoSQL).

Note: Представьте, будто вы разрабатываете систему, которая будет жить на одной машинке. Это позволит вам не думать о масштабировании преждевременно. 

Далее в примерах будут использоваться следующие обозначения:

Пример высокоуровнего дизайна

Компонентный дизайн

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

Пример детализации компонента Search UI

Повышение отзывчивости и отказоустойчивости

Теперь настал тот момент, когда стоит задуматься об отзывчивости и отказоустойчивости. Исходя из требований к системе какие-то сервисы (компоненты) будут более высоконагруженными, какие-то менее, поэтому нужно подумать про:

  • масштабирование,

  • балансировку нагрузки,

  • кэширование горячих данных (чаще всего используются),

  • ограничение нагрузки (rate limiters),

  • шардирование и репликацию данных,

  • шину данных (брокеры сообщений).

Пример отказоустойчивого компонента Search UI

Мониторинг и алертинг

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

Продуктовые метрики специфичны для каждого продукта. Пример: кол-во созданных заказов, MAU, DAU. 

Из технических метрик часто мониторят тайминги и rps ендпоинтов, ресурсы машинки (cpu wait, кол-во свободных потоков, память), ресурсы БД (время выполнения запросов, кол-во соединений к базе, лаг репликации), network (кол-во открытых соединений, пропускной  канал).

Пример мониторинга в Grafana

Безопасность

Если осталось еще немного времени, то можно коснуться темы безопасности системы. Какие могут осуществляться типы атак/фродов и каким образом мы можем от них защититься. Достаточно упомянуть использование сторонних сервисов (напр. CloudFlare).

Заключение

В данной статье я постарался систематизировать и дать в общем виде подход к решению задач по построению высоконагруженных распределенных систем. Этот план хорошо подходит при прохождении system design интервью.

В следующих статьях разберем конкретные примеры и более детально обсудим их построение. Напишите в комментариях, какие системы Вам хотелось бы рассмотреть. Спасибо!

Полезные ссылки

Пример качественного интервью по system design
Библия для тех, кто хочет научиться разрабатывать высоконагруженные распределенные системы
Книжный клуб Tinkoff
Доклад с Highload про построение Экспресс Доставки в Яндексе
Проходим L6 интервью на system design в FAANG
Архитектурные секции собеседования в Яндексе
Общие принципы прохождения system design интервью

Комментарии (1)


  1. funca
    10.07.2023 14:24

    Безопасность (1 минута)

    На скриншоте Льва Толстого, тонко). Только при чем здесь FAANG?