Pull to refresh

Comments 12

Траблшутинг процесс творческий, увольнять инженеров за это плохая практика.

Я бы в первую очередь перешёл на keydb, это бы позволило решать проблему не в режиме горящих жоп и ограничило баг. Те возможно были бы утилизированы все треды без роста нагрузки и тогда это 100% цикл. Но в keydb другие проблемы, форк не поспевает и там нет последних фичей, с подменой ip например. Плюс есть свои фатальные баги.

Envoy, haproxy или самописный проксик не решает проблему. Или я не понял что они должны были решить. Проксирование редиса на L7 работает хорошо, из минусов только лишние ресурсы на прокси. Но основная его цель как раз скрыть кластер для клиента, те его можно было использовать для миграции. Или подмены кластеров. Из плюсов он даёт метрики по командам.

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

Спасибо за ваш комментарий.

Честно говоря, даже если это и код, то я не очень понимаю откуда оно вылезло - транзакции в NewRelic (к сожалению, я забыл их упомянуть и добавил чуть позже в статью) циклов не выявили. Да, релик не очень хорошой работает с OOMами (в том числе по глубине стека вызовов), но у нас на этот счет была доработка для Sentry - и там все было "как обычно".

А вот MONITOR и поправленная faina четко показывали что это один и тот же клиент бьет запросами.

Меня не уволили за то что тут описано, компанию я покинул по совсем другой причине :)

Меня как-то "увольняли" за сбой, поэтому наверно не так понял:))

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

Чтобы было понятнее: ваш код ожидает что из кэша будет извлечен объект, а приходила строка. Или вместо массива чисел одно число и тд. 

выглядит так, будто результат CLUSTER SLOTS был закеширован слишком надолго, и запросы приходили не на нужные ноды

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

Возможно, проблема в вычитывании результатов, которые присылает Redis - т.к. его подключение это последовательная TCP сессия - в каком порядке запросы отправлены - в таком порядке ответы придут обратно, никаких идентификаторов у ответов нет. Соответственно, если что-то не было вычитано или вычитали лишнего - все запросы этого подключения дальше будут с кривыми данными. Еще я видел ситуации, когда один и тот-же ключ использовали под разные типы данных или клали одно а пытались вычитать другое, помогала типизация ключей на клиенте. Или это были одинарные ошибки?

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

По поводу 100% загрузки ноды запросами по одному ключу, а это не могла быть библиотека с каким-нибудь бесконечным retry в случае неудачи? Во всяком случае, я бы попробовал отследить источник проблем, имхо, это либо вызывающий код или библиотека.

Спасибо за ваш комментарий.

"последотвательная TCP-сессия" - вы очень точно сформулировали то что я хотел сказать про pconnect и протокол Redis.

Одинаковые ключи с разными типа данных тут маловероятны. Проект хоть и на PHP, но достаточно типизирован, в CI стояли линтеры которые помогали разработчикам в отлове таких ситуаций. Да и команда, где это проявилось в первый раз, активно использовала DTO внутри своих компонентов. Да, ошибки были единичными, в абсолютном большинстве (99,9%) случаев все было хорошо.

Retry - может и мог быть, но в голове сейчас не могу прокрутить где именно. Насколько я помню – наш враппер делал максимум 3 попытки за какое-то время, и мы проверяли эту логику перед выкаткой.

А как в phpredis с ними обстоят дела уже не помню – гляну как будет время.

Спасибо. Интересно. Прочитал как детектив какой-то.

Я бы где-то в начале дебаггером залез бы и в итоге починил бы.

Спасибо за ваш комментарий.

Мысль интересная, но тяжело реализуемая в реальности, по следующим причинам:

1) Xdebug на прод при высокой нагрузке скорее всего никто не даст вам поставить или включить – если у вас нет пачки серверов которые можно быстро поставить в строй, скомпенсировав потерю вычислительной возможности после этого;

2) Даже если договоритесь "давайте поставим" – это займет время и скорее всего собьет среду выполнения, так как будет рестарт и проблема после этого на этом сервере уйдет, ну и опять таки потеряете время так как на какое-то время сервер будет выброшен из нагрузки;

3) Вам нужно будет как-то сэмулировать поведение клиента сервиса. Напоминаю: ошибка вылезает не постоянно, а очень редко. Вот в IDE у вас запрос пришел, как понять будет ошибка или нет? Интерактивно делать step over для каждого запроса?

У нас были достаточно подробные трейсы в Sentry по ним было понятно что проблема лезет корнями из Redis.

Очень удачный заголовок статьи! После фразы PHP 7.2 саму статью можно дальше не читать.

На всякий случай, если кто-то не в курсе, активная поддержка PHP 7.2 прекращена более трёх лет назад, а исправления безопасности окончательно прекращены более двух лет назад.

Тот факт, что приложение не было обновлено до актуальной версии PHP и зависимостей в течение более чем трёх лет, говорит очень многое об уровне команды и как следствие — о качестве кодовой базы.

Спасибо за ваш комментарий.

Не знаю почему вы решили что описанная ситуация возможна только на PHP 7.2, равно как и то что это произошло вчера.

Любая проблема должна быть пережита равно как и соблюдены условия для того чтобы ее можно было опубликовать. Если все еще непонятно, говорю прямо: мне бы не дали эту статью написать несколько лет назад. :)

Но стало интересно почитать или послушать про ваш опыт поддержки огромных проектов (тут репозитарий кода весил в районе 1,5Гб, релиз с зависимостями что-то около 120Мб, крутилось на нескольких десятках серверов, а вся обвязка вокруг монолита – почти 20 забитых стоек) под самые свежие версии языка.

Sign up to leave a comment.

Articles