[Перевод] Шпаргалка по метрикам производительности cURL: как измерить задержку сервера

image-loader.svg

Эту шпаргалку я написал в первую очередь, потому что был несколько озадачен, когда в течение более, чем 10 минут пытался найти в Google значение time_pretransfer. Попробуйте сами, я подожду. Это настоящая загадка!

Первым результатом выдачи по запросу «curl time_pretransfer meaning» оказывается следующий пост со StackOverflow, в котором автор цитирует страницу из мануала cURL, но при этом остается в недоумении (как и я):

Каково значение time_pretransfer? Я просмотрел страницу мануала curl, где говорится «время, пройденное от начала до момента запуска передачи файла». Мне это объяснение не совсем понятно.

Все верно — даже если вы «RTFM» (прочтете гребаное руководство), то соответствующая страница мануала совершенно не разъясняет значение time_pretransfer.

Тут можно подумать, что кто-нибудь уже написал хорошую статью по метрикам cURL.

В конечном итоге я все же выяснил значение time_pretransfer….в чем мне помог дедуктивный анализ и… скорость света (0.299 км/мкс). Больше я нигде верного ответа не нашел. Ну, а раз теперь он есть у меня, то я и делюсь им с вами в этой статье.

Несмотря на то, что ниже приведена полноценная памятка, я также пояснил каждую метрику отдельно. Если вам интересно, как я разгадал значение time_pretransfer, пролистайте к разделу «Что значит time_pretransfer?»

  • time_namelookup: длительность просмотра DNS (перевод имени домена в IP-адрес).
  • time_connect: длительность рукопожатия TCP (выполненного как при HTTP, так и при HTTPS-запросах).
  • time_appconnect: длительность рукопожатия SSL (только для HTTPS).
  • time_redirect: длительность перенаправления. Значение равно 0, если перенаправления не было. В cURL для активации перенаправления требуется флаг -L.
  • time_pretransfer: по-сути, это псевдоним для time_appconnect либо time_connect (в зависимости от HTTP или HTTPS). Он пригождается только в качестве указателя на то, когда начался конкретный запрос к серверу.
  • time_starttransfer: обозначает готовность сервера к передаче байтов. То же, что и TTFB (Time To First Byte). Он включает в себя time_pretransfer. Чтобы получить продолжительность этой фазы, нужно просто вычесть time_pretransfer из time_starttransfer.
  • time_total: общая продолжительность всего вызова cURL. Для получения времени передачи данных (их скачивания) нужно вычислить time_total — time_starttransfer.


Согласно разделу мануала cURL по Linux, все эти метрики также доступны для вывода.

image-loader.svg

Пример теста скорости в cURL


Перед вами типичный вывод теста скорости в cURL. Важно отметить, что он выполнен в отношении HTTPS URL. Этот фактор относится к time_appconnect и time_pretransfer.

Скачайте curl-format.txt с GitHub и выполните следующую команду:

$ curl -L -w "@curl-format.txt" -o tmp -s $YOUR_URL
time_namelookup: 0.001654s
time_connect: 0.054957s
time_appconnect: 0.156267s
time_pretransfer: 0.156494s
time_redirect: 0.000000s
time_starttransfer: 0.219013s
________________________________________
time_total: 0.443749s


Все показатели времени с момента запуска cURL суммируются.

Пара существенных примечаний по вышеприведенной команде:

  • Флаг -o tmp важно использовать, чтобы действительно скачать файл. Если же попытаться действовать умнее и передать -o /dev/null, то cURL пропустит скачивание файла, так как /dev/null для нее означает, что этого делать не нужно. В итоге время скачивания получится близким к 0 секунд (дельта между time_total и time_starttransfer).
  • Флаг -L нужен, чтобы cURL следовала перенаправлениям.


Что значит time_namelookup?


Эту метрику проанализировать несложно. Она отражает время просмотра DNS. Конечным результатом здесь будет IP-адрес целевого сервера, к которому должна обратиться cURL. Соединений с этим сервером пока не установлено.

Обратите внимание, что эта метрика является важным фактором в тесте скорости. Вы можете удивиться, если считаете, что это просто банальный просмотр DNS.

Как правило, поиск по DNS происходит очень быстро, потому что компьютер зачастую уже имеет кэшированный результат. Кэширование делается, потому что результаты поиска изменяются редко. Например, если для домена есть запись А, которая разрешается в IP, то компьютер может легко ее кэшировать — вся запись максимум займет 32 байта (а большинство ПК располагают гигабайтами памяти).

