Thank you for reading this post, don't forget to subscribe!
В широком смысле, TTFB — это метрика, которая показывает время до получения первого байта (сетевого пакета) веб-страницы после отправки запроса со стороны клиента.
Измерение включает запрос DNS, время подключения к серверу и время ожидания обработанного запроса (обработка, перепаковка, отправка страницы). Интересно,что термин часто путают c временем отклика сервера — этот показатель дает возможность оценить скорость реакции на HTTP-запрос при отсутствии сетевой задержки. На TTFB влияет почти все: сетевые проблемы и задержки, объем входящего трафика, настройки веб-сервера, объем и оптимизированность контента ( качество графики, размер css/js/html).
Очевидно, что не на все вышеперечисленные моменты легко повлиять. У вас вряд ли будет возможность самостоятельно улучшить качество сети, а высокий трафик на веб-сайт может быть чем-то плохим только в случае DDoS-атак. Единственное, на что реально повлиять — бекенд, так что займемся тюнингом Nginx.
Анализ TTFB
На просторах Всемирной паутины размещено большое количество ресурсов, посвященных проверке скорости загрузки веб-страниц. Один из самых популярных и уважаемых — WebPageTest.org.
Он предоставляет более, чем исчерпывающую информацию о времени подключения, TTFB, времени инициализации TLS/SSL (если используется), а также о загрузке отдельных элементов веб-страницы.
Для проверки скорости загрузки и целой стопки дополнительных параметров можно использовать браузер. И в Chrome, и в FireFox, и даже в Safari присутствуют соответствующие утилиты разработчика.
Оптимизация Nginx
Еще раз кратко пройдемся по уже известным параметрам и добавим несколько новых, которые непосредственно влияют на TTFB.
Соединения
Для начала необходимо задать количество “работников” Nginx.
Каждый рабочий процесс способен обрабатывать множество соединений и привязывается к физическим ядрам процессора. Если вы точно знаете, сколько ядер в вашем сервере, то можно задать их количество самостоятельно, или довериться Nginx:
1 |
worker_processes auto; |
# Определение количества рабочих процессов
Кроме этого необходимо задать количество соединений:
1 |
worker_connections 1024; |
# Определение количества соединений на один рабочий процесс, в пределах от 1024 до 4096
Запросы
Чтобы веб-сервер мог обрабатывать максимальное количество запросов, необходимо задействовать выключенную по умолчанию директиву multi_accept:
1 |
multi_accept on; |
# Рабочие процессы будут принимать все соединения
Примечательно, что функция будет полезна только при условии большого количества запросов одновременно. Если же запросов не так много, имеет смысл оптимизировать рабочие процессы, чтобы они не трудились вхолостую:
1 |
accept_mutex on; |
# Рабочие процессы будут принимать соединения по очереди
Улучшение TTFB и времени отклика сервера напрямую зависит от директив tcp_nodelay и tcp_nopush:
1 2 |
tcp_nodelay on; tcp_nopush on; |
# Активация директив tcp_nodelay и tcp_nopush
Если не слишком вдаваться в подробности, то обе функции позволяют отключить некоторые особенности TCP, которые были актуальны в 90х, когда Интернет только набирал обороты, но не имеют смысла в современных условиях. Первая директива отправляет данные, как только они будут доступны (обходит алгоритм Нейгла). А вторая дает возможность отправлять заголовок ответа (веб-страницы) и начало файла, ожидая заполнения пакета (то есть, включает tcp_cork). Так что браузер сможет начать отображение веб-страницы раньше.
На первый взгляд, функции противоречат друг другу. Поэтому директива tcp_nopush должна использоваться вместе с sendfile. В этом случае пакеты будут заполнены до отправки, т.к. директива работает намного быстрее и оптимальнее, чем метод read+write. После того, как пакет заполнен, Nginx автоматически отключает tcp_nopush, а tcp_nodelay заставляет сокет отправить данные. Включить sendfile очень просто:
1 |
sendfile on; |
# Включение более эффективного, по сравнению с read+write, метода отправки файлов
Так что комбинация всех трех директив снижает нагрузку на сеть и ускоряет отправку файлов.
Буферы
Еще одна важная оптимизация затрагивает размер буферов — если они слишком маленькие, Nginx будет часто обращаться к дискам, слишком большие — быстро заполнится оперативная память.
Для этого потребуется настроить четыре директивы. client_body_buffer_size и client_header_buffer_size задают размер буфера для чтения тела и заголовка запроса клиента соответственно. client_max_body_size задает максимальный размер запроса клиента, а large_client_header_buffers задает максимальное число и размер буферов для чтения больших заголовков запросов.
Оптимальные параметры буферов будут выглядеть так:
1 2 3 4 |
client_body_buffer_size 10K; client_header_buffer_size 1k; client_max_body_size 8m; large_client_header_buffers 2 1k; |
# Размер буфера 10 КБ на тело запроса, 1 КБ на заголовок, 8 МБ на сам запрос и 2 буфера для чтения больших заголовков
Таймауты и keepalive
Правильная настройка времени ожидания и keepalive также может существенно повысить отзывчивость сервера.
Директивы client_body_timeout и client_header_timeout задают время ожидания на чтение тела и заголовка запроса:
1 2 |
client_body_timeout 10; client_header_timeout 10; |
# Установка времени ожидания, в секундах
При этом в случае отсутствия ответа от клиента при помощи reset_timedout_connection можно указать Nginx отключать такие соединения:
1 |
reset_timedout_connection on; |
# Отключение соединений, превысивших время ожидания
Директива keepalive_timeout задает время ожидания, прежде чем прекратить соединение, а keepalive_requests ограничивает количество keepalive-запросов от одного клиента:
1 2 |
keepalive_timeout 30; keepalive_requests 100; |
# Установка времени ожидания 30 с и ограничения в 100 запросов на клиент
Ну а send_timeout задает время ожидания при передаче ответа между двумя операциями записи:
1 |
send_timeout 2; |
# Nginx будет ждать ответа 2 с
Кэширование
Включение кэширования существенно улучшит время отклика сервера.
Методы более подробно выложены в материале о кэшировании с Nginx, но в данном случае актуально включение cache-control. Nginx способен отправлять запрос на кэширование редкоизменяемых данных, которые часто используются, на стороне клиента. Для этого в секцию server нужно добавить строчку:
1 |
location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {expires 365d;} |
# Задание форматов файлов и длительности хранения кэша
Также не помешает закэшировать информацию о часто используемых файлах:
1 2 3 4 |
open_file_cache max=10000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; |
# Разрешает кэшировать дескрипторы 10 000 файлов в течение 30 секунд
open_file_cache задает максимальное количество файлов, информация о которых будет храниться, и время хранения. open_file_cache_valid задает время, после которого нужно проверить актуальность информации, open_file_cache_min_uses определяет минимальное количество обращений к файлу со стороны клиентов, а open_file_cache_errors включает кэширование ошибок поиска файлов.
Логирование
Это еще одна функция, которая может незначительно снизить производительность всего сервера и, соответственно, время отклика и TTFB. Так что лучшим решением будет отключить основной лог, а сохранять информацию только о критических ошибках:
1 2 |
access_log off; error_log /var/log/nginx/error.log crit; |
# Отключение основного логирования
Сжатие Gzip
Полезность Gzip сложно преувеличить. Сжатие позволяет значительно уменьшить трафик и разгрузить канал. Но у него есть и обратная сторона — для компрессии нужно время. Так что для улучшения TTFB и времени отклика сервера его придется отключить.
На данном этапе мы не можем рекомендовать отключение Gzip, так как сжатие улучшает Time To Last Byte, то есть, время, требуемое для полной загрузки страницы. А это в большинстве случаев более важный параметр. На улучшение TTFB и времени отклика сервера существенно повлияет масштабное внедрение HTTP/2, который содержит встроенные методы компрессии заголовков и мультиплексирование. Так что в будущем, возможно, отключение Gzip будет не таким заметным, как сейчас.
Оптимизация PHP: FastCGI в Nginx
Все современные сайты используют серверные технологии. PHP, к примеру, который также важно оптимизировать. Обычно PHP открывает файл, проверяет и компилирует код, затем выполняет. Таких файлов и процессов может быть множество, поэтому PHP умеет кэшировать результат для редкоизменяемых файлов при помощи модуля OPcache. А Nginx, подключенный к PHP при помощи модуля FastCGI, может сохранять результат выполнения скрипта PHP для моментальной отправки пользователю.
Самое важное
Оптимизация ресурсов и правильные настройки веб-сервера — основные влияющие на TTFB и время отклика сервера факторы. Также не стоит забывать о регулярных обновлениях ПО до стабильных версий, которые несут оптимизации и повышения производительности.