Скорость прокси и время отклика: как измерить правильно
Время отклика и скорость передачи это две разные величины, и меряются они по-разному. Отклик показывает, сколько прошло от отправки запроса до первого байта ответа, и считается в миллисекундах. Скорость показывает, сколько байт в секунду идёт после первого байта, и считается в мегабитах. Корректный замер снимается серией из нескольких десятков запросов на свой целевой домен с разбором по фазам через curl -w, после чего берётся медиана и разброс.
Дальше разобрано, из каких кусков складывается задержка, как снять все величины одной командой, зачем нужна серия, как мерить под нагрузкой в несколько потоков, что портит замер до полной непригодности, как перевести полученные цифры в число потоков для прогона и как отличить медленный посредник от медленного целевого сайта.
Отклик и скорость: почему их путают
Фраза «прокси медленный» почти всегда означает отклик. Человек открыл страницу, она думала пару секунд, и вывод готов. При этом сама страница потом загрузилась мгновенно, потому что после первого байта канал отработал на полную. Отклик и пропускная способность живут отдельно друг от друга, и узкое место у них разное.
Разница видна на простом примере. Канал в сто мегабит с откликом в 700 миллисекунд отдаёт страницу в сто килобайт примерно за 710 миллисекунд: почти всё время ушло на ожидание. Канал в десять мегабит с откликом в 60 миллисекунд отдаст ту же страницу за 140 миллисекунд. На мелких объектах побеждает отклик. На выгрузке архивов и картинок побеждает канал.
Отсюда практическое правило замера. Для парсинга страниц и работы с кабинетами меряем отклик и его разброс, потому что общая длительность прогона складывается из тысяч ожиданий. Для выгрузки крупных объектов меряем скорость передачи тела. Обе величины снимаются одной командой, поэтому спорить о том, какая важнее, незачем: берём обе и смотрим на свою задачу.
Мы разводим эти две величины с первого разговора, потому что от этого зависит, что вообще мерить. Вопрос «какая у вас скорость» без уточнения ответа не имеет: у одного и того же узла отклик на лёгкой странице и скорость выгрузки архива ведут себя совершенно по-разному. Спрашиваем, что именно идёт в работу, и дальше берём подходящий инструмент замера.
Третья величина стоит рядом и путается с первыми двумя. Это пропускная способность прогона в запросах за час. Она вычисляется из отклика и числа потоков, и именно она отвечает на вопрос «успеем ли за ночь». Одиночный отклик сам по себе на этот вопрос не отвечает.
Из чего складывается задержка
Задержка одного запроса собирается из четырёх последовательных кусков. Каждый меряется отдельно, и это главное преимущество разбора по фазам: узкое место видно сразу, гадать не приходится.
| Фаза | Как получить из curl | Что происходит | От чего зависит |
|---|---|---|---|
| Разбор имени | time_namelookup | Домен превращается в адрес | Настройки службы имён, локальный кеш |
| Установка соединения | time_connect минус time_namelookup | Тройное рукопожатие TCP до посредника | Расстояние до узла и качество маршрута |
| Рукопожатие шифрования | time_appconnect минус time_connect | Туннель CONNECT и согласование TLS до площадки | Версия протокола, число обменов, загрузка сторон |
| Ожидание первого байта | time_starttransfer минус time_pretransfer | Площадка приняла запрос и готовит ответ | Скорость самого сайта и его очередь |
| Передача тела | time_total минус time_starttransfer | Ответ идёт по каналу | Размер ответа и пропускная способность |
Первые три куска относятся к пути и к посреднику. Четвёртый относится к площадке. Пятый относится к каналу и к объёму. Разделение работает безотказно: если общее время выросло, достаточно посмотреть, какая из пяти величин прибавила, и разговор сразу становится предметным.
Одна особенность касается работы через посредника. Величина time_connect при ключе -x показывает соединение до узла, а time_appconnect включает открытие туннеля и рукопожатие с площадкой внутри него. Поэтому на HTTPS фаза шифрования выглядит крупнее, чем при прямом обращении: в неё входит лишний обмен с посредником. Устройство самого туннеля разобрано в материале про туннель CONNECT.
Разбор имени в серии обычно нулевой начиная со второго запроса: адрес уже лежит в локальном кеше. При схеме socks5h имя разбирает узел, и эта фаза уходит внутрь фазы соединения целиком.
Замер через curl -w: полный набор величин
Все величины снимаются одной командой. Формат вывода удобнее держать отдельным файлом: строка получается длинной, и править её каждый раз утомительно.
# fmt.txt: формат вывода для curl -w
dns %{time_namelookup}
connect %{time_connect}
tls %{time_appconnect}
pretransfer %{time_pretransfer}
ttfb %{time_starttransfer}
total %{time_total}
size %{size_download} байт
speed %{speed_download} байт/с
code %{http_code}
redirects %{num_redirects}
Дальше замер запускается в одну строку:
curl -s -o /dev/null -w @fmt.txt \
--max-time 30 \
-x http://91.208.63.22:8000 \
https://shop.example.net/catalog/page/17
Типовой вывод по рабочему узлу выглядит так:
dns 0.004
connect 0.071
tls 0.243
pretransfer 0.243
ttfb 0.612
total 0.688
size 146820 байт
speed 213401 байт/с
code 200
redirects 0
Читается он по разностям. Соединение до узла заняло 67 миллисекунд, рукопожатие добавило 172, площадка думала 369 миллисекунд, тело в 143 килобайта пришло за 76 миллисекунд. Узкое место здесь стоит на стороне площадки, и никакая смена узла его не уберёт.
Сравнительная проба снимается тем же форматом без ключа -x. Два вывода рядом отвечают на вопрос о накладных расходах посредника точнее любых рассуждений.
curl -s -o /dev/null -w @fmt.txt --max-time 30 https://shop.example.net/catalog/page/17
Разница по ttfb между прямым и проксированным запросом это и есть цена посредника на этом маршруте. Величины в пределах сотни миллисекунд считаются рабочими для серверных узлов, потому что трафик идёт через дополнительный пункт и физику маршрута никто не отменял.
Ключ --max-time держим обязательным во всех замерах. Без него зависший запрос стоит до системного таймаута и портит серию длиной в несколько минут вместо честного обрыва. Значение берём с двойным запасом от ожидаемого времени: тридцать секунд для страниц каталога, минуту для тяжёлых объектов. Ключ -o /dev/null тоже нужен всегда, иначе тело ответа сыплется в терминал и мешается с цифрами. Проверить, что связка вообще отвечает, удобно до замера, порядок такой пробы разобран отдельно. Сами узлы, по которым мы гоняем эти пробы, входят в общий пакет, где оформляется доступ к пулу IPv4 и SOCKS5.
Одно измерение ничего не значит
Единственный замер сообщает погоду на секунду. Ротация внутри пула автоматическая, поэтому следующий запрос уйдёт с другого выхода, и время у него будет своё. Разговор о скорости начинается с серии в тридцать и больше запросов.
for i in $(seq 1 30); do
curl -s -o /dev/null --max-time 20 -w '%{time_starttransfer} %{time_total} %{http_code}\n' \
-x http://91.208.63.22:8000 "https://shop.example.net/catalog/page/$i"
done > series.txt
Среднее по такой серии почти бесполезно: пара долгих ответов тянет его вверх и картина смазывается. Берём медиану и края.
sort -n series.txt | awk '{a[NR]=$1} END {
printf "мин %.3f медиана %.3f p90 %.3f макс %.3f запросов %d\n",
a[1], a[int(NR*0.5)+1], a[int(NR*0.9)], a[NR], NR
}'
Пример вывода: мин 0.402 медиана 0.611 p90 0.940 макс 2.310 запросов 30. Медиана отвечает за типовое поведение, p90 отвечает за то, сколько ждать в худших случаях, максимум показывает наличие выбросов. Разброс между медианой и p90 важнее самой медианы: связка с медианой в 600 миллисекунд и p90 в 700 предсказуема, связка с той же медианой и p90 в две с половиной секунды заставит прогон стоять на длинных ответах.
Долю успешных ответов считаем той же серией, по третьему полю.
awk '{print $3}' series.txt | sort | uniq -c | sort -rn
Вывод вида 28 200 и 2 000 читается однозначно: двадцать восемь ответов с кодом 200 и два обрыва без кода. Доля успешных и медиана отклика это та пара цифр, по которой связка допускается к работе. Ровные серии на длинной дистанции держат серверные прокси на собственном оборудовании: маршрут у них предсказуемый, и разброс между медианой и p90 остаётся узким от первого запроса до последнего.
Первый запрос серии стоит отбросить. В нём сидит разбор имени, установка соединения с нуля и прогрев маршрута, поэтому он всегда выпадает из ряда и портит статистику на выборке из тридцати штук.
Замер под нагрузкой в несколько потоков
Последовательная серия описывает поведение одного канала. Боевой прогон идёт в десятки потоков, и там начинается другая физика: очереди на стороне площадки, ограничения по частоте, конкуренция за канал. Поэтому после последовательной серии всегда снимаем параллельную.
# 200 запросов в 20 потоков, каждая строка это время и код
seq 1 200 | xargs -P 20 -I{} \
curl -s -o /dev/null --max-time 30 -w '%{time_starttransfer} %{http_code}\n' \
-x http://91.208.63.22:8000 "https://shop.example.net/catalog/page/{}" > load20.txt
awk '{s+=$1; n++} END {printf "среднее %.3f на %d запросов\n", s/n, n}' load20.txt
awk '{print $2}' load20.txt | sort | uniq -c | sort -rn
Замер повторяется на нескольких уровнях параллельности: 5, 10, 20, 40, 80. Получается ряд, по которому видно, где площадка перестаёт держать темп.
| Потоков | Медиана отклика | Доля кода 200 | Как читается |
|---|---|---|---|
| 5 | 0.61 | 100% | Запас есть, поднимаем дальше |
| 10 | 0.63 | 100% | Отклик держится, площадка не замечает нагрузки |
| 20 | 0.72 | 99% | Рабочая точка, отклик подрос слегка |
| 40 | 1.35 | 94% | Очередь на стороне площадки, появились отказы |
| 80 | 3.90 | 61% | Ограничение по частоте, дальше поднимать бессмысленно |
Рабочей точкой берём последний уровень, где доля успешных держится около сотни процентов при умеренном росте отклика. В примере это двадцать потоков. Дальше рост параллельности удлиняет прогон: время каждого запроса растёт быстрее, чем прибавляется параллельных каналов.
Отдельный момент про лимиты пакета. Стандартные пакеты дают до 1000 потоков, корпоративный до 3000, при двух привязанных адресах общее число делится между ними пополам. Замер под нагрузкой упирается в ограничение площадки задолго до этих величин, поэтому цифра из таблицы описывает поведение сайта, потолок доступа лежит заметно выше. Состав пакета по потокам и привязкам разобран отдельно в материале про то, что входит в пакет.
Мы снимаем такой ряд на каждом новом целевом домене, и занимает он минут десять. Полученная рабочая точка потом переносится в настройки софта один раз, дальше прогон идёт на ней без правок. Повторяем ряд, когда площадка меняет поведение: рост доли отказов на прежней параллельности это первый признак того, что пороги на её стороне сдвинулись.
Что портит замер
Испорченный замер хуже отсутствующего: по нему принимают настройки, и потом прогон ведёт себя непонятно. Ошибок немного, все они повторяются.
| Что сделали | Что получилось | Как мерить правильно |
|---|---|---|
| Замер на общем чекере скорости | Померили чужой сервис и путь до него | Мерить на своём целевом домене |
| Взяли один запрос | Поймали случайную точку ряда | Серия от тридцати запросов, медиана и p90 |
| Оставили первый запрос в выборке | Прогрев маршрута ушёл в статистику | Отбросить первый результат |
| Дёргали один и тот же адрес страницы | Второй ответ пришёл из кеша площадки | Разные адреса либо параметр против кеширования |
Гоняли curl с несколькими адресами в одной команде | Соединение переиспользовалось, отклик занижен | Отдельный вызов на каждый запрос |
| Мерили по HTTP, работать будете по HTTPS | Фаза рукопожатия выпала из подсчёта | Замер тем же протоколом, что и прогон |
| Брали страницу в пару килобайт | Скорость передачи посчитать не по чему | Взять объект того размера, что в работе |
| Мерили с домашней машины по беспроводной сети | В цифры вошёл свой последний участок | Замер с серверной машины |
| Не смотрели на коды ответов | Часть строк это отказы с быстрым временем | Считать медиану только по коду 200 |
| Сравнивали замеры разных часов | Нагрузка на площадке гуляет по суткам | Прямой и проксированный замер подряд |
Про кеш стоит сказать подробнее, потому что эта ошибка встречается чаще прочих. Площадка отдаёт повторный запрос из кеша за десятки миллисекунд, и серия из тридцати обращений к одному адресу страницы показывает медиану вчетверо ниже настоящей. Лечится это перебором адресов, как в примерах выше, либо параметром против кеширования в конце строки. Свой локальный кеш ведёт себя так же: time_namelookup со второго запроса падает в ноль, и это нормально, потому что в боевом прогоне имя разбирается один раз на всю пачку.
Последняя строка таблицы важнее остальных. Любое сравнение делается парой замеров, снятых подряд в пределах минуты: прямой и через посредника. Замер, снятый вчера, сравнивать с сегодняшним бесполезно, потому что за сутки успевает поменяться и загрузка площадки, и маршрут.
Ещё одна ловушка сидит в кодах ответов. Отказ по коду 403 приходит быстро, и такие строки занижают медиану на десятки процентов при полностью нерабочем прогоне. Поэтому фильтруем выборку по коду перед подсчётом, а разбор самих отказов вынесен в материал про ошибку 403 при работе через прокси.
Как перевести замеры в число потоков
Цифры из замера превращаются в настройку прогона одной формулой. Требуемая скорость в запросах за секунду умножается на медианное время отклика в секундах, и получается число одновременных потоков.
Считаем на живом примере. Нужно собрать 300 000 карточек за десять часов. Это 30 000 запросов в час, то есть 8,3 запроса в секунду. Медиана отклика по замеру 1,2 секунды. Умножаем: 8,3 на 1,2 даёт ровно 10 потоков. Прибавляем треть на выбросы и длинные ответы, получаем 13. Проверяем по таблице нагрузки: рабочая точка держалась до двадцати потоков, значит настройка проходит с запасом.
| Задача | Объём и срок | Требуемая скорость | Медиана отклика | Потоков с запасом |
|---|---|---|---|---|
| Каталог поставщика за ночь | 60 000 страниц за 8 часов | 2,1 в секунду | 0,9 с | 3 |
| Прайсы конкурентов днём | 120 000 страниц за 6 часов | 5,6 в секунду | 0,7 с | 6 |
| Крупный сбор карточек | 300 000 страниц за 10 часов | 8,3 в секунду | 1,2 с | 13 |
| Съём позиций по семантике | 45 000 запросов за 5 часов | 2,5 в секунду | 1,8 с | 6 |
| Сверка остатков каждый час | 9 000 страниц за 40 минут | 3,8 в секунду | 0,6 с | 3 |
Формула работает в обе стороны. Если число потоков задано лимитом софта, делим его на медиану отклика и получаем достижимую скорость в запросах за секунду. Умножаем на срок прогона и сразу видим, укладывается задача в отведённое окно или нет. Для парсеров вроде A-Parser эта арифметика прямо ложится в настройки: подробности по настройке под пул собраны на странице про прокси для A-Parser.
Одна поправка касается тяжёлых ответов. Когда средний объект весит мегабайты, к отклику прибавляется время передачи тела, и в формулу идёт time_total вместо ttfb. Считать объём выкачки при этом не требуется: трафик безлимитный на всех пакетах, и на выбор потоков он не влияет. Как считать нужное число адресов под такую нагрузку, разобрано в материале про то, сколько адресов нужно под задачу.
Медленный посредник или медленный целевой сайт
Самый частый вопрос звучит как «у меня всё тормозит, дело в прокси?». Отвечает на него разбор по фазам, снятый парой замеров подряд.
| Что видно в выводе | Где узкое место | Что делать |
|---|---|---|
connect крупный, ttfb минус pretransfer маленький | Путь до узла | Взять другую строку из списка, замерить снова |
connect маленький, ttfb крупный | Площадка готовит ответ долго | Смена узла ничего не даст, снижаем темп |
tls минус connect крупный, остальное ровно | Рукопожатие шифрования | Проверить версию протокола на клиенте |
| Прямой замер такой же медленный | Площадка | Работаем с темпом и параллельностью |
| Прямой быстрый, проксированный медленный на всех строках | Маршрут до узлов | Проверить свой канал и фильтры на машине |
| Прямой быстрый, проксированный медленный на части строк | Отдельные выходы пула | Отсеять строки серией перед прогоном |
speed низкий при крупном size | Пропускная способность канала | Сравнить с прямой выгрузкой того же объекта |
| Медиана ровная, p90 в разы выше | Выбросы на длинном хвосте | Поднять таймаут, добавить повтор запроса |
| Отклик растёт с числом потоков | Ограничение по частоте на площадке | Вернуться к рабочей точке из таблицы нагрузки |
| Время скачет от минуты к минуте | Загрузка площадки по времени суток | Перенести прогон, повторить замер |
Разделительная проба занимает полминуты. Снимаем прямой замер, снимаем проксированный, сравниваем ttfb. Совпали в пределах сотни миллисекунд, значит посредник работает ровно и цифры задаёт площадка. Разошлись в разы, значит смотрим на маршрут: повторяем замер на трёх других строках списка и на другом целевом домене. Одинаковая картина по разным доменам указывает на клиентскую машину, разная картина указывает на конкретную площадку.
Полезен и третий замер, на нейтральном лёгком адресе. Он отсекает влияние целевого сайта целиком и показывает голую задержку маршрута.
curl -s -o /dev/null -w 'ttfb %{time_starttransfer} total %{time_total}\n' \
--max-time 15 -x http://91.208.63.22:8000 http://echo.example.net:9000/ping
Значение в пределах десятых долей секунды означает, что путь до узла и обратно рабочий, и всё, что видно сверх этого на боевом домене, добавляет площадка. Именно такие ровные маршруты нужны при постоянном сборе данных, поэтому под регулярные прогоны берут прокси для парсинга с широким пулом.
Журнал замеров и регулярный контроль
Разовые цифры живут неделю. Дальше их забывают и меряют заново, обычно посреди сорванного прогона. Журнал снимает этот круг: одна строка после каждого замера, и через месяц видно поведение связки на длинной дистанции.
#!/bin/bash
# speed-log.sh: серия из 30 запросов, строка в журнал
TARGET="https://shop.example.net/catalog/page"
PROXY="http://91.208.63.22:8000"
STAMP=$(date +'%d.%m %H:%M')
TOTAL=30
for i in $(seq 1 $TOTAL); do
curl -s -o /dev/null --max-time 20 \
-w '%{time_starttransfer} %{http_code}\n' -x "$PROXY" "$TARGET/$i"
done > series.raw
awk '$2 == 200 {print $1}' series.raw | sort -n | awk -v stamp="$STAMP" -v total="$TOTAL" '
{ t[NR] = $1 }
END {
printf "%s медиана %.3f p90 %.3f успешных %d из %d\n",
stamp, t[int(NR*0.5)+1], t[int(NR*0.9)], NR, total
}' >> speed.log
Сортировка вынесена в отдельный шаг намеренно: встроенная сортировка массива есть только в gawk, а связка sort -n с последующим awk работает на любой машине. Строка в журнале выглядит коротко и читается сразу: отметка времени, медиана, p90 и доля успешных в одном ряду. Через две недели таких строк накапливается три десятка, и любое изменение видно глазом без графиков.
Замер повторяем при трёх событиях: перед крупным прогоном, после смены целевого домена и при жалобе на скорость от того, кто работает с прогоном. Первые два случая занимают минуту, третий закрывает разговор цифрами вместо ощущений. Планировать выгрузку по объёму при этом не нужно совсем, потому что трафик на всех вариантах доступа безлимитный по объёму выкачки, и в журнал идут только время и коды.
Журнал удобен ещё одним свойством: он показывает форму ряда поверх отдельных всплесков. Медиана, которая держится на одном уровне двадцать прогонов подряд, говорит о связке больше любого разового замера. Ползущая вверх медиана при ровной доле успешных обычно указывает на площадку, которая набрала нагрузку. Прыгающая доля успешных при ровной медиане указывает на пороги по частоте.
Отдельно держим замер по протоколу, которым реально идёт работа. Для программ на сокетах это SOCKS5, для браузеров и парсеров обычно HTTPS. Смешивать нельзя: рукопожатие у них разное, и цифры получаются несопоставимые.
Частые вопросы
Сколько запросов нужно для достоверного замера?
Тридцати достаточно для медианы и p90 по одному узлу, двухсот в двадцать потоков достаточно для проверки под нагрузкой. Первый запрос серии отбрасываем: в него входит разбор имени и установка соединения с нуля. Считать медиану надо только по ответам с кодом 200, потому что быстрые отказы занижают её на десятки процентов.
Успею ли снять полный замер за бесплатный тест?
Бесплатный тест длится до 2 часов под ваш запрос, а полная программа с последовательной серией, параллельными прогонами на пяти уровнях и разделительной пробой укладывается примерно в полчаса. Остаток окна уходит на боевой сценарий с рабочими настройками софта, и после него цифры для выбора пакета уже есть.
Влияет ли число адресов на скорость прогона?
На отклик одного запроса не влияет, на общую скорость прогона влияет прямо. Пул держится в районе 12 000 активных адресов, ротация внутри него автоматическая, список обновляется в реальном времени, поэтому параллельные потоки расходятся по разным выходам и площадка видит равномерную нагрузку. Отсюда и ровный отклик при росте параллельности до рабочей точки.
Чем ещё померить список кроме curl?
Для массовой проверки списка подойдёт чекер от Zennolab, у него есть демонстрационная версия: он проходит выборку пачкой и показывает отвечающие строки, время отклика и тип прокси. Разбор по фазам он не даёт, поэтому под точные замеры берём curl с форматом вывода, а чекер оставляем для быстрого отсева нерабочих строк перед прогоном. Пул с потоками и безлимитным трафиком под такие прогоны оформляется там, где берут доступ к серверным адресам IPv4.
Соседние разборы по диагностике: как проверить, что прокси работает с командами и разбором кодов завершения, проверка анонимности по заголовкам запроса со своей страницей-эхо, утечка запросов к DNS и настройки резолвинга. План замеров под своё окно проверки собран в материале про бесплатный тест до 2 часов.