Влияние GZIP на производительность Nginx

Дата: 16.08.2015Метки:

Использование GZIP в Nginx может создавать сильную нагрузку на процессор и серьезно снизить производительность. Для устойчивой работы веб-сервера под нагрузкой, важно заранее подобрать оптимальные параметры. В процессе приходится искать своего рода компромисс межу степенью сжатия GZIP и производительностью Nginx.

В интернете много информации по настройке GZIP в Nginx. Вместо того что бы слепо полагаться на сухую информацию, я решил проверить на практике влияние сжатия на производительность Nginx. Затем на основе полученных данных выбрать оптимальные настройки.

Для замеров на виртуальной машине под Debian 8.1 была установлена последняя на текущий момент версия Nginx 1.9.3, собранного с параметром --with-http_gzip_static_module. Для тестирования использовался статический HTML-документ с главной страницы моего блога.

Производительности Nginx измерялась утилитой ApacheBench, запущенная со следующими параметрами:

service nginx restart && ab -c 100 -n 25000 -H "Accept-Encoding: gzip,deflate" "http://192.168.1.32/static.html"

Посмотреть полные данные тестирования можно на сайте GitHab. Для лучшей наглядности данные представлены в виде графиков ниже.

Поочередно изменяя значения параметра gzip_comp_level от 1 до 9 запускался ApacheBench. В конце каждого теста записывались данные о количестве обработанных запросов и объеме переданных данных.

Результаты измерений можно увидеть на графике ниже.

Следующий график содержит информацию о количестве переданных данных для различного уровня сжатия.

На последнем графике мы можем сравнить скорость работы Nginx с включенным и отключенным сжатием GZIP и использованием модуля gzip_static.

Исходя из полученных данных, можно сделать вывод о том, что уровень сжатия GZIP существенно влияет на производительность Nginx. На первом графике видно, что разница между максимальным и минимальным значениями достигает почти 2,5 раза.

Производительность операции упирается в ресурсы процессора. Начина с значения параметра gzip_comp_level равным 3, скорость начинает значительно проседать. По сравнению с данными полученными без использования сжатия, дальнейшее увеличение уровня компрессии не приносит существенного результата. Использование степени сжатия больше 6 вовсе не имеет смысла и приносит больше вреда чем пользы.

Дополнительно выполнены замеры для отдачи предварительно сжатых данных.  Результаты показывают, что использования модуля http_gzip_static_module является хорошей альтернативой GZIP сжатию на лету и позволяет существенно увеличить производительность Nginx.

Таким образом, на основе полученных данных можно сделать вывод, что наиболее эффективно будет передавать предварительно сжатые данные с использованием максимального уровнем сжатия. Для сжатия всех имеющихся CSS и JS файлов, необходимо выполнить команду:

for i in `find /home/www/* -type f -name '*.js'`; do echo $i; gzip -c -9 $i > $i.gz; touch -r $i $i.gz; done;
for i in `find /home/www/* -type f -name '*.css'`; do echo $i; gzip -c -9 $i > $i.gz; touch -r $i $i.gz; done;

Для того что бы удалит .gz архивы:

for i in `find /home/www/* -type f -name '*.js.gz'`; do echo $i; rm $i; done;
for i in `find /home/www/* -type f -name '*.css.gz'`; do echo $i; rm $i; done;

Для сжатия динамически создаваемых страниц напротив лучше использовать минимальные параметры уровня сжатия, я рекомендую становить значение параметра gzip_comp_level равным 2.

Рекомендуемые параметры GZIP для Nginx:

gzip on;
gzip_static on;
gzip_comp_level 2;

Установка Nginx с поддержкой HTTP/2

Дата: 14.08.2015Метки:

Завершение разработки протокола HTTP/2 стало первым крупным обновлением HTTP за последние 16 лет. При проектировании HTTP/2 основной фокус был направлен на оптимизацию алгоритмов передачи данных и ускорение загрузки страниц.

В качестве основы для HTTP/2 был взят уже существующий открытый протокол SPDY/3, первую версию которого Google представила в 2009 году. Согласно планам, HTTP/2 должен быстро вытеснить протокол SPDY, став его эволюционным продолжением. Уже в начале 2016 года Google планирует полностью перейти на новый стандарт и отказаться от поддержки SPDY в браузере Chrome.

Недавно была представлен тестовая версия модуля HTTP/2 для Nginx. В данный момент доступна альфа версия патча. Полную поддержку протокола HTTP/2 планируется ввести к концу этого года, а пока все желающие могут протестировать его в своих проектах.

