Toxiproxy на VPS: как проверить приложение при медленной базе и обрыве связи
«Если база недоступна, покажем сообщение об ошибке». Это хороший план — пока не выясняется, что база доступна, но отвечает сорок секунд. Пользователь нажимает кнопку ещё раз, сервер копит соединения, а сообщение об ошибке появляется уже после третьего созданного заказа.
Такие ситуации трудно исследовать обычным выключением контейнера. Полный отказ заметен сразу; медленная или оборванная в неудобный момент связь ведёт себя хитрее. Toxiproxy позволяет вставить управляемую помеху между приложением и зависимостью: задержать ответ, ограничить поток или оборвать соединение.
Проведём учебный эксперимент на отдельном VPS. Его цель — выяснить, что увидит пользователь и что останется в данных после сбоя. Проверять таким способом рабочую базу без специально подготовленного плана не требуется: для первого полезного результата достаточно копии приложения и обезличенных записей.
Содержание
- Что именно мы ломаем
- Подготовка опыта занимает меньше времени, чем разбор дублей
- Создаём управляемый участок связи
- Опыт первый: ответ приходит слишком поздно
- Опыт второй: соединение оборвалось посередине
- Опыт третий: зависимость вернулась, а очередь ещё нет
- Что положить в отчёт команды
- VPS для такой лаборатории
Отдельный VPS для испытания сбоев
Разверните копию приложения и тестовую базу, чтобы проверить задержки и обрывы связи в управляемых условиях. Toxiproxy устанавливается самостоятельно.
Выбрать VPS для тестового стендаЧто именно мы ломаем
Toxiproxy работает как TCP-посредник. Приложение подключается к нему, а он — к тестовой базе. Управляющий HTTP-интерфейс добавляет или удаляет условия сбоя. Устройство инструмента и поддерживаемые воздействия описаны в репозитории Shopify.
Для нашего стенда PostgreSQL слушает 127.0.0.1:5432, посредник принимает подключения на 127.0.0.1:15432, а приложение использует второй адрес. Управление Toxiproxy доступно только локально на порту 8474. Снаружи открыт лишь защищённый вход в тестовое приложение, если он вообще нужен.
Это важное различие: мы изменяем один маршрут, а не отключаем сеть целиком. SSH остаётся работоспособным, мониторинг видит сервер, остальные зависимости можно оставить в обычном состоянии. Благодаря этому наблюдаемая ошибка имеет понятную причину.
В контейнерной схеме адреса будут другими. 127.0.0.1 внутри контейнера относится к самому контейнеру; для соседнего сервиса обычно используют его имя во внутренней сети. Не переносите приведённые адреса в Compose без изменения схемы подключения.
Подготовка опыта занимает меньше времени, чем разбор дублей
Создайте тестовую базу и пользователя с правами только на неё. В приложении замените почту, платежи и другие реальные действия на песочницы. Придумайте узнаваемый префикс тестовых объектов и уникальный идентификатор операции. По нему позже можно будет найти результат, даже если клиент не получил ответ.
Перед вмешательством выполните обычный сценарий и запишите его длительность, HTTP-ответ и запись в базе. Затем повторите через посредник без добавленных помех. Если второй вариант уже не работает, исследовать задержки рано: сначала исправьте маршрут, аутентификацию и проверку TLS.
Если драйвер проверяет имя сервера в сертификате PostgreSQL, промежуточный адрес не повод отключать проверку сертификатов. Для libpq параметры host и hostaddr позволяют отдельно определить имя и сетевой адрес, но конкретное применение зависит от клиента. Поведение соединений описано в документации PostgreSQL. Настройте тестовый маршрут с сохранением требуемой проверки подлинности.
Заранее задайте ожидаемый результат. Например: при недоступной базе форма отвечает понятной ошибкой в пределах согласованного времени, повтор не создаёт второй заказ, после восстановления связи приложение работает без ручного перезапуска. Это условия эксперимента, которые команда выбирает под продукт, а не универсальные нормативы.
Создаём управляемый участок связи
Установите подходящий бинарный выпуск Toxiproxy из официального репозитория и зафиксируйте версию стенда. Для локального процесса управляющий адрес можно указать явно:
toxiproxy-server -host=127.0.0.1 -port=8474
В другой сессии создайте посредника для тестовой базы:
curl --fail-with-body -sS -X POST http://127.0.0.1:8474/proxies \
-H 'Content-Type: application/json' \
--data '{"name":"shop_test_pg","listen":"127.0.0.1:15432","upstream":"127.0.0.1:5432","enabled":true}'
После этого настройте тестовое приложение на порт 15432 и заново откройте его подключения. Уже существующий пул прямых соединений может продолжить обходить посредника. Проверьте фактический маршрут, прежде чем делать вывод «система спокойно пережила сбой».
Управляющий интерфейс не публикуйте в интернет. Если используете Docker, отдельно проверьте адрес публикации порта: привязка к 0.0.0.0 и привязка к localhost имеют разный смысл. Это разобрано в документации Docker по портам. Доступ к управлению помехами должен оставаться у того, кто проводит эксперимент.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
АРЕНДОВАТЬ СЕРВЕРОпыт первый: ответ приходит слишком поздно
Добавим задержку на направлении от базы к приложению:
curl --fail-with-body -sS -X POST \
http://127.0.0.1:8474/proxies/shop_test_pg/toxics \
-H 'Content-Type: application/json' \
--data '{"name":"slow_reply","type":"latency","stream":"downstream","toxicity":1,"attributes":{"latency":800,"jitter":100}}'
Значения в примере заданы для опыта: задержка 800 миллисекунд с разбросом 100. Это не результат измерения какого-либо провайдера. Помеха действует на поток, поэтому операция с несколькими обменами может замедлиться сильнее, чем на одни 800 миллисекунд.
Откройте карточку товара, отправьте форму, выполните поиск. Смотрите, растёт ли число занятых соединений, сколько времени ждёт пользователь и прекращается ли ненужная работа после клиентского тайм-аута. Если браузер сдался через пять секунд, база вполне может продолжать выполнять запрос.
Полезно сравнить два действия: чтение и создание записи. Для чтения допустим повтор при определённых условиях. Для изменения данных автоматический повтор требует понимания, завершилась ли первая попытка. Одинаковая политика для обоих случаев часто и создаёт дубли.
Удалите именно добавленную помеху и проверьте возврат нормальной скорости:
curl --fail-with-body -sS -X DELETE \
http://127.0.0.1:8474/proxies/shop_test_pg/toxics/slow_reply
Опыт второй: соединение оборвалось посередине
Следующий опыт проводите отдельно, после очистки первого. Добавьте воздействие reset_peer с выбранной задержкой до сброса соединения, следуя параметрам установленной версии. Меняйте момент обрыва относительно начала операции и сохраняйте идентификатор каждого тестового заказа.
Здесь главный вопрос звучит не «получили ли мы ошибку», а «известно ли, что случилось с записью». При обрыве после отправки команды, но до получения подтверждения клиент может не знать исход операции. Повторный запрос должен сверяться с устойчивым идентификатором и правилами приложения.
Проверьте также транзакцию из нескольких действий. Например, создание заказа и резервирование остатка должны оставаться согласованными согласно вашей модели данных. Ошибка между ними не должна оставлять заказ, который существует только наполовину.
После снятия воздействия убедитесь, что пул соединений умеет заменить повреждённые подключения. Иногда сеть уже восстановилась, а приложение продолжает выдавать ошибки, потому что удерживает непригодные соединения. Перезапуск скрывает симптом, но не исправляет поведение клиента.
Опыт третий: зависимость вернулась, а очередь ещё нет
Короткий сбой может накопить много отложенной работы. После восстановления все исполнители одновременно повторяют запросы и создают второй пик нагрузки. Поэтому наблюдайте не только период отказа, но и последующие минуты.
У повторов должны быть ограничения: число попыток, общий срок и пауза с разбросом. Если каждый клиент повторяет строго через одну секунду, они с завидной дисциплиной снова приходят вместе. Так получается маленький оркестр, играющий на базе данных одной и той же нотой.
Проверьте, сохраняется ли порядок там, где он важен. Обновление статуса «отправлен» не должно быть затёрто запоздавшим повтором «принят». Сам сетевой инструмент не решает эту задачу; он помогает воспроизвести ситуацию и увидеть недостаток бизнес-логики.
В инженерном разборе Shopify полезна сама постановка вопроса: зависимость может отказать, а приложение должно иметь заранее определённое поведение. Для одних данных допустим временный отказ от необязательной функции, для других необходим явный отказ всей операции.
Что положить в отчёт команды
Для каждого опыта сохраняйте конфигурацию помехи, время начала и завершения, идентификаторы запросов, наблюдение пользователя и итоговые записи в базе. Не включайте реальные пароли и персональные данные. Отдельно отмечайте, понадобилось ли ручное вмешательство после снятия сбоя.
Хороший отчёт превращается в конкретные изменения: добавить тайм-аут, ограничить повторы, защитить запись от дубля, исправить восстановление пула. Формулировка «приложение нестабильно» слишком широка; «после разрыва все соединения пула остаются неисправными» уже указывает направление работы.
Когда ошибка исправлена, повторите тот же сценарий. Позже включите воспроизведение в проверку выпуска, если оно достаточно быстро и предсказуемо. Случайный хаос полезен не на первом шаге: сначала нужен маленький опыт, который команда умеет объяснить и повторить.
VPS для такой лаборатории
Если тестовое приложение небольшое, для начала можно взять MAATRIX Uab Start с 2 vCPU и 4 ГБ памяти. Для приложения, PostgreSQL и более заметной параллельной нагрузки удобнее проверить Heka Standard с 4 vCPU и 8 ГБ. Эти конфигурации — варианты стенда, а не оценка мощности рабочей системы.
Ресурсов должно хватать, чтобы непреднамеренный дефицит памяти не смешивался с моделируемой сетевой проблемой. Генератор существенной нагрузки лучше разместить отдельно. Сам Toxiproxy устанавливается самостоятельно; он не требует переносить производственную базу на этот сервер.
После испытаний снимите все воздействия, верните исходную конфигурацию стенда и убедитесь, что обычный сценарий снова проходит. Управляемая авария полезна именно тем, что у неё есть начало, наблюдаемый результат и проверенное завершение.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
АРЕНДОВАТЬ СЕРВЕРОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →