Как сломать свой сервис и спать спокойно: обзор Toxiproxy
Представьте ситуацию: три часа ночи, вы просыпаетесь от звонка дежурного инженера. База данных в другом дата-центре начала «лагать», сетевые задержки выросли до пяти секунд, и ваше приложение, которое отлично работало на тестах, внезапно сложилось как карточный домик. Знакомая история?
В локальной разработке у нас всё всегда идеально: MySQL отвечает за миллисекунды, Redis доступен мгновенно, а сеть стабильна как скала. Но реальный мир — это хаос. И чтобы этот хаос не убил ваш продакшн, его нужно научиться имитировать. Именно для этого ребята из Shopify создали Toxiproxy.

Что это такое и зачем оно в вашем стеке?
Toxiproxy — это специализированный TCP-прокси, написанный на Go. Его единственная задача — быть «плохим парнем» между вашим приложением и его зависимостями (БД, кэшем, внешними API).
В отличие от стандартных инструментов Linux вроде iptables или tc, которые требуют root-прав и сложны в настройке, Toxiproxy управляется через простой HTTP API или CLI. Это делает его идеальным инструментом для автоматизированных тестов и CI/CD пайплайнов. Вы буквально можете сказать в коде теста: «А теперь пусть Redis отвечает с задержкой в две секунды», и проверить, не отвалится ли фронтенд по тайм-ауту.
Пять способов испортить жизнь своему коду (в благих целях)
Toxiproxy использует концепцию «токсиков» (toxics) — манипуляций, которые применяются к соединению. Вот самые интересные из них:
- Latency (Задержка): Добавляет фиксированную задержку или джиттер (случайные колебания времени ответа). Это классика для проверки того, как ваше приложение обрабатывает медленные запросы.
- Bandwidth (Пропускная способность): Ограничивает скорость передачи данных (например, до 10 КБ/с). Идеально для симуляции медленного мобильного интернета.
- Slow Close: Задерживает закрытие TCP-сокета. Помогает отловить утечки соединений и проблемы с пулом коннектов.
- Timeout: Просто перестает передавать данные и закрывает соединение через заданное время.
- Slicer: Нарезает TCP-пакеты на мелкие кусочки, добавляя между ними микро-задержки. Это отличный способ проверить устойчивость парсеров протоколов.
Интересно, что токсики можно комбинировать. Например, можно сделать соединение медленным и нестабильным одновременно, выставив параметр toxicity (вероятность срабатывания).
Как это работает на практике?
Принцип работы прост: вы настраиваете Toxiproxy так, чтобы он слушал локальный порт и перенаправлял трафик на реальный сервис. Затем вы меняете конфиг своего приложения, чтобы оно стучалось не в базу напрямую, а в порт Toxiproxy.
Давайте посмотрим на живой пример на Ruby (хотя у Toxiproxy есть клиенты под всё: Go, Python, Java, Node.js, PHP и даже Rust). Допустим, мы хотим проверить, как блог на Rails поведет себя, если Redis с тегами «приляжет».
Сначала регистрируем прокси при запуске приложения:
require 'toxiproxy'
Toxiproxy.populate([
{
name: "redis_tags",
listen: "127.0.0.1:22222", # Приложение пойдет сюда
upstream: "127.0.0.1:6379" # Реальный Redis здесь
}
])
А теперь пишем сам тест:
test "должен вернуть пустой массив, если Redis недоступен" do
@post.add_tag "технологии"
# Кладем прокси для Redis
Toxiproxy[/redis/].down do
assert_equal [], @post.tags
end
end
Если ваш код не умеет обрабатывать Redis::CannotConnectError, тест упадет. Это и есть тот самый момент истины, который Toxiproxy дарит разработчику еще до того, как код попал в продакшн.
Почему не использовать стандартные средства ОС?
Часто спрашивают: «Почему бы не дергать nc или не настраивать ipfw?». Ответ кроется в удобстве и детерминированности:
- Кроссплатформенность: Toxiproxy одинаково работает на Linux, macOS и Windows.
- API-first: Вам не нужно лезть в консоль сервера. Вы управляете состоянием сети прямо из кода тестов.
- Динамичность: Можно менять параметры «на лету» без перезагрузки сервисов.
- Метрики: Инструмент из коробки отдает данные в формате Prometheus. Вы можете видеть, сколько данных прошло через прокси и как часто срабатывали токсики.
Архитектура и производительность
Несмотря на то, что это прослойка, Toxiproxy очень быстр. В Shopify заявляют, что на обычном MacBook задержка чистого прокси составляет меньше 100 микросекунд, а пропускная способность достигает 1000 МБ/с. Это значит, что в 99% случаев вы даже не заметите присутствия Toxiproxy в системе, пока не включите токсики специально.
Серверная часть написана на Go, что обеспечивает легкость развертывания — это просто один бинарник. Для любителей контейнеров есть официальный Docker-образ:
docker run --rm -it ghcr.io/shopify/toxiproxy
Итог: кому это нужно?
Toxiproxy — это must-have инструмент для команд, которые всерьез занимаются обеспечением отказоустойчивости (Resiliency Testing) и хаос-инжинирингом.
Если вы пишете микросервисы, которые зависят друг от друга, или ваше приложение активно общается с внешними API — попробуйте интегрировать Toxiproxy в свои интеграционные тесты. Это позволит вам не просто «надеяться», что тайм-ауты настроены верно, а доказать это на практике.
Спокойный сон разработчика начинается там, где заканчивается неуверенность в сетевых соединениях. И Toxiproxy — отличный способ эту уверенность обрести.