Однако просмотр DNS может занять и больше времени, если кэшированного результата в памяти компьютера нет. Это особенно актуально, когда у целевого сайта невысокий траффик, так как это означает, что на промежуточных маршрутизаторах результат просмотра DNS не кэширован, и они не могут вернуть его быстро. Водном из проведенных мной тестов скорости этот процесс занял 56% от всего времени скачивания (0.122108/0.217073 с.). И это невероятно высокий показатель. Я удивлен, что он получился столь велик. Тестирование проводилось в отношении моего собственного нового сайта, траффик которого реально очень низок. Следующий поиск по DNS занял всего 0.001408 с. Здесь уже определенно сработало кэширование.

Для тестов скорости CDN очень важно, чтобы операция просмотра DNS выполнялась. Поиск по DNS — это процесс, в котором CDN находит ближайший к вам IP-адрес сервера. Поэтому для одного и того же пути домена IP-адрес будет сильно отличаться в зависимости от вашего местоположения. Несмотря на то, что есть способ исключить просмотр DNS из операции cURL, указав IP-адрес как часть входных данных, так делать не стоит. Поиск DNS очень важен для работы CDN.

Писать об этом было довольно интересно. Я, наверное, как-нибудь займусь тестированием быстродействия DNS, хотя это будет уже посложнее, нежели просто тестировать скорость CDN.

Что значит time_connect?


Time_connect отражает длительность установки TCP-соединения с целевым сервером. На предыдущем шаге, просмотре DNS, мы получили только IP-адрес. На текущем этапе уже создаются сокеты и данные готовы для передачи между клиентом и сервером.

Обратите внимание, что эта процедура выполняется при каждом запросе, как для HTTP, так и для HTTPS, независимо от того, с какого сервера запрос поступает (Google, Facebook, Microsoft или любого рядового сервера на WordPress).

Что значит time_appconnect?


Эта метрика показывает продолжительность рукопожатия SSL, измеряемого только для HTTPS-запросов. Если выполнить запрос к HTTP URL, то cURL сообщит для time_appconnect значение 0.000…

Выполняется эта процедура для каждого HTTPS-запроса, независимо от его цели или отвечающего сервера, даже если это Google.

Хотя не совсем понятно, почему метрика называется time_appconnect. Похоже на ошибочный термин. Возможно, точнее было бы time_sslconnect.

Что значит time_pretransfer?


По существу, time_pretransfer равнозначна либо time_appconnect (HTTPS), либо time_connect (HTTP) — в зависимости от того, выполняется HTTPS-запрос или HTTP. В этом вся ее суть. Между time_pretransfer и предыдущей стадией ничего не происходит.

Именно эта метрика меня по истине смутила. Мне никак не удавалось понять ее смысл, пока я не осознал, что…промежуток времени с предыдущей стадии слишком мал для наличия в нем какой-либо сетевой активности.

Почему я так уверен, что здесь задействуется только ЦП? Поскольку промежуток между time_pretransfer и time_appconnect очень мал, то даже если данные будут передаваться напрямую между двумя точками со скоростью света, то в него все равно не уложится их передача в оба конца.

Давайте посчитаем. Первым делом отметим, что в примере вывода cURL разница во времени между time_pretransfer и time_appconnect составляет всего 227 мкс. Если вы проверите сами, то она может составить даже всего 27 мкс (как видно из вывода cURLв соответствующем ишью на GitHub).

Второе, что мы возьмем в расчет — это скорость света в мкс. Скорость света составляет 300 000 км/с. В одной секунде содержится 1 миллион мкс, значит 300 000 км/с * 1 с/1 000 000 мкс = 0.299 км/мкс.

В завершении умножаем получаемое значение 227 мкс * 0.299 км/мкс = 67.87 км.

Стоп, 67 км?

И это в оба конца, значит в одну сторону будет всего около 34 км.

Да уж… Я сильно сомневаюсь, что в такой близости от меня располагается дата центр. Хоть я и нахожусь в крупном городе США, но все же не в одном из типичных вариантов вроде Сан-Франциско, Нью-Йорка, Лос-Анжелеса, Чикаго или Далласа.

Я считаю, что на данной стадии cURL скорее всего просто подготавливается к получению байтов — и все. В промежутке между time_pretransfer и time_appconnect вряд ли может происходить какой-то обмен байтами.

