# 12. Отладка и проблемы производительности

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

---

Индекс LLMS: [llms.txt](/ru/llms.txt)

---

<!-- Generated by scripts/generate-haproxy-docs.py from pinned upstream text. -->

При запуске HAProxy с параметром «-d» процесс остаётся на переднем плане и выводит по строке на каждое событие — входящее соединение, завершение соединения, каждую встреченную строку заголовка запроса или ответа. Этот отладочный вывод формируется до обработки содержимого, поэтому локальные изменения в нём не учитываются. Основное назначение — показывать запросы и ответы без запуска анализатора сетевого трафика. При одновременной обработке нескольких соединений вывод читается хуже, но скрипты «debug2ansi» и «debug2html» из каталога examples/ заметно помогают, раскрашивая его.

Если HAProxy отклоняет запрос или ответ HTTP/1.x как некорректный, лучше всего подключиться к CLI и выполнить «show errors». Команда показывает последние сохранённые ошибочные запрос и ответ HTTP/1.x для каждого фронтенда и бэкенда, включая все сведения для точного определения первого отклонённого символа входного потока. Иногда это необходимо, чтобы доказать заказчикам или разработчикам наличие ошибки в их коде. В таком случае часто можно ослабить проверки, сохранив захват ошибок, с помощью «option accept-unsafe-violations-in-http-request» или аналогичного параметра для ответов сервера «option accept-unsafe-violations-in-http-response». Подробнее см. руководство по конфигурации.

Пример:

```shell
> show errors
Total events captured on [13/Oct/2015:13:43:47.169]: 1

[13/Oct/2015:13:43:40.918] frontend HAProxyLocalStats (#2): invalid request
  backend <NONE> (#-1), server <NONE> (#-1), event #0
  src 127.0.0.1:51981, session #0, session flags 0x00000080
  HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
  HTTP chunk len 0 bytes, HTTP body len 0 bytes
  buffer flags 0x00808002, out 0 bytes, total 31 bytes
  pending 31 bytes, wrapping at 8040, error at position 13:

  00000  GET /invalid request HTTP/1.1\r\n

```

Вывод команды «show info» в CLI содержит полезные сведения о максимальной достигнутой интенсивности соединений, максимальной достигнутой скорости вычисления ключей SSL и в целом информацию, помогающую объяснить временные проблемы с использованием CPU или памяти. Пример:

```shell
> show info
Name: HAProxy
Version: 1.6-dev7-e32d18-17
Release_date: 2015/10/12
Nbproc: 1
Process_num: 1
Pid: 7949
Uptime: 0d 0h02m39s
Uptime_sec: 159
Memmax_MB: 0
Ulimit-n: 120032
Maxsock: 120032
Maxconn: 60000
Hard_maxconn: 60000
CurrConns: 0
CumConns: 3
CumReq: 3
MaxSslConns: 0
CurrSslConns: 0
CumSslConns: 0
Maxpipes: 0
PipesUsed: 0
PipesFree: 0
ConnRate: 0
ConnRateLimit: 0
MaxConnRate: 1
SessRate: 0
SessRateLimit: 0
MaxSessRate: 1
SslRate: 0
SslRateLimit: 0
MaxSslRate: 0
SslFrontendKeyRate: 0
SslFrontendMaxKeyRate: 0
SslFrontendSessionReuse_pct: 0
SslBackendKeyRate: 0
SslBackendMaxKeyRate: 0
SslCacheLookups: 0
SslCacheMisses: 0
CompressBpsIn: 0
CompressBpsOut: 0
CompressBpsRateLim: 0
ZlibMemUsage: 0
MaxZlibMemUsage: 0
Tasks: 5
Run_queue: 1
Idle_pct: 100
node: wtap
description:
```

Если в новой версии HAProxy проблема возникает как будто случайно (например, прерывается каждый второй запрос или изредка происходит аварийное завершение), стоит попробовать включить заполнение памяти контрольным значением: тогда сразу после каждого вызова malloc() выделенная область заполняется заданным байтом. По умолчанию используется байт 0x50 (ASCII-код 'P'), но можно выбрать любой другой, в том числе нулевой (это даёт тот же эффект, что calloc(), и может скрыть проблему). Заполнение памяти включается параметром командной строки «-dM». Оно немного снижает производительность и не рекомендуется для рабочей среды. Если с ним проблема возникает всегда либо никогда не возникает при заполнении нулями, это явно указывает на ошибку, о которой обязательно следует сообщить. Если заметных изменений нет, проблема с этим не связана.

