https://habr.com/ru/companies/flant/articles/1043512/
Следуя нашему правилу вносить изменения в инфраструктуру максимально осторожно, мы сперва выкатили всё на стейдж. Развёртывание прошло успешно. Но спустя несколько недель начались спорадические сбои: примерно раз в неделю один из агентов Cilium падал так, что приходилось полностью перезагружать весь узел. Никаких явных паттернов или очевидных причин. Баг случался редко, но бил слишком больно, чтобы пускать такое в production.
Первая мысль — скорее всего, намудрили с конфигурацией, ведь Cilium — серьёзный, проверенный в бою проект, который используют тысячи компаний по всему миру. Наверняка мы допустили ошибку в конфигурации или столкнулись с пограничным случаем. Забегая вперед — догадка оказалась и верной, и неверной одновременно, причём весьма неожиданным образом.
. . .
Заметил кое-что интересное: упавшие агенты Cilium потребляли аномально много памяти во время запуска узлов, на которых они размещались. Причём потребление памяти не росло постепенно — на графиках были видны резкие всплески прямо при инициализации узла.
. . .
Я начал экспериментировать с различными параметрами Cilium: лимитами памяти, размерами eBPF-карт, различными настройками производительности. Затем попробовал отключить одну специфическую опцию, связанную с производительностью (bpf-distributed-lru: false), и перезапустил тест. Сбои прекратились. Включил её обратно — сбои вернулись. Снова отключил — всё стабильно. Многочисленные перезапуски теста показали: закономерность сохраняется.
Это была первая реальная зацепка: баг был напрямую связан с некой оптимизацией, которую мы включили, руководствуясь официальными гайдами Cilium.
. . .
При включённом distributed LRU ядро округляет вверх количество записей в карте до значения, кратного num_possible_cpus().
Вот где скрывалась проблема! Ядро автоматически корректировало размер любой карты так, чтобы он был кратен количеству ядер процессора. В конфиге Cilium мы жёстко прописали статический размер карты, как рекомендует официальная документация: bpf-ct-global-tcp-max: 131072
Это степень двойки (131 072 = 217), как и рекомендуют гайды. И оно отлично работало… пока количество ядер тоже было степенью двойки. Но вот в случае 36, 48 или 72 ядер значение округлялось вверх, создавая несоответствие.
Последовательность событий, которая приводила к проблеме, выглядит следующим образом:
- Cilium настраивает карту на 131 072 записи.
- Ядро округляет это значение до 131 076 (на узле с 36 ядрами).
- Цикл согласования (reconciliation) Cilium проверяет размер карты.
- Обнаружено расхождение: в карте 131 076 записей, а должно быть 131 072.
- Cilium удаляет карту и пересоздаёт её с размером 131 072 записи.
- Ядро округляет значение до 131 076… и так до бесконечности!
Оригинал
Kernel Archaeology: Why 36 CPUs Crash Cilium But 32 Don’t
https://medium.com/qonto-way/kernel-archaeology-why-36-cpus-crash-cilium-but-32-dont-2007f6f6772a