Для сборки Nginx с поддержкой HTTP/2 необходим NGINX 1.9.0 и OpenSSL 1.0.2 или новее.

Добавим в /etc/apt/sources.list официальный репозиторий для mainline-ветки Nginx:

deb http://nginx.org/packages/mainline/debian/ codename nginx
deb-src http://nginx.org/packages/mainline/debian/ codename nginx

Скачиваем и устанавливаем PGP-ключ, затем обновляем индекс пакетов apt:

cd /tmp/ && wget http://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key
apt-get update

Скачиваем необходимые для компиляции и сборки пакета программы, устанавливаем зависимости необходимые для Nginx:

apt-get install dpkg-dev
apt-get build-dep nginx

Скачиваем исходники Nginx:

cd /tmp
apt-get source nginx

Страница с патчами HTTP/2 для Nginx. Скачиваем патч HTTP/2 для нашей версии Nginx, проверяем возможность применения и если нет ошибок, по устанавливаем патч:

cd /tmp/nginx-1.9.3
wget http://nginx.org/patches/http2/patch.http2.txt
patch -p1 --dry-run < patch.http2.txt
patch -p1 < patch.http2.txt

Скачиваем и распаковываем исходники OpenSSL:

cd /tmp
wget https://openssl.org/source/openssl-1.0.2d.tar.gz
tar ixzvf openssl-1.0.2d.tar.gz

Перед началом сборки и компиляции необходимо внести изменения в файл:

nano /tmp/nginx-1.9.3/debian/rules

В секциях override_dh_auto_build и configure_debug необходимо удалить строку $(WITH_SPDY) и добавить в конец следующие опции:

--with-http_v2_module 
--with-openssl=/tmp/openssl-1.0.2

Для примера привожу фрагмент с изменениями из моего файла:

override_dh_auto_build:
	dh_auto_build
	mv objs/nginx objs/nginx.debug
	CFLAGS="" ./configure 
		--prefix=/etc/nginx 
		--sbin-path=/usr/sbin/nginx 
		--conf-path=/etc/nginx/nginx.conf 
		--error-log-path=/var/log/nginx/error.log 
		--http-log-path=/var/log/nginx/access.log 
		--pid-path=/var/run/nginx.pid 
		--lock-path=/var/run/nginx.lock 
		--http-client-body-temp-path=/var/cache/nginx/client_temp 
		--http-proxy-temp-path=/var/cache/nginx/proxy_temp 
		--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp 
		--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp 
		--http-scgi-temp-path=/var/cache/nginx/scgi_temp 
		--user=nginx 
		--group=nginx 
		--with-http_ssl_module 
		--with-http_gzip_static_module 
		--with-threads 
		--with-file-aio 
		--with-cc-opt="$(CFLAGS)" 
		--with-ld-opt="$(LDFLAGS)" 
		--with-ipv6 
		--with-http_v2_module 
		--with-openssl=/tmp/openssl-1.0.2
	dh_auto_build

После чего выполняем компиляцию и сборку deb-пакета:

cd /tmp/nginx-1.9.3
dpkg-buildpackage -rfakeroot -uc -b

После сборки пакета, установим Nginx командой:

dpkg -i nginx_1.9.3-1~jessie_i386.deb

Для включения поддержки HTTP/2 добавьте в конфигурационный файл Nginx вашего сайта параметры ssl и http2 к директивам listen:

server {
    listen 443 ssl http2 default_server;

    ssl_certificate     server.crt;
    ssl_certificate_key server.key;
    ...
}

На момент написания статьи в браузерах не реализована поддержка HTTP/2 без SSL шифрования, поэтому параметр ssl является обязательным. Как вариант — можно создать самоподписанный сертификат.

На данный момент статья частично потеряла свою актуальность, Начиная с версии Nginx 1.9.5 присутствует встроенная поддержка протокола. Информация о том как включить HTTP/2 в Nginx.

Установка Nginx из исходников

Дата: 13.08.2015Метки:

Как правило, в стандартных репозиториях Debian находится устаревшая версия пакета Nginx. Для того чтобы установить последнюю стабильную версию и включить автоматическое обновление пакетов, рекомендуется использовать официальный репозиторий Nginx.

Для более тонкой настройки и выбора модулей, которые войдут в состав сборки, я предпочитаю самостоятельно собирать Nginx из исходников. При необходимости у меня всегда есть проверенный и настроенный под себя deb-пакет Nginx, а в случае каких-либо проблем, всегда есть возможность откатится до предыдущей сборки.

