В Roblox рассказали подробности технического сбоя, который длился с 28 по 31 октября 2021 года. В этот период игровая онлайн-платформа была недоступна для пользователей. Длительное время исправления неполадок было обусловлено сложностями диагностики, сообщил генеральный директор компании Дэвид Башуки. Сбой вызвали две проблемы: включение новой функции потоковой передачи в Consul при необычно высокой нагрузке чтения и записи, а также производительность в BoltDB. Система BoltDB с открытым исходным кодом используется в Consul для управления журналами. Именно проблемы с диагностикой этих двух в основном не связанных между собой проблем, скрытых глубоко в реализации Consul, объясняют длительность сбоя, заявили в Roblox. Системы мониторинга, которые обеспечили бы лучшее понимание причины сбоя, полагались на затронутые системы, такие как Consul.  Основная инфраструктура Roblox работает в собственных центрах обработки данных. Они насчитывают более 18 000 серверов и 170 000 контейнеров. Чтобы запустить тысячи серверов на нескольких сайтах, используется пакет технологий компании HashiStack. Оркестратор Nomad используется для управления контейнерами совместно с решениями Consul и Vault. Nomad используется для планирования работы. Он решает, какие контейнеры будут работать, на каких узлах и на каких портах они доступны, а также проверяет работоспособность контейнера. Consul используется для обнаружения сервисов, проверки работоспособности и блокировки сессий.   За несколько месяцев до октябрьского инцидента Roblox обновился с Consul 1.9 до Consul 1.10, чтобы воспользоваться новой функцией потоковой передачи. Она предназначена для значительного снижения нагрузки на сеть и процессор, необходимой для распространения обновлений по крупномасштабным кластерам, таким как в Roblox. Во второй половине дня 28 октября производительность Vault снизилась, а на одном из серверов Consul возникла высокая загрузка ЦП. Первое расследование показало, что кластер Consul, от которого зависят Vault и многие другие службы, стал работать хуже: медианная задержка записи, обычно не выходившая за 300 мс, теперь достигла 2 секунд. Для масштаба Roblox проблемы с оборудованием — обыденность, и Consul может пережить аппаратный сбой. Однако, если аппаратное обеспечение просто работает медленно, а не дает сбоев, это может повлиять на общую производительность Consul. В этом случае команда подозревала снижение производительности оборудования в качестве основной причины и начала процесс замены одного из узлов кластера Consul. Даже с новым оборудованием производительность кластера продолжала падать. Учитывая серьезность инцидента, команда решила заменить все узлы в кластере Consul. Эти новые машины имели 128 ядер (увеличение в 2 раза) и новые, более быстрые твердотельные накопители с интерфейсом подключения NVMe. Но кластер по-прежнему не восстановил номинальную работу: медианная задержка записи всё так же находилась в районе 2 секунд вместо обычного показателя 300 мс или ниже. Тогда команда решила выключить весь кластер Consul и сбросить его состояние с восстановлением из снэпшота возрастом в несколько часов, то есть до начала отключения. Команда Roblox понимала, что в этом случае возникла бы незначительная потеря данных системы (но не пользовательских). Однако серьёзность ситуации и уверенность в способности написать нужные конфигурации самостоятельно перевесила риски.   Несмотря на то, что на тот момент через систему Roblox не проходил генерируемый пользователями трафик, внутренние службы все еще работали и исправно обращались к Consul. Эти операции чтения и записи создавали значительную нагрузку на кластер. Тогда инженеры настроили iptables в кластере для блокировки доступа, чтобы восстановить его контролируемым образом. Сброс прошел гладко, и изначально показатели выглядели хорошо. Однако производительность Consul снова начала падать. Медианное время записи данных опять ушло в 2 секунды. Зависящие от Consul службы одна за другой объявляли себя «unhealthy». В конце концов система вернулась в изначальное проблемное состояние. С начала инцидента прошло 14 часов, и поиски проблемы продолжались.   Компания исключила отказ оборудования и предположила, что кластер вернулся в неработоспособное состояние из-за тысяч контейнеров, пытающихся переподключиться. Команда инженеров решила сократить использование Consul, а затем систематически восстанавливать его, параллельно заблокировав внешний трафик. Они собрали список сервисов, которые используют кластер, и внесли изменения в конфигурацию, чтобы отключить все случаи несущественного использования. Этот процесс занял несколько часов из-за большого разнообразия целевых систем и типов изменений конфигурации. В итоге число запущенных экземпляров сервисов Roblox снизили с сотен до единиц. Но и это не помогло восстановить работоспособность Consul. В течение следующих 10 часов команда инженеров изучала журналы отладки и метрики на уровне операционной системы. Эти данные показали, что записи Consul KV блокируются в течение длительного периода времени. Причина конфликта не была сразу очевидна, но одна из теорий заключалась в том, что переход с серверов с 64-ядерными процессорами на 128-ядерные в начале сбоя мог усугубить проблему. Изучив данные htop и данные отладки производительности, показанные на снимках экрана ниже, команда пришла к выводу, что стоит вернуться к 64-ядерным серверам, аналогичным тем, которые использовались до сбоя. Команда перевела кластер Consul обратно на серверы с 64 ядрами ЦП, но это изменение не помогло. Истинная причина сбоя была заложена в систему задолго до него. За несколько месяцев до неполадок инженеры включили новую функцию потоковой передачи Consul в части сервисов. Эта функция, предназначенная для снижения использования ЦП и пропускной способности сети кластера Consul, работала успешно, и поэтапно ее включили в большее количество серверных служб.  27 октября, за день до сбоя, функция заработала на бэкенд-сервисе, отвечающем за маршрутизацию трафика. В рамках этого развертывания, чтобы подготовиться к увеличению трафика, также увеличили количество узлов, поддерживающих маршрутизацию трафика, на 50%. Система хорошо работала с потоковой передачей на этом уровне за день до начала инцидента, поэтому изначально было неясно, почему ее производительность изменилась.  Однако, проанализировав отчеты о производительности и флейм-графы с серверов Consul, инженеры получили доказательства того, что пути потоковой передачи ответственны за конфликт, вызывающий высокую загрузку ЦП. И они отключили функцию потоковой передачи для всех систем Consul, включая узлы маршрутизации трафика. Именно это позволило восстановить работу Consul. Команда HashiCorp объяснила, что, хотя потоковая передача в целом была более эффективной, она использовала меньше элементов управления параллелизмом. При очень высокой нагрузке — и чтения, и записи — архитектура потоковой передачи усугубляет количество конфликтов на одном канале, что вызывает блокировку во время записи и делает канал значительно менее эффективным.  Однако и после восстановления некоторые сервисы в Consul демонстрировали те же проблемы с задержкой, которые наблюдались до отключения потоковой передачи. Первопричину инженеры HashiCorp нашли уже после восстановления работы. Через несколько дней они указали, что Consul использует популярную библиотеку с открытым исходным кодом под названием BoltDB для хранения журналов Raft. Она не используется для хранения текущего состояния в Consul, а скорее для непрерывного журнала применяемых операций. Чтобы предотвратить бесконечный рост BoltDB, Consul регулярно делает снэпшоты. Операция моментального снимка записывает текущее состояние Consul на диск, а затем удаляет самые старые записи журнала из BoltDB. Однако благодаря структуре BoltDB даже при удалении самых старых записей журнала пространство, которое BoltDB использует на диске, не сокращается. Вместо этого все страницы (сегменты по 4 КБ в файле), которые использовались для хранения удаленных данных, помечаются как «свободные» и повторно используются для последующих операций записи. BoltDB отслеживает эти свободные страницы в структуре, называемой «свободным списком». Как правило, на задержку записи существенно не влияет время, необходимое для обновления списка страниц, но рабочая нагрузка Roblox выявила патологическую проблему с производительностью в BoltDB, из-за которой его обслуживание было чрезвычайно долгим. Спустя 54 часа после начала инцидента кластер Consul уже работал, а команда Roblox готовилась к восстановлению нормальной работы. Roblox использует типичный шаблон микросервисов для своего бэкэнда. В нижней части «стека» микросервисов находятся базы данных и кэши. Эти базы данных не пострадали от сбоя, но система кэширования, которая регулярно обрабатывает 1 миллиард запросов в секунду на нескольких уровнях во время обычной работы системы, была неработоспособной. Поскольку кэши хранят временные данные, которые можно легко повторно заполнить базами данных, самым простым способом вернуть систему кэширования в работоспособное состояние было ее повторное развертывание. Процесс повторного развертывания кэша столкнулся с рядом проблем: вероятно, из-за восстановления кластера Consul из снэпшота, который был выполнен ранее, внутренние данные планирования, которые кэш-система хранит в Consul KV, были неверными; развертывание небольших кэшей занимало больше времени, чем ожидалось, а развертывание больших кэшей не завершалось. Оказалось, причиной стал неработоспособный узел.  Инструмент автоматического развертывания системы кэширования был создан для поддержки поэтапных корректировок крупномасштабных развертываний, которые уже обрабатывали трафик в масштабе, а не для итерационных попыток загрузить большой кластер с нуля. Команда начала работать над выявлением и устранением этих проблем, обеспечением правильного развертывания системы кэширования и проверкой ее работы.  Окончательный этап возвращения систем в строй начался 31 октября. Как и в случае с системой кэширования, значительная часть запущенных служб была отключена на этапах устранения неполадок. Команде необходимо было перезапустить эти службы с правильными уровнями мощности и убедиться, что они работают. Чтобы избежать флуда, инженеры использовали управление DNS для регулирования количеством игроков, которые могли получить доступ к Roblox. Это позволило допустить на платформу определенный процент случайно выбранных игроков, в то время как другие продолжали перенаправляться на статическую страницу обслуживания. Каждый раз инженеры проверяли загрузку базы данных, производительность кэша и общую стабильность системы. Работа продолжалась в течение дня, доступ поэтапно увеличивали на 10%. Спустя 73 часа он был предоставлен 100% игроков, и Roblox полностью заработал. Roblox и HashiCorp уже после сбоя выявили и изолировали конкретные проблемы с конфликтами в новом протоколе потоковой передачи. Теперь команда создает новые тесты для воспроизведения конкретной проблемы и работает над улучшением архитектуры системы потоковой передачи, чтобы избежать конфликтов при экстремальной нагрузке и обеспечить стабильную работу в таких условиях. Инженеры также разобрались во внутренней работе BoltDB. Из-за особого шаблона использования, созданного во время инцидента, операции записи 16 КБ вместо этого стали намного больше. В рассматриваемом хранилище журналов объемом 4,2 ГБ хранилось только 489 МБ фактических данных, а 3,8 ГБ — это «пустое» место. Это означает, что при каждом добавлении журнала новая свободная страница размером 7,8 МБ также записывалась на диск, хотя фактически добавляемые необработанные данные весили 16 КБ или меньше. Это переполняло буферы TCP и способствовало увеличению времени записи до 2-3 секунд.  HashiCorp и Roblox разработали и развернули процесс с использованием существующих инструментов BoltDB для «сжатия» базы данных, что решило проблемы с производительностью. Также они расширили системы телеметрии, чтобы лучше отслеживать производительность Consul и BoltDB и отслеживать схемы трафика между сервисами Roblox и Consul. Запуск всех серверных служб Roblox в одном кластере Consul также стал причиной столь масштабного сбоя. Платформа уже работает над дополнительным центром обработки данных, в котором будут размещаться ее серверные службы. Также Roblox сотрудничает с HashiCorp, чтобы развернуть новую версию Consul. Она заменит BoltDB преемником под названием bbolt. Обновление тестируется и будет завершено в первом квартале 2022 года. В ноябре сервис по отслеживанию данных Roblox зарегистрировал 6 млн пользователей, которые находились онлайн одновременно, что стало рекордом для площадки с момента ее запуска. Компания обслуживает более 40 млн пользователей ежедневно. Рыночная стоимость Roblox превышает $44 млрд.  Информационная служба Хабра