Прим. перев.: в начале августа Red Hat публично рассказала о решении проблем доступности, что возникали в предыдущие месяцы у пользователей её сервиса Quay.io (в его основе — реестр для образов контейнеров, доставшийся компании вместе с покупкой CoreOS). Вне зависимости от вашей заинтересованности в этом сервисе как таковом, поучителен сам путь, по которому прошли SRE-инженеры компании для диагностики и устранения причин аварии.



19 мая, ранним утром (по летнему североамериканскому восточному времени, EDT), сервис quay.io упал. Авария затронула как потребителей quay.io, так и Open Source-проекты, использующие quay.io в качестве платформы для сборки и распространения ПО. Red Hat дорожит доверием как одних, так и других.

Команда SRE-инженеров сразу подключилась к работе и постаралась как можно скорее стабилизировать работу сервиса Quay. Однако пока они этим занимались, клиенты лишились возможности push’ить новые образы, и лишь периодически им удавалось pull’ить имеющиеся. По неведомой причине база данных quay.io блокировалась после масштабирования сервиса на полную мощность.

«Что изменилось?» — это первый вопрос, который принято задавать в подобных случаях. Мы заметили, что незадолго до проблемы кластер OpenShift Dedicated (на котором работает quay.io) начал обновляться до версии 4.3.19. Поскольку quay.io работает на Red Hat OpenShift Dedicated (OSD), регулярные обновления были обыденной операцией и никогда не приводили к проблемам. Более того, за предыдущие полгода мы несколько раз обновляли кластеры Quay без каких-либо перерывов в обслуживании.

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

Анализ первопричин


Основным симптомом сбоя была лавина из десятков тысяч подключений к БД, из-за которой экземпляр MySQL оказался фактически недееспособным. Из-за этого было сложно диагностировать проблему. Мы установили ограничение на максимальное количество подключений от клиентов, чтобы помочь команде SRE оценить проблему. Никакого необычного трафика к базе данных не заметили: на самом деле, большинство запросов были на чтение, а лишь немногие — на запись.

Мы также попытались выявить паттерн в трафике БД, который мог бы вызвать эту лавину. Однако никаких закономерностей в логах отыскать не удалось. Ожидая готовности нового кластера с OSD 4.3.18, мы продолжали попытки запустить pod'ы quay.io. Каждый раз, когда кластер выходил на полную мощность, база данных зависала. Это означало, что было необходимо перезапустить экземпляр RDS в дополнение ко всем pod'ам quay.io.

К вечеру мы стабилизировали сервис в режиме read-only и отключили максимум несущественных функций (например, сбор мусора в пространстве имен), чтобы снизить нагрузку на БД. Зависания прекратились, но причина так и не была найдена. Новый кластер OSD был готов, и мы перенесли сервис, подключили трафик и продолжили мониторинг.

Quay.io стабильно работал на новом OSD-кластере, поэтому мы вернулись к логам базы данных, но так и не смогли обнаружить корреляцию, объясняющую блокировки. Инженеры OpenShift работали совместно с нами, пытаясь понять, могли ли изменения в Red Hat OpenShift 4.3.19 привести к проблемам с Quay. Однако ничего обнаружить не удалось, а воспроизвести проблему в лабораторных условиях не получилось.

Второй сбой


28 мая, незадолго до полудня по EDT, quay.io опять упал c тем же симптомом: функционирование базы данных блокировалось. И снова мы бросили все силы на расследование. Прежде всего было нужно восстановить работу сервиса. Однако на этот раз перезагрузка RDS и перезапуск pod'ов quay.io ни к чему не привели: очередная лавина подключений захлестнула базу. Но почему?

