Обложка статьи «Как Facebook масштабирует архитектуру чата с нагрузкой в миллиарды сообщений в день»

Как Facebook масштабирует архитектуру чата с нагрузкой в миллиарды сообщений в день

Перевод статьи «Facebook Real-time Chat Architecture Scaling With Over Multi-Billion Messages Daily»

Как всё начиналось

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

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

Почему бы не использовать сторонние решения?

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

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

Архитектура и стек технологий чата в реальном времени

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

  • пользовательский интерфейс;
  • веб-узел;
  • модуль определения пользовательского присутствия;
  • кластер каналов;
  • журналирование чата.

Пользовательский интерфейс

Написан на JavaScript с применением PHP для серверного рендеринга.
Длительные сессии подключения между клиентом и сервером настроены с помощью AJAX. От Flash отказались по двум причинам: во-первых, требовалось просить пользователей установить соответствующий плагин, тем самым делая его менее удобным, во-вторых, Flash небезопасен.

Поток сообщений представляет собой смесь технологий pull и push. Сначала клиент отправляет pull-запрос на получение существующих сообщений, в то же время подписываясь на дельта-обновления, которые в свою очередь основаны на технологии push. Как только пользователь подписывается на обновления, Facebook начинает отправлять их клиенту каждый раз, когда они появляются.

Бэкенд

Используется PHP, веб-запросы обрабатываются в чистом виде. Отвечает за аутентификацию пользователей, настройки приватности пользователей, историю чата, обновления, получаемые от друзей, и за другие функции платформы.

Модуль определения пользовательского присутствия

Предоставляет информацию о доступности друзей и/или соединений в онлайн-режиме. Написан на C++ и является наиболее нагруженной частью системы (из-за запросов «вопрос-ответ»).

Модуль собирает информацию об онлайн-пользователях и отправляет её клиенту по запросу.

Кластер каналов

Серверы каналов отвечают за очередь сообщений и доставку. Функциональность написана на Erlang.

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

Серверы кластера каналов используют библиотеку Mochi Web. Она служит для построения лёгких HTTP-серверов. Сообщения пользователей выстраиваются в очередь на серверах кластера каналов. Каждому сообщению присваивается порядковый номер для установления синхронной связи между любыми двумя и более пользователями.

Журналирование чата

Регистрация метаданных чата и другой информации производится через журналирование сообщений. Функциональность написана на C++ и записывает данные между загрузками пользовательского интерфейса страниц.

Масштабируемость и развёртывание сервиса

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

Все модули бэкенда слабо связаны, как показано на изображении. Они общаются между собой через Thrift.

Thrift — протокол связи, облегчающий коммуникацию между службами, работающими на разнородных технологиях. Это разработанный в Facebook фреймворк для сериализации и RPC (Remote Procedure Call), который обеспечивает общение между сервисами. Он помогает организовать слаженную работу систем, написанных на C++, Erlang, PHP и JavaScript.

Самая ресурсоёмкая операция

Больше всего ресурсов уходит на информирование пользователей об онлайн-статусе их друзей. Это важно, так как чаще всего человек начинает разговор только тогда, когда видит, что его собеседник подключен к сети. Изначально рассматривали вариант отправлять пользователям уведомления о том, что их друзья в сети. Но такое было бы крайне сложно масштабировать, учитывая количество пользователей платформы. Эта операция имеет наихудшую сложность O (среднее количество друзей пользователя * количество пользователей онлайн в час-пик * частоту ухода пользователей в оффлайн и время повторного соединения) сообщений в секунду.

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

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

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

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

Синхронизация сообщений и хранилищ данных

Для управления синхронной связью, как было сказано ранее, служит присвоение порядковых номеров сообщениям. Кроме того, в Facebook создали протокол синхронизации Messenger Sync Protocol, который сократил использование немедийных данных на 40 %. Перегруженность сети, как следствие, уменьшилась.

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

 

Последние сообщения отправляются из памяти Iris, а старые беседы извлекаются из обычного хранилища. Iris спроектирован на основе MySQL и Flash-памяти.
Изначально в качестве хранилища мессенджера Facebook использовалась Hbase, но позже оно мигрировало в MyRocks. Это открытый проект базы данных, написанный в Facebook, в котором применяется RocksDB в качестве движка MySQL для хранения данных.

Не смешно? А здесь смешно: @ithumor