Какие этапы измеряет curl
Когда страница грузится медленно, фраза «сайт тормозит» ничего не говорит. Задержка может возникать при поиске адреса по имени, при установлении соединения, при согласовании шифрования, при ожидании ответа приложения или уже при передаче данных. curl умеет разложить запрос на этапы, и для этого не нужны сторонние программы.
Все времена в переменных — накопительные, в секундах, от начала запроса. Это важно: time_connect включает в себя время time_namelookup, поэтому этап «чистого» соединения получают вычитанием.
| Переменная | Что означает |
|---|---|
| time_namelookup | Сколько прошло до завершения разрешения имени |
| time_connect | До завершения TCP-соединения |
| time_appconnect | До завершения TLS-рукопожатия (для https) |
| time_pretransfer | До готовности начать передачу |
| time_redirect | Время, потраченное на все перенаправления |
| time_starttransfer | До получения первого байта ответа |
| time_total | Полное время запроса |
| speed_download | Средняя скорость загрузки, байт в секунду |
| size_download | Сколько байт получено |
Готовая команда и как её читать
Самый удобный способ — вынести формат в файл. Создайте curl-format.txt, где каждая строка выглядит как "dns: %{time_namelookup}\n" и далее аналогично для connect, appconnect, starttransfer и total. Запуск: curl -s -o /dev/null -w и затем знак @, сразу за которым идёт имя файла формата (curl-format.txt), после чего адрес. Знак @ говорит curl прочитать формат из файла. Можно записать и в одну строку: -w "dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} first=%{time_starttransfer} total=%{time_total}\n".
Пример вывода (пример): dns=0.021 tcp=0.048 tls=0.112 first=0.190 total=0.205. Считаем разности: имя разрешилось за 21 мс, соединение заняло 27 мс, TLS 64 мс, ожидание ответа приложения 78 мс, передача тела 15 мс. Значения условные и показывают лишь способ расчёта.
Для http без шифрования time_appconnect равен нулю, это нормально. При использовании -L времена относятся к последнему звену, но time_redirect показывает суммарное время предыдущих.
Что означает каждая большая разница
Перейдём от чисел к причинам. Смотрите на то, какой из участков непропорционально велик.
- Долгий time_namelookup при остальных нормальных этапах — медленный DNS-сервер, пустой кэш, недоступный первый из списка серверов. Проверьте другой резолвер через dig и сравните.
- Большой участок между namelookup и connect — сама сеть: далёкий сервер, потери пакетов, перегрузка канала. Сопоставьте с ping и mtr.
- Большой участок между connect и appconnect — медленное TLS-рукопожатие: цепочка сертификатов, старый узел, проверка отзыва.
- Долгий промежуток между pretransfer и starttransfer — сервер долго готовит ответ: нагрузка на приложение, база данных, кэш.
- Разница между starttransfer и total велика — тело большое или скорость канала мала; сверьте с speed_download.
Результат измерений нестабилен, поэтому одного запуска мало. Выполните 5–10 проб подряд и сравнивайте медианные значения, а не лучшее или худшее. Первое обращение всегда медленнее из-за кэшей DNS и нового TLS-соединения.
Повторные замеры и сравнение
В Linux и macOS цикл выглядит так: for i in 1 2 3 4 5; do curl -s -o /dev/null -w "%{time_total}\n" адрес; sleep 1; done. В PowerShell: 1..5 | ForEach-Object { curl.exe -s -o NUL -w "%{time_total}\n" адрес; Start-Sleep 1 }. Пауза между попытками нужна, чтобы не создавать нагрузку на проверяемый сервер и не ловить ограничения по частоте.
Чтобы сравнить два пути к одному серверу, пригодится ключ --resolve: он подставляет адрес вместо ответа DNS, например --resolve example.com:443:198.51.100.10. Тогда этап DNS исключается, а вы сравниваете именно соединение с конкретным узлом. Адрес в примере взят из блока документации и подставьте свой.
Ключ --http1.1 и --http2 помогает выяснить, влияет ли версия протокола на скорость, а -4 и -6 заставляют использовать IPv4 или IPv6. Разница между ними иногда объясняет, почему часть клиентов ждёт лишние секунды: имя разрешается в оба типа адреса, а IPv6 не работает.
Ограничения метода
curl измеряет время от вашего компьютера до сервера с вашей точкой входа в сеть, а не «скорость сайта вообще». На результат влияют Wi-Fi, нагрузка на компьютер, антивирус, проверяющий соединения, и промежуточные кэши. Для оценки пропускной способности канала лучше подходят специальные утилиты, а не загрузка одной страницы: размер небольшой, и скорость не успевает разогнаться.
Не запускайте частые замеры по чужим ресурсам. Для проверки собственного сайта разумно делать это из нескольких мест и в разное время суток. Значение time_starttransfer часто называют TTFB и используют как основную метрику отзывчивости сервера, а time_total лучше сравнивать при одинаковом размере ответа.
Практический порядок диагностики медленной страницы
Когда нужно быстро понять, что не так, действуйте по порядку. Сначала выполните три-четыре замера подряд и убедитесь, что задержка воспроизводится. Затем сверьте этап DNS: если он занимает десятки миллисекунд и более, попробуйте запрос с другим резолвером и сравните, а также посмотрите, не выдаёт ли имя несколько адресов, часть из которых недоступна. После этого оцените соединение: сопоставьте time_connect с результатом ping до того же узла — они должны быть близки, ведь TCP-рукопожатие занимает примерно одно круговое время.
Если ping и time_connect расходятся сильно, между вами и сервером есть фильтр или балансировщик, отвечающий вместо самого узла. Следом идёт TLS: разница между time_appconnect и time_connect обычно составляет одно–два круговых времени. Слишком большое значение указывает на медленный узел терминирования шифрования или на дальний сервер.
Наконец, ожидание первого байта: если оно составляет сотни миллисекунд при быстром соединении, медленно работает приложение. Тут вам нужно не сетевое, а серверное решение, и сообщить о проблеме стоит владельцу сайта, приложив числа замеров и время. Фиксируйте время и адрес, с которого мерили, — без этого сравнение бесполезно.