Post Mortem за недостъпността на Quay.io

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

Post Mortem за недостъпността на Quay.io

На 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.

До вечерта стабилизирахме услугата в режим само за четене и изключихме максимум несъществени функции (например, събиране на боклука в пространството за имена), за да намалим натоварването на базата данни. Замръзванията преустановиха, но причината така и не беше намерена. Новият кластер OSD беше готов, и ние прехвърлихме услугата, свързахме трафика и продължихме наблюдението.

Quay.io стабилно работеше на новия OSD-кластер, затова се върнахме към логовете на базата данни, но не успяхме да открием корелация, която да обясни блокировките. Инженерите на OpenShift работеха съвместно с нас, опитвайки се да разберат дали промените в Red Hat OpenShift 4.3.19 са довели до проблеми с Quay. Въпреки това, нищо не беше открито, а не успяхме да възпроизведем проблема в лабораторни условия.

Вторият срив

На 28 май, малко преди обяд по EDT, quay.io отново падна с един и същ симптом: функционирането на базата данни беше блокирано. И отново насочихме всички сили към разследването. Преди всичко беше необходимо да възстановим работата на услугата. Въпреки това този път рестартирането на RDS и перезареждането на pod-овете на quay.io не доведоха до нищо: нова лавина от връзки заля базата. Но защо?

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

Като се отчете значителното количество подове на Quay и хиляди входящи заявки в секунда, голямо количество свързвания към базата данни теоретично можеше да претовари инстанцията на MySQL. Чрез мониторинг бе установено, че Quay в средно обработва 5 хиляди заявки в секунда. Приблизително толкова беше и броят на свързванията към базата данни. 5 хиляди свързвания безопасно попадаха в възможностите на нашата инстанция RDS (въпреки че не може да се каже същото за десетките хиляди). По някаква причина се появяваха неочаквани изблици на свързвания., обаче не забелязахме никаква корелация с входящите заявки.

Този път решихме твърдо да намерим и отстраним източника на проблема, а не да се ограничим до рестартиране. В кодовата база на Quay бяха направени промени, ограничаващи броя на свързванията към БД за всеки работник gevent. Този брой стана параметър в конфигурацията: стана възможно да се променя „в движение“, без да се събира нов образ на контейнера. За да установим, какъв брой свързвания реално може да се обработи, бяха проведени няколко теста със staging среди, в които се задаваха различни стойности, за да видим как това ще се отрази на сценарии за натоварване. В крайна сметка установихме, че Quay започва да връща грешки 502, когато броят на свързванията надхвърли 10 хиляди.

Веднага разгряхме тази нова версия в продукция и започнахме да следим графика на свързванията към базата данни. В миналото базата се блокираше след около 20 минути. След 30 безпроблемни минути получихме надежда, а след един час — увереност. Възстановихме трафика за запис на сайта и започнахме постмортем анализ.

Успявайки да заобиколим проблема, който водеше до блокировка, не успяхме да установим истинските му причини.Потвърди се, че той не е свързан с никакви промени в 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 чаартове и контейнери с богати метаданни. Повечето потребители на 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. от преводача

Прочетете също в нашия блог:

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster