Привет, меня зовут Анатолий, я ведущий разработчик в ITFB Group. У нас высоконагруженный сервис торговых операций. И раз в неделю, как по расписанию, раздавался панический звонок: «Опять пропали запросы!». Мы неслись смотреть логи — а там... ничего. Ни ошибок, ни падений. Никаких пятисотых, только стабильные двухсотые. Стенды dev и prod молчали, как рыбы. Запросы загадочным образом появлялись через некоторое время, и всё работало, пока история не повторялась снова. Это был не баг, это был призрак. Призрак в сети.

Сегодня я расскажу, как мы его поймали.

Контекст: что за система и в чем боль?

Сервис торговых операций (наш герой): Написан на Java, само собой с использованием, Spring Boot. Он отвечает за запуск и управление аукционами.

База данных: PostgreSQL — хранит все состояния и ставки.

Инфраструктура: всё крутится в Kubernetes.

Проблема: Раз в несколько дней несколько операций «пропадали» — их таймеры останавливались, а потом, спустя минуту-другую вдруг продолжали работу, будто ничего и не случилось.

Тот самый обрыв соединения, который я обнаружил
Тот самый обрыв соединения, который я обнаружил

Симптомы: призрак в машине

  1. Тишина в логах. Абсолютная. Ни ошибок 5xx, ни таймаутов в трейсах. Сервисы были живы и здоровы по всем метрикам Kubernetes.

  2. На стендах всё чисто. На dev и staging воспроизвести проблему не получалось. Она проявлялась только в prod под реальной нагрузкой.

  3. Запросы доходили, но с диким опозданием. Это был главный ключ. Мы не теряли их насовсем, они просто «застревали» в пути и прибывали с задержкой в десятки секунд, сбивая все тайминги.

Расследование: от слепого поиска к точечной гипотезе

Шаг 1: Отчаяние и первый прорыв

Мы перерыли всё: логи приложения, логи Postgres, метрики БД (не было ли дедлоков?). Безрезультатно. Стандартный мониторинг был слеп к этой проблеме.

Решение, которое всё изменило

Я написал и запустил простой diagnostic pod в том же кластере. Это был простейший скрипт на Bash, который в бесконечном цикле curl'ил healthcheck-эндпоинт нашего Java-сервиса раз в секунду и логировал время ответа.

Результат оказался ошеломляющим: Мы поймали аномалию! Раз в 2-3 дня наш скрипт фиксировал потерю 2-3 запросов подряд. После этого пауза в 20-40 секунд – и пропавшие запросы вдруг «возвращались к жизни», получали ответ HTTP 200 OK, и всё шло дальше, как ни в чем не бывало.

Гипотеза №1 (Java / JVM): возможно сборщик мусора (Garbage Collector) уходит в длительную паузу? Мы подключили GC-логирование и смотрели в Grafana. Результат: паузы GC были в пределах нормы (200-300 мс) и не совпадали по времени с 4-5-секундными простоями.

Гипотеза №2 (Kubernetes): Проблема с самими подами? Мы посмотрели метрики: пересоздания подов, нехватка ресурсов – ничего не совпадало по времени с нашими инцидентами.

Гипотеза №3 (сеть): А что если сеть ненадолго «зависает»? Пакеты не теряются, а где-то буферизуются (например, на балансировщике нагрузки) и потом отпускаются дальше? Это объясняло бы всё: отсутствие ошибок (TCP-сессия не рвется), задержку и случайность происходящего.

Инструменты и доказательства

Мы начали целенаправленную охоту на сеть.

  1. Углубленный мониторинг: Мы настроили Blackbox Exporter для Prometheus, который начал постоянно опрашивать наш эндпоинт не раз в секунду, а раз в 100 мс, чтобы точнее поймать момент проседания.

  2. Анализ трафика: В момент, предшествующий очередному инциденту, мы запустили на поде с Java-сервисом команду: bash tcpdump -i any -w /tmp/capture.pcap port 8080 #

  3. Анализ дампа: Открыв полученный файл capture.pcap в Wireshark, мы увидели четкую картину:
    - Клиент исправно отправляет SYN-пакеты для установления соединения.
    - В течение 4-5 секунд на них нет ответа (SYN-ACK).
    - Через 4-5 секунд соединение волшебным образом устанавливается, и все «замерзшие» запросы разом уходят и получают ответ.

Это было 100% доказательство: проблема была не в приложении, а в сетевом оборудовании между подами в Kubernetes, которое на короткое время переставало маршрутизировать пакеты.

Решение и выводы

Решение: Мы передали полученные данные (логи скрипта, .pcap дамп) команде инфраструктуры. Они, в свою очередь, обнаружили проблему на балансировщике нагрузки (L4). В его конфигурации или прошивке был баг (нам они постеснялись сказать), который при определенной нагрузке приводил к кратковременному «зависанию» сессии. Он не разрывал соединение, а буферизовал трафик, пытаясь его восстановить, и через некоторое время успешно это делал.

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

Главные уроки

Сначала среда, потом код. Если логи молчат, а проблема есть – ищите на уровень ниже (K8s, сеть, ОС).

Создавайте активную нагрузку для диагностики. Пассивного мониторинга часто недостаточно. Простейший скрипт, который «спамит» запросы, может оказаться ценнее сложной системы APM.

tcpdump + Wireshark – мастхэв для любого разработчика. Умение сделать дамп трафика и хотя бы базово его прочитать – критически важный навык для работы в распределенных системах.

Гипотезы должны быть проверяемыми. Мы не просто говорили «сеть виновата», мы предложили механизм проверки и нашли прямое доказательство. Наш «призрак» оказался сетевым багом. И теперь мы знаем: если что-то работает с перебоями, но не падает – первым делом смотрим на сеть.

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