Поделитесь своими идеями, мыслями или советом.

Введение

Boomerang — это приложение, похожее на индихакеров, домашняя страница facebook, панель инструментов tumblr, временная шкала twitter или их комбинация.

Функции приложения

  • Пишите посты
  • Комментировать сообщения
  • Голосовать за посты
  • Посмотреть хронологию главной страницы
  • У пользователя есть подписчики и за ним следуют другие пользователи

Факты и цифры

  • 10 миллионов активных пользователей
  • 50К запросов в секунду тратится на чтение
  • На запись тратятся сотни (~500) запросов в секунду.

Пользователи потребляют больше, чем производят. На чтение уходит больше времени, чем на запись.

Обзор архитектуры

1. CDN

CDN будет использоваться для кэширования файлов активов (изображений, CSS и JS).

2. Балансировщик нагрузки (+ еще)

3. Серверы веб-приложений (+ еще)

4. Услуги

Переход к распределенным услугам на основе различных функций, которые у нас есть.

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

5. Очереди заданий (+ еще)

6. Кэширование

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

7. База данных

Реляционная база данных, такая как MySQL, прекрасно работает с сегментированием и репликацией.

8. Облачное хранилище (+ еще)

Часть I — Конвейер чтения

В нашем случае у нас есть 3 основных действия чтения: (1) временная шкала, (2) публикация и комментарии к ней и (3) данные пользователя.

Что здесь?

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

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

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

Отображение профиля пользователя или временной шкалы не требует нескольких перекрестных запросов. Это быстро. Огромное преимущество. Не нужно разбрасываться-собираться, прыгать по разным осколкам. Осколки не взаимодействуют друг с другом. Легко реализовать.

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

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

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

Итак, что происходит, когда пользователь просматривает свою временную шкалу?

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

Временная шкала, хранящаяся в кеше, содержит только идентификаторы сообщений, а не сами сообщения (название, содержание, голоса и т. д.).

Далее…?

Итак, нам нужно получить заголовки постов. Имея список идентификаторов сообщений, перейдите к сегменту пользователя и получите список (последних) заголовков пользовательских сообщений. Обычно посты находятся в кеше. Это еще один кеш перед базой данных; кеш постов.

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

Что делать, если на временной шкале пользователя произошел промах кеша?

Тогда это дисковый хит. Воссоздание таймлайна.

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

Далее нужно получить посты со списком идентификаторов постов, которые мы только что запросили. Если сообщений нет в кеше, то это еще одно попадание в базу данных.

Важно помнить, что в одном сегменте хранятся ВСЕ данные временной шкалы пользователя. Он состоит из постов от подписчиков. Нет необходимости отслеживать список отслеживаемых пользователей.

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

Как мы ищем определенные пользовательские данные в сегменте?

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

Данные могут быть любыми пользовательскими данными, такими как сообщения, комментарии или пользовательские метаданные.

Итак, если вы хотите найти пользователя, чей идентификатор попадает, скажем, в shard003.

Один. Разложите идентификатор на 3 части.

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

Два. Подключитесь к сегменту, перейдите к таблице пользователей (или сообщениям, если тип — сообщения) и используйте локальный идентификатор, чтобы найти пользователя и вернуть данные.

Harley Quinn использует таблицу сопоставления для сопоставления идентификаторов твитов с различными сегментами.

Кажется, есть шанс попасть в базу данных. Есть ли способ избежать этого?

Индексы.

Индексы вокруг идентификаторов в таблицах; идентификатор пользователя, идентификатор сообщения, идентификатор комментария.

Индексы вокруг отношений; идентификатор пользователя для созданного поста или комментария и дата создания сделают запросы намного быстрее. Это можно сделать в таблицах сопоставления в сегменте, о котором мы говорили ранее.

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

Как насчет просмотра содержимого публикации вместе с комментариями к ней?

Он следует почти по тому же пути, что и временная шкала.

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

Если не. Тогда это попадание в базу данных.

Что произойдет, если это попадание в базу данных?

Такой же. Учитывая идентификатор сегмента, тип — сообщения (таблица сообщений) и локальный идентификатор (строка), получите сообщение из базы данных и сохраните его обратно в кеше.

Наконец, пользовательские данные? Профиль пользователя.

Снова. Служба поддержки пользователей…. Вы поняли.

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

Часть II — Написание пайплайна

Ура! А что происходит, когда вы пишете новый пост?

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

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

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

Это преимущество, которое мы получаем от обработки; распространение опубликованных постов на запись, а не на чтение. Таким образом, операции чтения выполняются очень быстро.

Что делать, если у пользователя много подписчиков. Собираемся ли мы перебирать их все?

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

Много дублирования, не так ли?

Верно. Мы жертвуем дублированием ради производительности.

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

Хотя он может храниться и в моем осколке. Это хороший компромисс между производительностью и использованием диска.

Кажется, процесс написания поста занимает много времени.

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

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

Что, если некоторые пользователи сегмента настолько активны, что нарушили баланс между сегментами?

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

Выполнение этого автоматически имеет некоторые сложности; Это может привести к повреждению данных и неправильной балансировке, которую нелегко исправить.

Спасибо за чтение! Если вам понравилось, ставьте 👏 за это.