Поэтому time_pretransfer — это то же, что и time_connect или time_appconnect. В таком случае единственное очевидное назначение этой метрики — упростить анализ того, сколько времени потребовалось серверу для начала передачи байтов. Вычисляется она так: time_starttransfer — time_pretransfer, что плавно переносит нас к следующей метрике, time_starttransfer.

Что значит time_starttransfer?


По сути, продолжительность time_starttransfer — time_pretransfer представляет задержку. В частности, эта метрика измеряет, как быстро сервер может ответить на конкретный запрос cURL. Если вы работаете со стороны бэкенд, то именно эта метрика будет интересовать вас больше всего. Все остальные относятся к типичным операциям TCP или SSL, характерным для каждого сервера, а в качестве бэкенд-инженера повлиять на их быстродействие вы можете, разве что, арендовав дополнительные дорогостоящие сервера.

Time_starttransfer по своему существу аналогична Time To First Byte (TTFB), что отражает длительность подготовки сервера к ответу. Для бэкенд-инженеров данный термин тоже определенно известен. Это просто задержка, а уменьшение задержки очень важно.

Давайте рассмотрим пример оценки метрики time_starttransfer для CDN. Если запрашивать файл из CDN, то данная фаза будет отражать длительность подготовки сетью этого файла. В случае же, когда CDN ранее кэшировала файл в память, она его сможет вернуть быстро. Если же он был кэширован в слой SSD, то потребуется чуть больше времени. А может он вообще не кэширован, тогда сети потребуется выполнить собственный HTTP/HTTPS-запрос к серверу-источнику, где этот файл размещен. Итак, данный шаг очень важен при анализе отличий между разными CDN — все остальные показатели будут плюс-минус схожи.

Вот еще один пример. Предположим, что вы отправили запрос к Google Translate API для получения французского перевода английского предложения. В этом случае этап time_starttransfer — time_pretransfer отразит длительность выполнения перевода сервисом Google. Все предыдущие шаги будут представлять просто обычную настройку TCP-соединения, типичную для любого другого запроса.

Так что time_starttransfer — это просто задержка сервера. Мы уже прошли почти по всем метрикам, и последние две — это time_redirect и time_total, которые вполне ясны.

Что значит time_redirect?


Если перенаправления нет, то и значение этого показателя будет 0.000.
Если же перенаправление присутствует, то отразится его продолжительность.

Вот простые входные данные для cURL, на примере которых мы увидим, сколько может занять перенаправление: google.com, что ведет к перенаправлению на www.google.com.

Для наших целей тестирования скорости CDN важно, чтобы показатель time_redirect был равен 0, потому что перенаправление не относится к факторам, влияющим на скорость скачивания CDN.

Стоит также отметить, что если вам требуется измерить время перенаправления, то нужно убедиться в том, что оно происходит на соответствующем шаге. Когда я выполнил операцию cURL для google.com, продолжительность time_redirect должна была измеряться на шаге 2 (сразу после time_namelookup). Я же получил следующий вывод:

curl -L -w "@curl-format.txt" -o /dev/null -s google.com
time_namelookup: 0.006038s
time_connect: 0.069728s
time_appconnect: 0.000000s
time_pretransfer: 0.069885s
time_redirect: 0.069052s
time_starttransfer: 0.161169s
________________________________________
time_total: 0.179716s


Еще важный момент — нужно использовать флаг -L, чтобы cURL следовала перенаправлениям, в противном случае она этого делать не будет. Эту ошибку легко допустить, потому что cURL не будет ругаться, если получит перенаправление, которому не последует. Единственный ориентир здесь — это, если показатель time_redirect будет равен 0.000 при ожидании ненулевого значения.

Что значит time_total?


Эта метрика очень прозрачна. Она просто отражает продолжительность всего процесса скачивания — начиная с запроса на просмотр DNS и вплоть до отправки клиентом разрыва соединения FIN ввиду завершения получения всех байтов.

Кстати, если вы используете cURL для тестирования скоростей CDN, то должны знать, что одного только выполнения cURL недостаточно для измерения скорости доставки CDN. Вам нужно оценить две метрики, а именно »1-ю скорость скачивания» и «скорость кэшированного скачивания», то есть выполнить около 11 вызовов cURL к одному URL. У меня есть более углубленная статья, где я объясняю свой метод тестирования (англ.).

image-loader.svg

© Habrahabr.ru