Привет. Хочу разобрать один сумбурный кейс из поддержки Sentry-инстанса.

Проблема

Утро, как обычно. В Slack пишут разработчики: «Слушай, с Sentry что-то странное. Вроде работает, но issues не приходят». Смотрю, инстанс живой, но логов нет, новые issues действительно не создаются.

Первый рефлекс перезапустить. compose down && compose up. Через минуту всё поднимается, issues пошли, все довольны. Час-два тишина.

Потом снова. Issues нет. Ещё один рестарт.

Через несколько дней стало ясно, что это не случайные падения. Что-то системное происходит. Каждый день перезапускать не вариант.

Первая попытка: базовые метрики

Смотрю дашборд. На сервере только базовые вещи: диск, память, CPU, сеть. Всё зелёное, ничего не выделяется. Бесполезно.

Жду следующего сбоя. Когда он случается, снова смотрю те же графики. По-прежнему ничего. Непонятно, что именно ломается.

Добавляю детализацию

Понял, что нужны более гранулярные метрики. Включил:

  • Disk I/O по устройствам (dm-0, dm-1, dm-2, sda, sr0)

  • Load Average

  • По Redis: использование памяти, evicted keys, expired keys, connected clients

И жду следующего утра.

Первая нормальная зацепка

На следующее утро примерно в то же время вижу на графиках:

Метрики Redis и диска
Метрики Redis и диска

Память Redis упирается в лимит, после этого начинают вытесняться ключи. Если события нормально обрабатываются, память должна освобождаться. А тут она растёт и Redis начинает выкидывать ключи, значит, события где-то зависают и не разбираются.

Они просто копятся в Redis.

Kafka и Snuba

Копаюсь в логах и метриках. Нахожу: Snuba-консьюмеры лежат. Они не читают события из Kafka. Всё сходится: события не обрабатываются → не удаляются из Redis → Redis забивается → ключи вытесняются.

Перезапускаю консьюмеры, они поднимаются, очередь начинает разгребаться, всё приходит в норму. Разработчики снова видят issues.

Но понятно, что завтра будет то же самое. Что-то регулярно их убивает. Нужно понять, что именно.

Добавляю метрики по Kafka:

  • Stuck consumers

  • Consumer group members

  • Consumer lag

И сразу алерты на lag, чтобы ловить проблему раньше.

Метрики Kafka consumer groups
Метрики Kafka consumer groups

Диск

Жду следующего раза и уже целенаправленно смотрю на disk I/O.

И вот оно: каждое утро примерно в одно и то же время disk I/O упирается почти в 100% и держится так около получаса. Диск полностью забит.

Не случайность. Одно и то же время каждый день.

Kafka сильно завязана на диск. Когда I/O полностью занят, она начинает тормозить, консьюмеры ловят таймауты, соединения рвутся, они отваливаются.

Но почему диск так грузится? Никаких тяжёлых джоб или процессов, которые бы писали терабайты, не видно. Спрашиваю админов.

«А, ну да, говорят, по утрам полный бэкап/снепшот сервера. Минут на тридцать диск занимает».

Вот и причина.

Как это выглядит целиком

  1. Утром стартует бэкап → диск на 100%.

  2. Kafka не может нормально читать/писать.

  3. Snuba-консьюмеры отваливаются по таймаутам.

  4. События остаются в Redis (они удаляются только после успешной обработки).

  5. Redis начинает забиваться.

  6. Когда память заканчивается, Redis вытесняет старые ключи.

  7. Через ~30 минут бэкап заканчивается, диск освобождается.

  8. Часть консьюмеров к этому моменту уже мёртвая, поэтому разгребание идёт медленнее.

  9. Redis продолжает потихоньку расти, пока я руками не перезапущу консьюмеры.

Память Sentry
Память Sentry

Бэкап выключать нельзя, данные критичные. Нужно было сделать так, чтобы система переживала это окно.

Что сделал

Несколько слоёв защиты.

1. Relay на всех сервисах.
Relay - локальный буфер. Если Redis недоступен или перегружен, события копятся у него, а потом догоняют, когда всё оживёт. Защита от потери данных:

https://github.com/getsentry/relay

2. Увеличил лимит памяти Redis.
Вместо того чтобы сразу начинать вытеснять ключи, просто дал больше памяти:

redis:
  ...
  command: redis-server --maxmemory 6gb --maxmemory-policy allkeys-lru
  ...

Политику вытеснения оставил allkeys-lru. В худшем случае лучше потерять несколько ключей, чем полностью встать.

3. 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 и увеличенному лимиту. Консьюмеры, если и отваливаются, поднимаются сами. Issues снова приходят нормально.

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