Как измерить время ответа сервера?

Как измерить время ответа сервера? Конечно, для этого можно использовать команду ping. Но у этого способа есть два существенных минуса. Во-первых, очень часто по соображениям безопасности сервера на ICMP-пакеты не отвечают. Во-вторых, практическую ценность такое измерение имеет очень редко. В самом деле, какая посетителю разница, что ICMP-пакеты до сервера и обратно идут 20 миллисекунд, если страница с каталогом товаров все равно генерируется 15 секунд. Дальше мы покажем, как можно вычислить время отклика сервера на примере протокола HTTP с использованием библиотеки cURL.

Библиотека cURL предоставляет следующую информацию о времени выполнения операций:
  • CURLINFO_REDIRECT_TIME — общее время, которое потребовалось для обработки всех перенаправлений. Каждое перенаправление в HTTP это по сути отправка запроса и получение данных. Таким образом для каждого перенаправления измерение времени лучше проводить отдельно. В дальнейшем будет предполагаться, что никаких перенаправлений не происходит (максимальное количество перенаправлений установлено в 0).
  • CURLINFO_NAMELOOKUP_TIME — время, прошедшее с момента начала выполнения запроса до определения IP-адреса сервера по его доменному имени. Для URL заданных по IP-адресу сервера будет равно 0. В дальнейшем это время нас также интересовать не будет, т.к. оно может сильно зависеть от географического положения пользователя и множества других факторов, которые выходят за рамки данной статьи.
  • CURLINFO_CONNECT_TIME — время, прошедшее с момента начала выполнения запроса до установления соединения с удаленным сервером (получение пакета TCP/ACK).
  • CURLINFO_APPCONNECT_TIME — время, прошедшее с момента начала выполнения запроса до установления SSL-соединения (в рамках данной статьи рассматривается протокол HTTP без SSL).
  • CURLINFO_PRETRANSFER_TIME — время, прошедшее с момента начала запроса до отправки HTTP-запроса.
  • CURLINFO_STARTTRANSFER_TIME — время, прошедшее с момента начала запроса до получения первого байта ответа от сервера.
  • CURLINFO_TOTAL_TIME — общее время выполнения запроса. Это время помимо прочего ззависит от пропускной способности канала пользователя, т.к. включает в себя время загрузки ответа сервера.

Что же из вышеперечисленного действительно представляет практическую ценность? Казалось бы, это STARTTRANSFER_TIME, но оно включает в себя все сетевые задержки. При переносе серверов или точки проверки это время может сильно измениться, но это не будет означать, что сервера стали хуже работать и дольше обрабатывать запросы пользователей.WEBO Pulsar позволяет измерять это время, и если вам интересно полное время, которое пользователь из конкретной географической зоны тратит на ожидание контента, нужно установить переключатель «Способ вычисления времени ответа» в положение «Полное время запроса» при редактировании проверки.

Временем, которое сервер затратил на генерацию ответа является STARTTRANSFER_TIME – PRETRANSFER_TIME, т.е. время, прошедшее между отправкой запроса и получением ответа. В случае с нулевыми сетевыми задержками это время и будет временем, затраченным сервером на генерацию ответа. WEBO Pulsar позволяет измерять и его. Для этого нужно установить переключатель «Способ вычисления времени ответа» в положение «Время обработки запроса сервером + время доступа».

А что же произойдет, если сетевые задержки ненулевые, как это обычно бывает? В этом случае между отправкой HTTP-запроса и получением его сервером пройдет какое-то время, например, t1. А между окончанием обработки запроса сервером и получением ответа пользователем — еще какое-то время t2. Тогда время, затраченное на генерацию ответа будет вычисляться по формуле (STARTTRANSFER_TIME – PRETRANSFER_TIME) – (t1 + t2). В случае, когда на генерацию ответа требуется значительно больше времени, чем на доставку ответа пользователю это некритично. Но если ваш сервер работает быстро и отдает ответ за 2-4 милисекунды, а сетевые задержки между серверами составляют 50 милисекунд, это может существенно повлиять на результаты проверки. Как же вычислить это самое (t1 + t2)?

В идеале для этого нужно использовать утилиту ping, которая покажет среднее RTT (round trip time — время, прошедшее между отправкой ICMP-пакета и получением ответа, которое будет очень близко к t1 + t2). Но в общем случае утилиту ping использовать нельзя, т.к. сервер может не отвечать на ICMP-пакеты. На самом деле, (t1 + t2) ~ (CONNECT_TIME – NAMELOOKUP_TIME). Почему? Потому что обычно между определением адреса сервера и установлением TCP-соединения нужно лишь отправить TCP/SYN пакет и дождаться TCP/ACK пакета.

На обработку TCP/SYN пакета тратится очень малое количество времени (иначе на сервере возникают серьезные проблемы), поэтому это время практически равно RTT. Если же в процессе установления соединения один из пакетов потерялся (на каком-нибудь из промежуточных узлов), то (t1 + t2) ~ (CONNECT_TIME – NAMELOOKUP_TIME)/2. Если потерялось 2 пакета - то делить нужно будет на 3 и т.д.

Чем больше пакетов было потеряно в процессе, тем меньше точность определения RTT. По умолчанию WEBO Pulsar определяет время ответа именно так. Если вычисленное время ответа оказалось отрицательным, это значит, что установление соединения заняло больше времени, чем обычный обмен TCP-пакетами. В этом случае, WEBO Pulsar предполагает, что для установления соединения понадобилось 2 обмена пакетами и делит (CONNECT_TIME – NAMELOOKUP_TIME) на 2. И так вплоть до 5, т.к. дальнейшее приближение уже не имеет смысла из-за сильного падения точности.

Не стоит забывать, что на любом из этапов RTT может отличаться (иногда достаточно сильно) от среднего. Получить точный результат, не имея доступа к серверу невозможно, но данный метод позволяет получить достаточно неплохие результаты. Именно этот метод, «Время обработки запроса сервером», по умолчанию использует WEBO Pulsar для всех проверок.