Quay написан на Python, и каждый pod работает как единый монолитный контейнер. В среде выполнения контейнера одновременно выполняется множество параллельных задач. Мы используем библиотеку gevent под gunicorn для обработки веб-запросов. Когда в Quay поступает запрос (через наш собственный API, или через API Docker'а), ему назначается gevent worker. Обычно этот worker должен связаться с базой данных. После первого сбоя мы обнаружили, что gevent worker'ы подключались к базе данных, используя настройки по умолчанию.

Учитывая значительное число pod'ов Quay и тысячи поступающих запросов в секунду, большое число подключений к базе данных теоретически могло перегрузить экземпляр MySQL. Благодаря мониторингу было известно, что Quay в среднем обрабатывает 5 тыс. запросов в секунду. Примерно таким же было и число подключений к базе данных. 5 тыс. подключений с запасом укладывались в возможности нашего экземпляра RDS (чего нельзя сказать о десятках тысяч). По какой-то причине происходили неожиданные всплески числа подключений, однако мы не замечали какой-либо корреляции со входящими запросами.

В этот раз мы твердо решили найти и устранить источник проблемы, а не ограничиться перезагрузкой. В кодовую базу Quay были внесены изменения, лимитирующие число подключений к БД для каждого worker'а gevent. Это число стало параметром в конфигурации: стало возможным менять его «на лету», не собирая новый образ контейнера. Чтобы узнать, какое число подключений реально обработать, было проведено несколько испытаний со staging-окружением, в которых задавались разные значения, чтобы посмотреть, как это отразится на сценариях нагрузочного тестирования. В итоге обнаружилось, что Quay начинает выдавать ошибки 502, когда число подключений превышает 10 тыс.

Мы сразу развернули эту новую версию в production и стали следить за графиком подключений к базе данных. В прошлом база блокировалась примерно через 20 минут. Спустя 30 беспроблемных минут у нас появилась надежда, а спустя час — уверенность. Мы восстановили трафик на запись на сайте и приступили к postmortem-анализу.

Сумев обойти проблему, приводящую к блокировке, мы не выяснили ее подлинные причины. Подтвердилось, что она не связана с какими-либо изменениями в OpenShift 4.3.19, поскольку то же самое случилось и на версии 4.3.18, которая до этого работала с Quay без каких-либо проблем.

В кластере явно скрывалось что-то еще.

Детальное изучение


Quay.io шесть лет использовал настройки по умолчанию для подключения к БД без каких-либо проблем. Что изменилось? Понятно, что все это время трафик на quay.io неуклонно рос. В нашем случае все выглядело так, словно достигалось некое пороговое значение, которое служило триггером для лавины подключений. Мы продолжили изучать логи БД после второго сбоя, но не обнаружили каких-либо закономерностей или очевидных взаимосвязей.

Тем временем команда SRE занималась улучшениями в области наблюдаемости запросов в Quay и общего здоровья сервиса. Были развернуты новые метрики и панели мониторинга, показывающие, какие части Quay пользуются наибольшим спросом со стороны клиентов.

Quay.io нормально работал до 9 июня. Утром (по EDT) мы снова стали свидетелями значительного увеличения числа подключений к базе данных. На этот раз простоя не случилось, поскольку новый параметр ограничивал их количество и не позволял превысить пропускную способность MySQL. Однако примерно в течение получаса многие пользователи отмечали медленную работу quay.io. Мы быстро собрали все возможные данные, воспользовавшись добавленными инструментами мониторинга. Внезапно проявилась закономерность.

Перед самым скачком числа подключений большое число запросов поступило на App Registry API. App Registry — это малоизвестная функция quay.io. Она позволяет хранить такие штуки, как чарты Helm и контейнеры, «обогащённые» (rich) метаданными. Большинство пользователей quay.io не работают с этой функцией, однако ей активно пользуется Red Hat OpenShift. OperatorHub в составе OpenShift хранит все операторы в App Registry. Эти операторы формируют основу для экосистемы рабочих нагрузок OpenShift и операционной модели (в рамках операций «второго дня», Day 2), ориентированной на партнеров.

Каждый кластер OpenShift 4 использует операторы из встроенного OperatorHub'а для публикации каталога операторов, доступных для установки, и предоставления обновлений для уже установленных. С ростом популярности OpenShift 4 увеличилось и число кластеров на нем по всему миру. Каждый из этих кластеров загружает содержимое операторов, чтобы запустить встроенный OperatorHub, используя App Registry внутри quay.io как бэкэнд. В поисках источника проблемы мы упустили то, что с постепенным ростом популярности OpenShift увеличивалась и нагрузка на одну из редко используемых функций quay.io.

Мы провели некоторый анализ трафика запросов App Registry и заглянули в код реестра. Сразу же вскрылись недостатки, из-за которых запросы к базе данных формировались неоптимально. При небольшой нагрузке они не причиняли никаких хлопот, однако при ее возрастании становились источником проблем. У App Registry оказалось два проблемных endpoint'а, плохо реагирующих на возрастание нагрузки: первый выдавал список всех пакетов в репозитории, второй — возвращал все blob'ы для пакета.

Устранение причин


Всю следующую неделю мы занимались оптимизацией кода самого App Registry и его окружения. Были переработаны явно неэффективные SQL-запросы, устранены лишние вызовы команды tar (она запускалась при каждом извлечении blob'ов), добавлено кэширование везде, где возможно. Затем было проведено масштабное тестирование производительности и сравнена скорость работы App Registry до и после изменений.

Запросы API, которые раньше занимали до полуминуты, теперь выполнялись за миллисекунды. На следующей неделе мы развернули изменения в production, и с тех пор quay.io работает стабильно. За это время наблюдались несколько резких всплесков трафика на endpoint'е App Registry, но проделанные усовершенствования предотвратили перебои в работе базы данных.

Чему мы научились?


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

  1. Данные о том, кто и как использует ваш сервис, не бывают лишними. Поскольку Quay «просто работал», у нас никогда не возникала необходимость тратить время на оптимизацию трафика и управление нагрузкой. Все это создало ложное ощущение безопасности, что сервис может масштабироваться до бесконечности.
  2. Когда сервис падает, восстановление его работы — главный приоритет. Поскольку Quay продолжал страдать от заблокированной базы данных во время первого сбоя, наши стандартные процедуры не оказали предполагаемого эффекта и мы не смогли восстановить работу сервиса с их помощью. Это привело к ситуации, когда пришлось тратить время на анализ и сбор данных в надежде найти первопричину — вместо того, чтобы направить все усилия на восстановление работоспособности.
  3. Оценивайте влияние каждой из функций сервиса. Клиенты редко использовали App Registry, поэтому он не являлся приоритетным для нашей команды. Когда некоторые функции продукта почти не используются, их баги «всплывают» редко, и разработчики перестают следить за кодом. Легко стать жертвой заблуждения, что так и должно быть — пока внезапно эта функция не оказывается в центре масштабного инцидента.

Что дальше?


Работа по обеспечению стабильности сервиса никогда не прекращается и мы постоянно улучшаем его. Объемы трафика на quay.io продолжают расти, и мы осознаем, что обязаны делать все возможное, чтобы оправдать доверие клиентов. Поэтому в настоящее время работаем над следующими задачами:

  1. Развертывание реплик баз данных только для чтения, чтобы помочь сервису обрабатывать соответствующий трафик в случае возникновения проблем с основным экземпляром RDS.
  2. Обновление экземпляра RDS. Текущая версия сама по себе не является проблемой. Скорее, мы просто хотим убрать ложный след (по которому пошли во время сбоя); поддержание ПО в актуальном состоянии позволит устранить еще один фактор на случай будущих отключений.
  3. Дополнительное кэширование по всему кластеру. Мы продолжаем поиск областей, в которых кэширование позволить снизить нагрузку на базу данных.
  4. Добавление firewall’а веб-приложений (WAF), чтобы видеть, кто и почему подключается к quay.io.
  5. Начиная со следующего релиза, кластеры Red Hat OpenShift откажутся от App Registry в пользу каталогов операторов (Operator Catalogs), базирующихся на образах контейнеров, доступных на quay.io.
  6. Долгосрочной заменой App Registry может стать поддержка спецификаций артефактов Open Container Initiative (OCI). В настоящее время она реализуется в виде родного функционала Quay и будет доступна для пользователей, когда саму спецификацию окончательно согласуют.

Все вышеперечисленное является частью продолжающихся инвестиций Red Hat в quay.io по мере того, как мы переходим от небольшой команды «в духе стартапа» к зрелой платформе, управляемой SRE. Мы знаем, что многие наши клиенты полагаются на quay.io в своей повседневной работе (включая Red Hat!) и стараемся быть максимально открытыми в отношении недавних сбоев и продолжающихся усилий стать лучше.

P.S. от переводчика


Читайте также в нашем блоге:

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