Сегодня я подготовил для вас еще одно техническое интервью с Pinterest, ребята. В предыдущем уроке я рассмотрел вопрос об алгоритме, который получил во время первого собеседования на экране телефона. После этого собеседования меня пригласили пройти дистанционное собеседование на месте (из-за Covid ..)

Вот письмо с приглашением, которое я получил на удаленное собеседование на месте:

Следует отметить, что, поскольку это удаленное собеседование на месте, они дают вам час на собеседование по проектированию системы, потому что с помощью CoderPad сложнее объяснить ситуацию.

Вопрос на собеседовании по системному дизайну

Вопрос на собеседовании заключался в том, чтобы разработать дизайн системы для новой функции в Pinterest, где пользователи могут следить за пинами или получать обновления от пользователей. Например, предположим, что я следую булавке выше. Каждый раз, когда на этом пине появляется обновление, я должен получать уведомления об этом. Если я подписываюсь на пользователя, я должен получать уведомления, когда он публикует или редактирует пины.

Попробуй сам

Остановитесь здесь и попробуйте разработать систему для этой новой функции и сравните ее с схемой моей системы, представленной ниже! Так вы узнаете гораздо больше !!

Понять проблему и масштаб

Прежде чем погрузиться в дизайн, мы должны полностью понять проблему и ее масштабы, задав соответствующие вопросы интервьюеру.

Функциональные требования:

  • Пользователи должны иметь возможность следить за разными пользователями или пинами.
  • Пользователи должны получать уведомления о пользователях / пинах, на которых они подписаны.

Заинтересованные стороны и пользователи:

  • Для любых пользователей Pinterest.

Понять узор / масштаб

Затем мы должны попытаться понять, с каким объемом запросов / данных мы имеем дело. Вы можете задавать такие вопросы, как:

  • Какое количество пользователей у Pinterest?
  • Сколько запросов мы обрабатываем?
  • Соотношение между операциями чтения и записи?

Если вы провели небольшое исследование перед собеседованием, вы сможете найти приблизительное число.

  • # пользователей: несколько миллионов пользователей.
  • Количество контактов: несколько миллиардов контактов.
  • QPS: предположим, что 1M QPS (некоторое большое разумно большое число).

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

  • Желательный SLA
  • Потребности в безопасности.

Системный дизайн

Мы можем разбить дизайн на несколько составляющих:

  • Подписаться на объект (пользователь или пин-код)
  • Создать уведомление об обновлениях пин-кода
  • Отправить уведомление пользователям
  • Обработка обновления со слишком большим количеством подписчиков (например, 1 миллион подписчиков)

1. Подписаться на объект

В. Главный вопрос здесь - что должно произойти, когда пользователь нажимает кнопку «следовать» на пине или пользователе?

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

Здесь мы используем реляционную базу данных для хранения данных о подписчиках. Интервьюер обязательно спросит вас, почему бы не использовать другие типы баз данных (например, базы данных на основе графиков или документов).

  • Нереляционная база данных (например, MongoDB): она не подходит для хранения взаимосвязей. Это хорошо для хранения однозначных картографических данных, которые не часто меняются.
  • База данных графиков (например, Neo4j): база данных графиков отлично подходит, когда нам нужно иметь дело с высокой степенью взаимосвязи между объектами (например, социальная сеть в Facebook, где мы хотим найти друзей друзей друзей) . Однако в нашем случае мы просто имеем в виду отношения между пользователем и объектом (один ко многим).

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

Вот пример схемы данных для таблицы подписчиков:

Столбец для uuid пользователя и объекта. Другой столбец, чтобы указать, какой это тип объекта (ПИН или ПОЛЬЗОВАТЕЛЬ). Наконец, столбец для отметки времени, когда пользователь начал следить за объектом.

2. Создать уведомление

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

Каждый запрос на создание или редактирование контактов будет выполняться через вызов конечной точки на внутреннем сервере. Внутренний сервер будет сохранять обновление в базе данных (Pinterest использует реляционную базу данных для хранения контактов).

Мы можем создать уведомление либо асинхронно, либо синхронно:

  • Синхронный подход: после сохранения обновления в базе данных внутренний сервер будет явно отправлять уведомление соответствующим подписчикам перед отправкой ответа об успешном выполнении обратно пользователю. Это не идеально, потому что это значительно увеличит задержку операций записи.
  • Асинхронный подход: после сохранения обновления в базе данных внутренний сервер создаст задачу для отправки уведомления и отправит успешный ответ обратно пользователю, не дожидаясь завершения уведомления.

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

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

Затем мы можем создать воркеров, которые подписываются на эту тему, и создавать уведомления всякий раз, когда есть сообщения по этой теме. Перед созданием уведомлений работники должны будут искать в таблице подписчиков, чтобы получить список пользователей, которые следят за обновленными контактами.

3. Отправить уведомление

В. Как мы на самом деле отправляем уведомления пользователям? В начале интервью мне посоветовали относиться к сервису уведомлений как к черному ящику. Но после первоначального обсуждения дизайна мы вернулись и обсудили реализацию и этого.

В такой большой компании, как Pinterest, скорее всего, будет централизованная служба уведомлений.

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

Если не указано иное, мы можем рассматривать наши уведомления как низкоприоритетные и публиковать наше уведомление в очереди с низким приоритетом.

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

В. Как работает пользовательское соединение?

Мобильное / веб-пользовательское устройство может отключать фоновую службу для создания соединения через веб-сокет с одним из наших экземпляров серверной части уведомлений. Мы сохраним эту информацию о подключении в базе данных пары ключ-значение (например, userID - ›machineID).

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

Я рекомендую вам посмотреть видео на YouTube Масштабирование push-сообщений для миллионов устройств @Netflix. Этот человек очень хорошо объясняет сервис уведомлений красивыми слайдами.

4. Обработать ›1 млн подписчиков…

Текущий дизайн хорошо работает, когда количество последователей относительно невелико. Однако давайте рассмотрим случай, когда более 1 миллиона пользователей подписаны, например, на знаменитость. Попытка отправить уведомление более чем 1 миллиону подписчиков просто взорвет систему.

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

Для обновлений со слишком большим количеством подписчиков вместо отправки пакетного уведомления мы можем заставить клиентов (пользователей) периодически вызывать конечную точку (например, syncNotification) (например, каждые 5 минут), чтобы получать обновления по объектам со слишком большим количеством подписчиков. Вам необходимо убедиться, что не все устройства одновременно вызывают эту конечную точку. Чтобы предотвратить такой случай, мы можем рандомизировать период вызова этой конечной точки (например, случайный (0, 5 минут)).

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

Я хотел бы обсудить дальнейшие улучшения или альтернативы. Также я хотел бы услышать, как бы вы это спроектировали.