Если Ваш web-сервер защищен с помощью сервиса Cloudflare и периодически при открытии сайта появляется ошибка Error 524: A timeout occurred, то для диагностики проблемы можно легко найти официальную статью Error 524: A timeout occurred в которой описывается причина этой ошибки и как тестировать время ответа Вашего web-сервера. Но статья описывает только вариант тестирования по HTTP и не затрагивает особенностей тестирования при HTTPS соединениях и как раз в этом случае могу возникать сложности.
В своей заметке я постараюсь быстро рассказать особенности тестирования времени ответа web-сервера с помощью curl при HTTPS соединениях.
Исходные данные: Debian 9.9 + nginx 1.15.5 + curl 7.52.1
Задача: Протестировать время ответа web-сервера по HTTPS с помощью curl если он защищен сервисом Cloudflare
В моем случае вся связь по цепочке «Браузер клиента» -> «Сервера Cloudflare» -> «Мой web-сервер» идет только с использованием HTTPS, то есть в панели dash.cloudflare.com на странице SSL режим «Modes of Operation» стоит «Full SSL», более детально о режимах читайте на этой странице, а если кратко, то картинка ниже все проиллюстрирует:
Итак, первым шагом мы должны убедиться, что у нас свежая версия консольной утилиты curl, нам нужна версия выше 7.18.1 т.к. именно с этой версии есть поддержка расширения SNI. Если Вы захотите тестировать кластер серверов, то Вам потребуется curl не ниже версии 7.49.0, т.к. именно с этой версии есть поддержка опции —connect-to (см. лог изменений curl).
Проверим версию curl:
# curl --version curl 7.52.1 (x86_64-pc-linux-gnu) libcurl/7.52.1 OpenSSL/1.0.2r zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.7.0 nghttp2/1.18.1 librtmp/2.3 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL
Отлично, в нашем дистрибутиве Debian версия 7.52.1
Теперь первым шагом мы проверяем время ответа нашего web-сервера через Cloudflare, тут все просто:
MYDOMAIN="mysite.ru"; curl -vso /dev/null -A "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" -w "Connect: %{time_connect}\nTTFB: %{time_starttransfer}\nTotal time: %{time_total}\n" https://${MYDOMAIN}
В ответ нам будет выдано что-то подобное:
* Rebuilt URL to: https://mysite.ru/ * Trying 104.27.189.205... * TCP_NODELAY set * Connected to mysite.ru (104.27.189.205) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.2 (OUT), TLS header, Certificate Status (22): } [5 bytes data] * TLSv1.2 (OUT), TLS handshake, Client hello (1): } [512 bytes data] * TLSv1.2 (IN), TLS handshake, Server hello (2): { [96 bytes data] * TLSv1.2 (IN), TLS handshake, Certificate (11): { [2209 bytes data] * TLSv1.2 (IN), TLS handshake, Server key exchange (12): { [147 bytes data] * TLSv1.2 (IN), TLS handshake, Server finished (14): { [4 bytes data] * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): } [70 bytes data] * TLSv1.2 (OUT), TLS change cipher, Client hello (1): } [1 bytes data] * TLSv1.2 (OUT), TLS handshake, Finished (20): } [16 bytes data] * TLSv1.2 (IN), TLS change cipher, Client hello (1): { [1 bytes data] * TLSv1.2 (IN), TLS handshake, Finished (20): { [16 bytes data] * SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256 * ALPN, server accepted to use h2 * Server certificate: * subject: C=US; ST=CA; L=San Francisco; O=CloudFlare, Inc.; CN=sni.cloudflaressl.com * start date: Mar 31 00:00:00 2019 GMT * expire date: Mar 31 12:00:00 2020 GMT * subjectAltName: host "mysite.ru" matched cert's "*.mysite.ru" * issuer: C=US; ST=CA; L=San Francisco; O=CloudFlare, Inc.; CN=CloudFlare Inc ECC CA-2 * SSL certificate verify ok. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 } [5 bytes data] * Using Stream ID: 1 (easy handle 0x55fc957fada0) } [5 bytes data] > GET / HTTP/1.1 > Host: mysite.ru > User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 > Accept: */* > { [5 bytes data] * Connection state changed (MAX_CONCURRENT_STREAMS updated)! } [5 bytes data] < HTTP/2 200 < date: Tue, 14 May 2019 16:51:24 GMT < content-type: text/html; charset=UTF-8 < set-cookie: __cfduid=d13c3e9a1156e6edba1e2a13d0c30a8bd1557852684; expires=Wed, 13-May-20 16:51:24 GMT; path=/; domain=.mysite.ru; HttpOnly; Secure < set-cookie: PHPSESSID=6a5ac8ff445b861b55e311c631e9226c; path=/; secure; HttpOnly < expires: Thu, 19 Nov 1981 08:52:00 GMT < cache-control: no-store, no-cache, must-revalidate < pragma: no-cache < x-content-type-options: nosniff < x-xss-protection: 1; mode=block < x-frame-options: SAMEORIGIN < strict-transport-security: max-age=7776000; preload < expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" < server: cloudflare < cf-ray: 4d6e606b9fd1bd9b-AMS < { [888 bytes data] * Curl_http_done: called premature == 0 * Connection #0 to host mysite.ru left intact Connect: 0.068082 TTFB: 0.582591 Total time: 0.582884
Нас конечно же будет интересовать HTTP код ответа web-сервера, это строка с HTTP/2 200 — значит все хорошо.
Далее нас интересуют строки:
Connect: 0.068082 TTFB: 0.582591 Total time: 0.582884
Первая строка (Connect) — это время потраченное на соединение;
Вторая (TTFB — Time To First Byte или Время до первого байта) — время до получения первого байта (сетевого пакета) веб-страницы после отправки запроса со стороны клиента. Измерение включает DNS-запрос (разрешение имени), время подключения к web-серверу и время ожидания обработанного запроса (обработка, перепаковка, отправка страницы). Термин TTFB часто путают c временем отклика web-сервера — этот показатель дает возможность оценить скорость реакции на HTTP-запрос при отсутствии сетевой задержки. На TTFB влияет почти все: сетевые проблемы и задержки, объем входящего трафика, настройки web-сервера, объем и оптимизированность контента (качество графики, размер html/css/js), если например у вас сайт на php, то сюда же включается время ответа php-скриптов для формирования динамического контента, а если php-скрипты забирают данные из удаленной БД, то и время ответа БД так же будет участвовать в TTFB. В общем это довольно длинная цепочка зависимостей. Более детальный анализ всех стадий соединения и загрузки удобнее проводить с помощью специализированного сервиса, например webpagetest.org, но нам для наших целей сгодиться и curl
И третья строка (Total time) — это общее время.
Теперь нам нужно узнать TTFB в обход серверов Cloudflare и тут база знаний Cloudflare ответа не дает, поэтому вооружившись man curl мы найдем ответ сами, вот он:
MYDOMAIN="mysite.ru"; MYIP="185.125.231.XXX"; curl -vso /dev/null --insecure --resolve ${MYDOMAIN}:443:${MYIP} -A "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" -w "Connect: %{time_connect}\nTTFB: %{time_starttransfer}\nTotal time: %{time_total}\n" -H "Host: ${MYDOMAIN}" https://${MYIP}
,где переменная
MYDOMAIN=mysite.ru — это наш сайт
MYIP=185.125.231.XXX — это реальный IP адрес нашего web-сервера
В ответ нам будет выдано что-то подобное:
* Added mysite.ru:443:185.125.231.XXX to DNS cache * Rebuilt URL to: https://185.125.231.XXX/ * Trying 185.125.231.XXX... * TCP_NODELAY set * Connected to 185.125.231.XXX (185.125.231.XXX) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.2 (OUT), TLS header, Certificate Status (22): } [5 bytes data] * TLSv1.2 (OUT), TLS handshake, Client hello (1): } [512 bytes data] * TLSv1.2 (IN), TLS handshake, Server hello (2): { [103 bytes data] * TLSv1.2 (IN), TLS handshake, Certificate (11): { [808 bytes data] * TLSv1.2 (IN), TLS handshake, Server key exchange (12): { [333 bytes data] * TLSv1.2 (IN), TLS handshake, Server finished (14): { [4 bytes data] * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): } [70 bytes data] * TLSv1.2 (OUT), TLS change cipher, Client hello (1): } [1 bytes data] * TLSv1.2 (OUT), TLS handshake, Finished (20): } [16 bytes data] * TLSv1.2 (IN), TLS change cipher, Client hello (1): { [1 bytes data] * TLSv1.2 (IN), TLS handshake, Finished (20): { [16 bytes data] * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 * ALPN, server accepted to use h2 * Server certificate: * subject: C=CA; ST=None; L=NB; O=None; CN=185.125.231.XXX * start date: Mar 27 19:17:02 2019 GMT * expire date: Mar 24 19:17:02 2029 GMT * issuer: C=CA; ST=None; L=NB; O=None; CN=185.125.231.XXX * SSL certificate verify result: self signed certificate (18), continuing anyway. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 } [5 bytes data] * Using Stream ID: 1 (easy handle 0x5580c7871da0) } [5 bytes data] > GET / HTTP/1.1 > Host: mysite.ru > User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 > Accept: */* > { [5 bytes data] * Connection state changed (MAX_CONCURRENT_STREAMS updated)! } [5 bytes data] < HTTP/2 200 < server: nginx < date: Tue, 14 May 2019 16:53:18 GMT < content-type: text/html; charset=UTF-8 < set-cookie: PHPSESSID=f1be30edfc7680d6680f0aaa2ac3725c; path=/; secure; HttpOnly < expires: Thu, 19 Nov 1981 08:52:00 GMT < cache-control: no-store, no-cache, must-revalidate < pragma: no-cache < x-content-type-options: nosniff < x-xss-protection: 1; mode=block < x-frame-options: SAMEORIGIN < strict-transport-security: max-age=31557600 < { [3039 bytes data] * Curl_http_done: called premature == 0 * Connection #0 to host 185.125.231.XXX left intact Connect: 0.054492 TTFB: 0.492668 Total time: 0.493891
Время TTFB в случае прямого соединения с нашим web-сервером оказалось чуть ниже чем если соединение шло через Cloudflare, но иногда оно может быть и больше.
На этом все, до скорых встреч.
Если у Вас возникли вопросы или Вы хотите, чтобы я помог Вам, то Вы всегда можете связаться со мной разными доступными способами.
Профессионально занимаюсь системным администрированием Linux -серверов и баз данных (MySQL, PostgreSQL) на протяжении последних 24 лет.