Несмотря на очевидные преимущества, у данного варианта есть и свои недостатки. Приходится самостоятельно следить за выходом обновлений и при необходимости повторно собирать пакет.

Для того что бы не засорять систему ненужными пакетами, компиляцию и сборку deb-пакета я предпочитаю выполнять на виртуальной машине, после чего для установки необходимо просто перенести deb-пакет на сервер.

Для начала необходимо добавить официальный репозиторией Nginx. Для Debian замените codename на кодовое имя дистрибутива, и добавьте в конец файла /etc/apt/sources.list строки:

Для mainline-ветки.

deb http://nginx.org/packages/mainline/debian/ codename nginx
deb-src http://nginx.org/packages/mainline/debian/ codename nginx

Или для стабильной ветки.

deb http://nginx.org/packages/debian/ codename nginx
deb-src http://nginx.org/packages/debian/ codename nginx

Для проверки подлинности подписи репозитория Nginx, скачиваем PGP-ключ и устанавливаем его в связку ключей программы apt:

cd /tmp/ && wget http://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key

Для обновления индекса пакетов выполним команду:

apt-get update

Выполним установку необходимых для компиляции и сборки программ, установим все необходимые зависимости для nginx:

apt-get install dpkg-dev
apt-get build-dep nginx
apt-get install libxslt1-dev libgd2-dev libgeoip-dev

На момент написания поста, я использовал последнюю версию nginx-1.9.3. Для сборки deb-пакета скачиваем с официального репозитория исходники Nginx:

cd /tmp
apt-get source nginx

Для того что бы изменить параметры компиляции, добавить или удалить модули Nginx, необходимо отредактировать файл:

nano /tmp/nginx-1.9.3/debian/rules

Нас интересует содержимое секции override_dh_auto_build. Здесь мы можем включить в сборку необходимы нам модули или удалить ненужные. Ниже приведен пример используемой мной конфигурация:

override_dh_auto_build:
	dh_auto_build
	mv objs/nginx objs/nginx.debug
	CFLAGS="" ./configure 
		--prefix=/etc/nginx 
		--sbin-path=/usr/sbin/nginx 
		--conf-path=/etc/nginx/nginx.conf 
		--error-log-path=/var/log/nginx/error.log 
		--http-log-path=/var/log/nginx/access.log 
		--pid-path=/var/run/nginx.pid 
		--lock-path=/var/run/nginx.lock 
		--http-client-body-temp-path=/var/cache/nginx/client_temp 
		--http-proxy-temp-path=/var/cache/nginx/proxy_temp 
		--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp 
		--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp 
		--http-scgi-temp-path=/var/cache/nginx/scgi_temp 
		--user=nginx 
		--group=nginx 
		--with-http_ssl_module 
		--with-http_gzip_static_module 
		--with-threads 
		--with-file-aio 
		$(WITH_SPDY) 
		--with-cc-opt="$(CFLAGS)" 
		--with-ld-opt="$(LDFLAGS)" 
		--with-ipv6
	dh_auto_build

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

cd /tmp/nginx-1.9.3
dpkg-buildpackage -rfakeroot -uc -b

Если в процессе не было ошибок, в каталоге /tmp мы увидим собранный из исходников deb-пакет nginx_1.9.3-1~jessie_i386.deb. Для его установки необходимо выполнить команду:

dpkg -i nginx_1.9.3-1~jessie_i386.deb

 

Обновление 07.03.16
Начиная с версии Nginx 1.9.11 используется поддержка динамических модулей. Связи с чем в процессе сборки пакета произошли изменения. При отключении некоторых модулей процесс сборки может завершаться ошибкой.

Создание самоподписанного SSL сертификата

Дата: 12.08.2015Метки:

Для публичных сайтов важно использовать SSL сертификаты подтвержденные в специальных центрах сертификации, наиболее известные из них: Comodo, GeoTrust, Rapid SSL, Symantec. Помимо защиты соединения, сертификат выданный удостоверяющим центром дает гарантию, что информация о домене была проверена независимым доверенным источником.

Как и доверительный, самоподписанный сертификат обеспечивает шифрование передаваемых данных между сервером и браузером пользователя. Главный недостаток самоподписанных сертификатов: необходимость подтверждения его в браузере. Для внутреннего использования, если нет необходимости в проверке домена, вполне нормально использовать самоподписанные сертификаты.

