Проблема
Утро, все как обычно. Разработчики пишут: «Слушай, что-то с Sentry. Вроде работает, но issues не приходят». Проверяю статус, инстанс жив, но все верно: логов нет, issues не создаются.
Первый рефлекс, перезапустить. Делаю docker compose down && docker compose up. Через минуту инстанс поднимается, issues идут, разработчики довольны. День-два все нормально.
Потом повторяется. Issues нет. Нужен еще один рестарт.
Через несколько дней такого становится понятно: это не случайное падение. Происходит что-то системное. Перезапускать каждый день не решение.
Первая попытка: базовые метрики
Смотрю на дашборд мониторинга. На сервере только базовые метрики: диск, память, CPU, сеть. Все выглядит нормально, ничего не выделяется. Пользы никакой.
Добавляю детализацию: метрики диска и Redis
Понимаю, что нужна более гранулярная картина. Добавляю:
Disk I/O в разрезе устройств (dm-0, dm-1, dm-2, sda, sr0)
Load Average
Redis: RAM, evicted keys, expired keys, connected clients
Включаю и жду следующего утра.
Первая реальная зацепка
Следующим утром примерно в то же время вижу это на графиках.

Память Redis выстреливает до лимита. Потом начинают вытесняться ключи. Это уже настоящая зацепка: если события обрабатываются нормально, память должна освобождаться. Если она забивается и ключи вытесняются, значит, события где-то застревают.
Они копятся в Redis, потому что их никто не обрабатывает.
Добавляю метрики Kafka
Копаюсь в логах и метриках и нахожу ответ. Snuba-консьюмеры лежат. Они не разбирают события из Kafka. Это все объясняет: события не обрабатываются, не удаляются из Redis, Redis забивается, ключи вытесняются.
Перезапускаю Snuba-консьюмеров, они поднимаются, события начинают разгребаться, все приходит в норму. Разработчики снова видят issues.
Но я понимаю, что завтра это повторится. Что-то стабильно убивает эти консьюмеры. Нужно понять что.
Теперь мне нужен контроль над консьюмерами. Добавляю более детальные метрики по Kafka:
Stuck consumers
Consumer group members
Consumer lag
Заодно вешаю алерты на consumer lag, чтобы ловить проблему сразу.

Иду по следу: Disk I/O
Жду, когда проблема проявится снова. В этот раз смотрю внимательно.
При следующем срабатывании присматриваюсь к графику disk I/O, который добавил раньше. И вот оно, странно что не заметил раньше
Каждое утро примерно в одно и то же время disk I/O упирается в потолок почти на 30 минут подряд. Disk I/O почти 100%, диск полностью загружен.
Это не случайность. Происходит ровно в одно и то же время каждый день.
Тут все складывается. Kafka работает с диском. Когда диск полностью загружен, Kafka не может нормально читать и писать. Консьюмеры начинают ловить таймауты, соединения рвутся, они отваливаются.
Но почему диск так загружен? Активных процессов, которые пишут большие объемы, нет. Ни джоб, ни бэкап-сервисов. Проверяю и ничего подозрительного.
Спрашиваю у админов, что происходит с диском по утрам.
«А, ну да, по утрам делается полный бэкап или снепшот сервера. Занимает диск где-то на полчаса».
Полная картина
Теперь видна вся цепочка событий:
Утро: стартует бэкап/снепшот - диск полностью забивается
Kafka не может нормально работать - диск занят, I/O заблокирован
Snuba-консьюмеры ловят таймауты - соединения рвутся, они отваливаются
События остаются в Redis - они удаляются только после успешной обработки
Redis начинает забиваться необработанными событиями
Redis вытесняет старые ключи, чтобы освободить место
Через 30 минут диск освобождается - консьюмеры снова работают, события разгребаются
Но часть консьюмеров так и осталась отвалившейся после таймаута, поэтому обработка идёт медленнее
Redis продолжает расти - медленнее, чем раньше, но растет. Пока я не перезапущу Snuba-консьюмеров

Бэкап - неизбежная часть продакшен-инфраструктуры. Просто выключить его нельзя, данные критичны. Нужно адаптировать систему так, чтобы она переживала окно бэкапа.
Решение
Было сделано несколько слоев.
Первое: relay на всех сервисах, где еще не успели Relay - это буфер. Если Redis недоступен или перегружен, события копятся локально на relay, а потом отправляются, когда Redis оживет. Защита от потери данных:
https://github.com/getsentry/relay
Второе: увеличил лимит памяти Redis. Вместо того чтобы вытеснять ключи при заполнении памяти, просто дать памяти больше пространства:
... redis: ... command: redis-server --maxmemory 10gb --maxmemory-policy allkeys-lru ...
Политику вытеснения ключей я менять не стал, чтобы в худшем случае Redis не встал совсем. Лучше потерять несколько ключей, чем заблокировать весь сервис.
Третье: healthcheck и авторестарт для Snuba-консьюмеров. Если консьюмер падает, пусть перезапускается сам. Быстро:
snuba-consumer: image: getsentry/snuba:latest healthcheck: test: ["CMD", "curl", "-f", "http://localhost:1218/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s restart: on-failure:5 environment: SNUBA_SETTINGS: docker KAFKA_BROKERS: kafka:9092 REDIS_HOST: redis ...
Результат
После этих изменений всё стабилизировалось. Redis не переполняется благодаря relay и увеличенному лимиту памяти. Snuba-консьюмеры, если и падают, поднимаются сами. Разработчики видят issues так, как и должны.