История одного бага: как Cloudflare искала ошибку в библиотеке hyper
Как Cloudflare расследовала «невидимый» баг в архитектуре
Инженерная команда Cloudflare столкнулась с необычной проблемой после оптимизации архитектуры сервиса Cloudflare Images. Переход с сетевых сокетов на локальные Unix-сокеты, призванный повысить производительность, привел к неожиданным последствиям: пользователи начали жаловаться на поврежденные или неполные изображения.
Уникальность ситуации заключалась в том, что стандартные инструменты мониторинга уровня приложения не фиксировали никаких ошибок, а попытки воспроизвести инцидент с помощью curl не дали результата. Исследование причин растянулось на шесть недель, хотя итоговое исправление потребовало лишь четырех строк кода.
Поиск истины с помощью strace
Прорыв в расследовании произошел после использования strace — инструмента для отслеживания системных вызовов ядра. Выяснилось, что при передаче крупных файлов процесс выполнял системный вызов sendto для записи в буфер сокета, но сразу после этого инициировал закрытие соединения (shutdown), даже если часть данных оставалась во внутреннем буфере библиотеки.
Причиной оказалась ошибка в hyper — популярной HTTP-библиотеке на языке Rust. Баг, присутствовавший в коде годами, скрывался в цикле обработки соединений (dispatch.rs):
let _ = self.poll_flush(cx)?;
В этом фрагменте результат вызова функции poll_flush игнорировался. Если буфер сокета на стороне получателя временно переполнялся, функция возвращала статус Poll::Pending, сигнализируя, что данные не были переданы полностью. Однако из-за конструкции let _ библиотека ошибочно считала операцию завершенной и преждевременно закрывала сокет, что приводило к потере «хвоста» файла.
Уроки для высоконагруженных систем
Этот инцидент наглядно демонстрирует важность глубокого тестирования межсервисного взаимодействия. При работе с Kubernetes, sidecar-контейнерами или service mesh сетями критически важно:
- Проводить стресс-тесты на переполнение буферов.
- Активно симулировать поведение «медленных клиентов» (slow clients) в тестовой среде.
- Не игнорировать возвращаемые статусы асинхронных операций в низкоуровневом коде.