Генерируем ключ, в процессе необходимо будет ввести пароль.

openssl genrsa -des3 -out server.key.secure 2048

Расшифруем ключ:

openssl rsa -in server.key.secure -out server.key

Создаем файл сертификата:

openssl req -new -key server.key -out server.csr

В процессе необходимо будет указать информацию о себе.

Перейдем к процессу самоподписания сертификата:

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Сертификат готов, для использования необходимо скопировать файлы ключа server.key и сертификата server.crt в необходимую нам директорию.

Синхронизация времени в контейнере KVM

Дата: 11.08.2015Метки:

Без регулярной синхронизации, в зависимости от нагрузки на хост-систему, время внутри KVM контейнера может быстро сбивается. Причина такого поведения вызвана архитектурой операционной системы и особенностями технологии виртуализации.

Большинство операционных систем используют время аппаратных часов только в процессе загрузки, после чего для подсчета времени используются системные часы. В условиях виртуализации процедуры отвечающие за системное время не могут работать также как на реальном железе, в результате часы внутри виртуальной машины начинают постепенно отставать.

Для поддержания времени в актуальном состоянии необходимо регулярно выполнять синхронизацию. Для этих целей можно использовать ntpd, но для контейнеров KVM предпочтительнее использовать синхронизацию системного времени с аппаратными часам kvm-clock.

Время kvm-clock соответствуют времени на хост-системе, таким образом нет необходимости использовать ntpd в каждой гостевой системе.

Для коррекции системного времени мы будем использовать аппаратное время:

/sbin/hwclock --hctosys

Для того что бы система регулярно каждый час синхронизировала часы, добавим задание в cron:

crontab -e
0 */1 * * * /sbin/hwclock --hctosys

 

Wget ERROR: The certificate is not trusted

Дата: 11.08.2015Метки:

Из-за отсутствия в системе корневых сертификатов, wget при попытке получить данные с сервера по протоколу https не может выполнить проверку подлинности сертификата. В результате мы получим такую ошибку:

ERROR: The certificate of 'openssl.org' is not trusted.

Для решения проблемы необходимо установить пакет ca-certificates:

apt-get install ca-certificates

Как вариант можно использовать опцию игнорирования проверки подлинности:

wget --no-check-certificate

Следует отметить, использовать данную опцию необходимо крайне осторожно, это потенциально опасно и может поставить под угрозу всю систему.

Изменяем title страниц в WordPress

В WordPress по умолчанию для каждой страницы в содержимое тега title дописывается название сайта. С точки зрения SEO это не всегда правильно. Изменить формат тега title можно при помощи различный SEO плагинов. Для простых случаев можно обойтись редактированием файла functions.php, добавив в него следующий код:

function theme_name_wp_title( $title, $sep ) {
	global $page, $paged;

	if ( is_home() || is_front_page() ) {
		$title = get_bloginfo( 'name', 'display' ) . ' - ' . get_bloginfo( 'description', 'display' );
	}
	if ( is_page() ) {
		$title = get_the_title();
	}
	if ( is_single() ) {
		$title = get_the_title();
	}
	if ( is_category() ) {
		$title = single_cat_title( 'Рубрика: ', false );
	}
	if ( is_archive() && !is_category()) {
		$title = 'Месяц: ' . get_the_date( _x( 'F Y', 'monthly archives date format', 'twentyten' ) );
	}
	if ( is_search() ) {
		$title = 'Результаты поиска: ' . get_search_query();
	}
	if ( is_tag() ) {
		$title = single_tag_title('Метка: ', false);
	}
	if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) {
		$title .= '. Страница ' . $paged . '.';
	}
	return $title;
}
add_filter( 'pre_get_document_title', 'theme_name_wp_title', 10, 2 );

Начиная с WordPress 4.4 функция wp_title() упразднена, вместо нее необходимо использовать pre_get_document_title.

Использование веб-шрифтов внутри CSS

Дата: 10.08.2015Метки:

Прочитал недавно статью о загрузке веб-шрифтов на адаптивных сайтах и решил поделиться своими соображениями по этому поводу.

Основная мысль статьи заключается в том, что за счет хранения шрифтов в CSS файле мы можем ускорить загрузку сайта и уменьшить количество запросов к серверу. С технической стороны метод выглядит следующим образом. Используя Base64-представление, мы переводим бинарные данные шрифта в ASCII-текст, после чего записываем его в CSS-файл.