При отладке задержек важно использовать и strace, и tcpdump на локальной машине, а также ещё один tcpdump на удалённой системе. Задержки возникают на всех этапах обработки, и нужно установить, какой именно этап их вызывает, чтобы понять, где вмешаться. На практике локальный tcpdump показывает время поступления входящих данных. Strace показывает, когда haproxy получает эти данные через recv/recvfrom. Внимание: OpenSSL использует системные вызовы read()/write() вместо recv()/send(). Strace также показывает, когда haproxy отправляет данные, а tcpdump — когда система передаёт их интерфейсу. Затем внешний tcpdump показывает, когда отправленные данные действительно получены (локальный показывает только постановку пакетов в очередь). Преимущество захвата трафика в локальной системе состоит в том, что strace и tcpdump используют одни и те же часы. Strace следует запускать с «-tts200», чтобы получать полные временные метки и достаточно большие для чтения фрагменты данных. Tcpdump следует запускать с «-nvvttSs0», чтобы видеть полные пакеты, реальные номера последовательности и полные временные метки.

На практике поступившие данные почти всегда сразу получает haproxy, если только CPU машины не перегружен либо данные некорректны и потому не доставляются. Если данные получены, но не отправлены, причина обычно в заполнении выходного буфера: получатель недостаточно быстро читает данные. Это можно подтвердить, заметив, что механизм опроса некоторое время не сообщает о возможности записи в выходной файловый дескриптор. Часто проще найти в выводе strace момент, когда данные наконец отправлены, а затем просмотреть более ранние события и установить, когда поступило уведомление о готовности к записи. Обычно оно совпадает с получением ACK от адресата, видимым в tcpdump. После отправки данные могут некоторое время бездействовать внутри системы. И здесь окно перегрузки TCP может быть ограничено и не позволять отправить данные до получения ACK, открывающего окно. Если трафик отсутствует, а отправка данных задерживается на 40 ms или 200 ms, причина иная и фактически не является неисправностью: алгоритм Нейгла не позволяет немедленно отправлять пустые пакеты в надежде объединить их с последующими данными. HAProxy автоматически отключает алгоритм Нейгла в чистом режиме TCP и в туннелях. Однако при пересылке тела HTTP он остаётся включённым, повышая производительность за счёт уменьшения числа пакетов. Некоторые приложения, не соответствующие HTTP, могут быть чувствительны к задержке доставки неполных ответов HTTP. В таком случае нужно включить «option http-no-delay», чтобы отключить алгоритм Нейгла и обойти особенности их реализации. При этом следует помнить, что любой другой прокси в цепочке может столкнуться с тем же эффектом. Если tcpdump показывает немедленную отправку данных, но другая сторона получает их с задержкой, причиной может быть перегруженный канал WAN, перегруженная локальная сеть с включённым управлением потоком, препятствующим отправке, либо, что встречается чаще, работа HAProxy в виртуальной машине, гипервизор которой по какой-то причине решил отложить отправку данных. В виртуализированных средах задержки почти всегда вызваны слоем виртуализации, поэтому для экономии времени стоит сначала сравнить tcpdump внутри виртуальной машины и на внешних компонентах. Любую разницу следует относить к гипервизору и сопутствующим драйверам.

Если в трассировке tcpdump с параметром -vv видны сегменты TCP SACK, это всегда означает, что отправившая их сторона получила подтверждение потери пакета. Отсутствие SACK не доказывает отсутствие потерь, но их наличие определённо указывает на потери в сети. Потери в сети нормальны, однако их частота должна быть такой, чтобы SACK не бросались в глаза. Если они часто встречаются в трассировке, стоит точно выяснить, что происходит и где теряются пакеты. HTTP плохо переносит потери TCP, поскольку они вызывают огромные задержки.

Команда «netstat -i» выводит статистику по интерфейсам. Рост счётчика Rx-Ovr означает, что системе не хватает ресурсов для приёма всех входящих пакетов и они теряются ещё до обработки сетевым драйвером. Rx-Drp показывает потери уже полученных пакетов в сетевом стеке из-за того, что приложение недостаточно быстро их обрабатывает. Такое возможно и при некоторых атаках. Tx-Drp означает, что выходные очереди заполнены и пакеты пришлось отбросить. При использовании TCP это должно происходить очень редко, но может указывать на перегрузку исходящего канала.