Несмотря на очевидные преимущества, у данного метода есть свои недостатки. Если Google Fonts автоматически отдает шрифты в понятном для браузера формате, то в нашем случае придется использовать специальный скрипт. Я же склоняюсь к более простому варианту — просто пожертвовать совместимостью со старыми версиями браузеров.

Шрифты WOFF на текущий момент являются наиболее предпочтительными для использования. Если верить статистике сaniuse.com, этот формат поддерживают более 88% используемых браузеров в мире.

В качестве источника шрифтов лучше всего использовать Goole Fonts. Просто загружаем WOFF-файлы по ссылкам из CSS. По умолчанию в Chrome загружаются шрифты в формате WOFF2, поэтому для загрузки WOFF необходимо использовать браузер Internet Explorer.

Как запасной вариант — можно выполнить конвертирование из формата TTF в WOFF. Для этих целей в интернете есть множество онлайн-сервисов. Следует отметить, что после такой конвертации отрисовка шрифта может незначительно отличаться.

В целом я могу порекомендовать для этих целей Webfont Generator. Кроме функции конвертирования, он еще умеет оптимизировать шрифты и отдавать их в закодированном Base64 виде.

Еще можно использовать ttf to woff converter. Что бы перевести шрифты в Base64-представление используем утилиту Base64 Encode/Decode:

b64 -e input.woff output.txt

Поле того чего копируем шрифты в CSS:

@font-face {
 font-family: 'Noto Sans';
 font-style: normal;
 font-weight: 400;
 src: url(data:application/font-woff;charset=utf-8;base64,
d09GRgABAAAAAGfQABEAAAAAoxQAAQABAAAAAAAAAAAAAAAAAAAAAAAAAABHREVGAAABgAAA
AEQAAABeBXMEg0dQT1MAAAHEAAAF4wAADKz1RCPkR1NVQgAAB6gAAAAMAAAADAAVAApPUy8y
AAAHtAAAAGAAAABgd9GZHGNtYXAAAAgUAAABFQAAAYz5wR+KY3Z0IAAACSwAAACWAAAA/hmv
GsVmcGdtAAAJxAAABHkAAAe0NgsWDGdhc3AAAA5AAAAAEAAAABAAFgAjZ2x5ZgAADlAAAFDx
...
) format('woff');
}

Файл со шрифтами подключают как обычные CSS или загружают специальным скриптом:

Установка сертификатов StartSSL

Дата: 05.08.2015Метки:

Данная статья предполагает, что мы уже успешно прошли процедуру регистрации на сайте StartSSL и в нашем распоряжении есть следующие файлы: сертификат ssl.crt с проверкой домена и приватный ключ ssl.key. Копируем эти два файла на сервер. Приватный ключ перед использованием необходимо расшифровать командой:

openssl rsa -in ssl.key -out private.key

На этом этапе необходимо будет ввести пароль, который мы указывали в процессе заказа сертификата на сайте StartSSL.

Для безопасности установим права доступа на private.key:

# Только владелец может читать файл
chmod 400 /etc/nginx/ssl/*

Скачиваем сертификат Class 1 Intermediate Server CA:

wget http://www.startssl.com/certs/sub.class1.server.ca.pem

Объединяем сертификаты в один файл:

cat ssl.crt sub.class1.server.ca.pem > domain.pem

Минимальная конфигурацию NGINX для проверки работы SSL:

server {
    listen       443 ssl;
    server_name  domain.net;

    ssl_certificate      /etc/nginx/ssl/domain_com/domain.pem;
    ssl_certificate_key  /etc/nginx/ssl/domain_com/domain.key;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

После изменения настроек необходимо перезапустить NGINX:

service nginx restart

Для проверки правильности установки сертификатов используем сервис Symantec SSL Toolbox.

Подключение к OneDrive по протоколу WebDav

Последовательность действий аналогична подключению обычной сетевой папки, за исключением одной особенности — необходимо знать свой CID. Для этого в веб-интерфейсе OneDrive заходим в любой каталог, в адресной строке браузера вы увидите параметр cid=XXXXXXXXXXXXXXX.

Адрес подключения к хранилищу OneDrive по протоколу WebDAV выглядит следующим образом:

https://d.docs.live.net/XXXXXXXXXXXXXXX

Его необходимо скопировать в окно подключения сетевого диска, когда система запросит авторизацию, введите логин и пароль от вашего аккаунта OneDrive.

Для подключения также можно использовать командную строку:

net use S: https://d.docs.live.net/XXXXXXXXXXXXXXX/ /user:"user@live.com" "password" /persistent:yes