CPU: 1 x 2GHz
HDD: 10Gb
RAM: 512Mb
OS: Debian 8 x64
Схема работы системы выглядит следующим образом:
Описание работы схемы
Для посетителей сайта происходит перенаправление на HTTPS, где nginx работает в качестве прокси для Varnish, при этом на выходе nginx помимо реализации HTTPS-соединения происходит gzip-сжатие данных, передаваемых пользователю. Следующим элементом в данной системе является HTTP-акселератор Varnish, ожидающий соединения на 6081 порту. Получая запрос от клиента он выполняет поиск запрашиваемого URL в кэше, и в случае его обнаружения мгновенно отдаёт его фронтенду. Таким образом, при наличии запрашиваемого файла в кэше скорость запроса к страницам сокращается до скорости запроса к статическим данным. Если же запрашиваемого файла в кэше не обнаруживается, Varnish передаёт запрос бэкенду. Так же в Varnish реализована оптимизация клиентской стороны — здесь статическим данным устанавливаются заголовки Cache-Control и Expires, указывающие браузеру на необходимость кэширования этих данных на стороне клиента. Таким образом сокращается время загрузки сайта и уменьшается нагрузка на сервер.
В роли бэкенда выступает опять же nginx, ожидающий соединений на 127.0.0.1:81. Интерпретация PHP реализована с помощью FPM. Версия PHP — 5.6 с включенным по умолчанию акселератором OPcache. В качестве СУБД — MariaDB 10, являющаяся одной из лучших по производительности и кушающих в меру оперативную память СУБД среди форков MySQL. В качестве движка таблиц — MyISAM, так как запись производится редко, в основном чтение, для которого данный движок больше оптимизирован. За счёт отключения движка InnoDB реализуется экономия оперативной памяти. Наконец, в качестве CMS функционирует WordPress с установленным плагином Varnish HTTP Purge, отправляющий PURGE-запросы на адреса страниц, на которых были произведены изменения, что приводит к очистке кэша Varnish для данных страниц. Таким образом, пользователь получает всегда актуальную версию сайта. Далее я детально расскажу об установке и настройке данных компонентов, а так же о проблемах, с которыми я столкнулся.
Установка и настройка nginx
Устанавливаем:
apt-get install nginx
Содержимое основного конфига /etc/nginx/nginx.conf:
# Пользователь и группа, от имени которых будет запущен процесс
user www-data www-data;
# Число воркеров в новых версиях рекомендовано устанавливать в auto
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
# Максимальное количество соединений одного воркера
worker_connections 1024;
# Метод выбора соединений (для FreeBSD будет kqueue)
use epoll;
# Принимать максимально возможное количество соединений
multi_accept on;
}
http {
# Указываем файл с mime-типами и указываем тип данных по-умолчанию
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Отключить вывод версии nginx в ответе
server_tokens off;
# Метод отправки данных sendfile эффективнее чем read+write
sendfile on;
# Ограничивает объём данных, который может передан за один вызов sendfile(). Нужно для исключения ситуации когда одно соединение может целиком захватить воркер
sendfile_max_chunk 128k;
# Отправлять заголовки и и начало файла в одном пакете
tcp_nopush on;
tcp_nodelay on;
# Сбрасывать соединение если клиент перестал читать ответ
reset_timedout_connection on;
# Разрывать соединение по истечению таймаута при получении заголовка и тела запроса
client_header_timeout 3;
client_body_timeout 5;
# Разрывать соединение, если клиент не отвечает в течение 3 секунд
send_timeout 3;
# Задание буфера для заголовка и тела запроса
client_header_buffer_size 2k;
client_body_buffer_size 256k;
# Ограничение на размер тела запроса
client_max_body_size 12m;
# Отключаем лог доступа
access_log off;
# Подключаем дополнительные конфиги
include /etc/nginx/conf.d/*.conf;
}
Создадим файл настроек бэкенда /etc/nginx/conf.d/backend.conf:
server {
# Ожидать локального соединения на 81 порту
listen 127.0.0.1:81;
# Корневая директория и индексовый файл
root /var/www/site.ru/public_html;
index index.php;
# Включить gzip-сжатие на выходе бэкенда. В кэш пойдут уже сжатые версии файлов. Здесь происходит сжатие на 9 уровне компрессии. Обратите внимание, среди типов отсутствует text/plain, его мы сжимаем во фронтенде на 1 уровне компрессии, чтобы избежать высокой степени загрузки CPU при отдаче динамических данных
gzip on;
gzip_comp_level 9;
gzip_min_length 512;
gzip_buffers 8 64k;
gzip_types text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
gzip_proxied any;
# Имя хоста
server_name site.ru www.site.ru;
# Запрет на доступ к скрытым файлам
location ~ /\. {
deny all;
}
# Запрет на доступ к загруженным скриптам
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
# Поиск запрашиваемого URI по трем путям
location / {
try_files $uri $uri/ /index.php?$args;
}
# Добавление слэша в конце для запросов */wp-admin
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
location ~ \.php$ {
# При ошибке 404 выдавать страницу, сформированную WordPress
try_files $uri =404;
# При обращении к php передавать его на интерпретацию FPM
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
}
На тему детального описания настройки HTTPS в nginx рекомендую к прочтению данную статью: habrahabr.ru/post/252821
Создаём файл настроек фронтэнда /etc/nginx/conf.d/frontend.conf:
server {
# Редирект на HTTPS
listen REAL_IP:80;
server_name site.ru www.site.ru;
return 301 https://$server_name$request_uri;
}
server {
listen 93.170.105.102:443 ssl;
server_name site.ru www.site.ru;
# Устанавливать Keep-Alive соединения с посетителями
keepalive_timeout 60 60;
# Сжатие данных перед отправкой клиенту. Обратите внимание, из типов здесь присутствует только text/plain, для других данных применяется сжатие на бэкенде на более высоком уровне компрессии, после чего эти данные отправляются в кэш. Сделано для того, чтобы избежать нагрузок на CPU при сжатии динамических документов.
gzip on;
gzip_comp_level 1;
gzip_min_length 512;
gzip_buffers 8 64k;
gzip_types text/plain;
gzip_proxied any;
# Отдавать предпочтение шифрам, заданным на сервере
ssl_prefer_server_ciphers on;
# Установка длительности TLS сессии в 2 минуты
ssl_session_cache shared:TLS:2m;
ssl_session_timeout 2m;
# Задание файла, содержащего сертификат сайта и сертификат УЦ
ssl_certificate /etc/ssl/combined.crt;
# Указание закрытого ключа
ssl_certificate_key /etc/ssl/3_site.ru.key;
# Файл с параметрами Диффи-Хеллмана
ssl_dhparam /etc/ssl/dh2048.pem;
# Поддерживаемые протоколы
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
# Наборы шифров, данный набор включает forward secrecy
ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA512:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:ECDH+AESGCM:ECDH+AES256:DH+AESGCM:DH+AES256:RSA+AESGCM:!aNULL:!eNULL:!LOW:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
# Передача Strict-Transport-Secutiry заголовка
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
location / {
# Проксирование на Varnish
proxy_pass http://127.0.0.1:6081/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
}
}
Перечитаем конфиги nginx:
service nginx reload
Теперь при попытке зайти на сайт увидим ошибку 502. Это нормально, так как Varnish пока не запущен.
Установка и настройка Varnish
Устанавливаем Varnish:
apt-get install varnish
Файл параметров запуска располагается здесь — /etc/default/varnish. В DAEMON_OPTS задаём следующие параметры:
DAEMON_OPTS="-a :6081 -T 127.0.0.1:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,128m"
-a — задаёт порт, на котором Varnish будет принимать соединения, в нашем случае от фронтенда — nginx;
-T — здесь крутится админка, подробнее в описании к флагу -S;
-f — файл с конфигурацией VCL — специальном языке, предназначенном для определения правил обработки запросов и кэширования в Varnish;
-S — Varnish имеет панель администрирования. Для входа необходимо выполнить команду varnishadm, при этом пользователь должен иметь права на чтение файла /etc/varnish/secret для прохождения аутентификации;
-s указание места хранения кэша и его размер, в данном случае 128Mб в оперативной памяти.
Как вы уже, наверное, поняли, самое интересное нас ждёт в файле с правилами обработки запросов. Во время старта процесса Varnish’а данный файл компилируется. В VCL используется несколько подразделов-функций, в которых описываются эти правила. Кратко расскажу о них, полное описание рекомендую прочитать на официальном сайте.
sub vcl_recv — данная функция используется когда приходит запрос от клиента;
sub vcl_pass — выполняется, когда запрос клиента необходимо передать напрямую бэкенду, не кэшировать и не искать соответствия в кэше;
sub vcl_hash — определяет правила кэширования, можно использовать несколько хранилищ для одного и того же документа, в зависимости от разных условий, например, поддержки сжатия клиентом, или каких-либо других особенностей клиента. В нашем случае не будет использоваться, так как клиент у нас для Varnish’а один — nginx на фронтенде;
sub vcl_backend_response — данная функция используется когда приходит запрос от бэкенда (nginx);
sub vcl_deliver — используется непосредственно перед отправкой данных клиенту, например, для добавления/изменения заголовков.
Схема работы компонентов VCL может быть представлена следующим образом:
Если обращение к бэкенду происходит при этом из функции vcl_miss ответ бэкенда отправляется и в кэш. Сам язык очень похож на C. Приступим к настройке. Открываем файл /etc/varnish/default.vcl и начинаем кодить:
# Сообщаем компилятору о том, что используется новая версия VCL 4
vcl 4.0;
# Настройки бэкенда
backend default {
.host = "127.0.0.1";
.port = "81";
}
# Диапазон IP/Хостов, которым разрешено выполнять PURGE-запросы для очистки кэша
acl purge {
"localhost";
"127.0.0.1";
}
# Получение запроса от клиента
sub vcl_recv {
# Разрешить очистку кэша вышеописанному диапазону
if (req.method == "PURGE") {
# Если запрос не из списка, то разворачивать
if (!client.ip ~ purge) {
return(synth(405, "This IP is not allowed to send PURGE requests."));
}
return (purge);
}
# POST-запросы а также страницы с Basic-авторизацией пропускать
if (req.http.Authorization || req.method == "POST") {
return (pass);
}
# Пропускать админку и страницу входа
if (req.url ~ "wp-(login|admin)" || req.url ~ "preview=true") {
return (pass);
}
# Пропускать sitemap и файл robots, у меня sitemap генерируется плагином Google XML Sitemaps
if (req.url ~ "sitemap" || req.url ~ "robots") {
return (pass);
}
# Удаляем cookies, содержащие "has_js" и "__*", добавляемые CloudFlare и Google Analytics, так как Varnish не будет кэшировать запросы, для которых установлены cookies.
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
# Удаление префикса ";" в cookies, если вдруг будет обнаружен
set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
# Удаляем Quant Capital cookies (добавляются некоторыми плагинами)
set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
# Удаляем wp-settings-1 cookie
set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-1=[^;]+(; )?", "");
# Удаляем wp-settings-time-1 cookie
set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-time-1=[^;]+(; )?", "");
# Удаляем wp test cookie
set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=[^;]+(; )?", "");
# Удаляем cookie, состоящие только из пробелов (или вообще пустые)
if (req.http.cookie ~ "^ *$") {
unset req.http.cookie;
}
# Для статических документов удаляем все cookies, пусть себе кэшируются
if (req.url ~ "\.(css|js|png|gif|jp(e)?g|swf|ico|woff|svg|htm|html)") {
unset req.http.cookie;
}
# Если установлены cookies "wordpress_" или "comment_" пропускаем напряиую к бэкенду
if (req.http.Cookie ~ "wordpress_" || req.http.Cookie ~ "comment_") {
return (pass);
}
# Если cookie не найдено, удаляем данный параметр из пришедшего запроса как таковой
if (!req.http.cookie) {
unset req.http.cookie;
}
# Не кэшировать запросы с установленными cookies, это уже не касается WordPress
if (req.http.Authorization || req.http.Cookie) {
# Not cacheable by default
return (pass);
}
# Кэшировать всё остальное
return (hash);
}
sub vcl_pass {
return (fetch);
}
sub vcl_hash {
hash_data(req.url);
return (lookup);
}
# Приём ответа от бэкенда
sub vcl_backend_response {
# Удаляем ненужные заголовки
unset beresp.http.Server;
unset beresp.http.X-Powered-By;
# Не хранить в кэше robots и sitemap
if (bereq.url ~ "sitemap" || bereq.url ~ "robots") {
set beresp.uncacheable = true;
set beresp.ttl = 30s;
return (deliver);
}
# Для статических файлов, которые отдаёт бэкенд...
if (bereq.url ~ "\.(css|js|png|gif|jp(e?)g)|swf|ico|woff|svg|htm|html") {
# Удаляем все куки
unset beresp.http.cookie;
# Устанавливаем срок хранения в кэше - неделю
set beresp.ttl = 7d;
# Устанавливаем заголовки Cache-Control и Expires, сообщая браузеру о том, что эти файлы стоит сохранить в кэше клиента и не нагружать лишниий раз наш сервер
unset beresp.http.Cache-Control;
set beresp.http.Cache-Control = "public, max-age=604800";
set beresp.http.Expires = now + beresp.ttl;
}
# Не кэшировать админку и страницу логина
if (bereq.url ~ "wp-(login|admin)" || bereq.url ~ "preview=true") {
set beresp.uncacheable = true;
set beresp.ttl = 30s;
return (deliver);
}
# Разрешить устанавливать куки только при обращении к этим путям, всё остальное будет резаться
if (!(bereq.url ~ "(wp-login|wp-admin|preview=true)")) {
unset beresp.http.set-cookie;
}
# Не кэшировать результат ответа на POST-запрос или Basic авторизации
if ( bereq.method == "POST" || bereq.http.Authorization ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# Не кэшировать результаты поиска
if ( bereq.url ~ "\?s=" ){
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# Не кэшировать страницы ошибок, только нужные вещи в кэше!
if ( beresp.status != 200 ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# Хранить в кэше всё прочее на протяжении одного дня
set beresp.ttl = 1d;
# Срок жизни кэша после истечения его TTL
set beresp.grace = 30s;
return (deliver);
}
# Действия перед отдачей результата пользователю
sub vcl_deliver {
# Удаляем ненужные заголовки
unset resp.http.X-Powered-By;
unset resp.http.Server;
unset resp.http.Via;
unset resp.http.X-Varnish;
return (deliver);
}
После чего выполняем команду:
service varnish restart
Перейдя теперь в браузере на наш сайт, мы увидим index.php, который нужно предварительно создать.
Проблема Varnish и Debian 8
А что если вы захотите изменить порт, на котором Varnish будет принимать входящие соединения или изменить объём кэша. Судя по официальной документации нужно изменить файл с параметрами запуска Varnish, располагающийся по пути: /etc/default/varnish и перезапустить сервис. Но нет! Ничего не изменится, и если мы зайдём в top и нажмем на клавишу ‘c’, то увидим, что сервис запущен с прежними настройками. А всё дело в том, что в новой версии Debian используется systemd вместо init.d в качестве системы инициализации, и поэтому нужно зайти в файл /lib/systemd/system/varnish.service и прописать там в директиве ExecStart те же параметры запуска:
[Unit]
Description=Varnish HTTP accelerator
[Service]
Type=forking
LimitNOFILE=131072
LimitMEMLOCK=82000
ExecStartPre=/usr/sbin/varnishd -C -f /etc/varnish/default.vcl
ExecStart=/usr/sbin/varnishd -a :6081 -T 127.0.0.1:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,128m
ExecReload=/usr/share/varnish/reload-vcl
[Install]
WantedBy=multi-user.target
После сохранения выполнить следующие команды для вступления изменений в силу:
systemctl daemon-reload
service varnish restart
В данный момент данная проблема отписана разработчикам, когда и как они её решат — неизвестно, поэтому на всякий случай производите одинаковые изменения в обоих файлах, чтобы однажды после апдейта всё не упало.
Установка и настройка PHP-FPM
Устанавливаем FPM и библиотеку PHP для работы с СУБД:
apt-get install php5-fpm php5-mysqlnd
Заходим в файл конфигурации /etc/php5/fpm/pool.d/www.conf и меняем директиву:
listen = 127.0.0.1:9000
На следующее:
listen = /var/run/php5-fpm.sock
В этом же файле задаём настройки воркеров:
; Динамическое изменение количества воркеров
pm = dynamic
; Максимальное число воркеров, создаются под нагрузкой, не может быть меньше pm.max_spare_servers.
pm.max_children = 10
; Сколько воркеров запускать при старте FPM
pm.start_servers = 1
; Минимальное количество запасных воркеров (остаются в памяти при отсутствии нагрузки)
pm.min_spare_servers = 1
; Максимальное количество запасных воркеров (при простое, остальные неиспользуемые будут завершаться)
pm.max_spare_servers = 3
; Максимальное количество запросов, которые выполняет один воркер, прежде чем перезапуститься
pm.max_requests = 500
Меняем несколько директив в /etc/php5/fpm/php.ini
upload_max_filesize = 10M
post_max_size = 12M
allow_url_fopen = Off
post_max_size задаём чуть больше, чем upload_max_filesize, так как помимо файла в запросе идут другие данные.
Здесь же директивой allow_url_fopen запрещаем выполнять скрипты, расположенные удаленно (убирая возможность эксплуатации уязвимости удалённого инклуда).
И говорим FPM перечитать конфиг:
service php5-fpm reload
Теперь создайте файлик, выводящий phpinfo() и обратитесь к нему в браузере, всё должно работать. Не забывайте, что он уже закэшировался в Varnish и если вы будете изменять конфигурацию PHP, то она не будет обновляться в вашем браузере. Можете написать правило на пропуск данного файла в Varnish, либо же на время тестов проксировать не Varnish, а напрямую бэкенд на 81 порту.
Установка и настройка MariaDB
Эту СУБД я выбрал по причине её лучшей производительности и способности выдерживать большие нагрузки, при этом затрачивая меньшее количество оперативной памяти по сравнению с MySQL, а так же её полной совместимостью с WordPress. Установка очень проста, будет запрошен пароль для пользователя root.
apt-get install mariadb-server
В качестве движка для таблиц я использую MyISAM, по причине того, что запись в таблицу выполняется редко, а на чтении MyISAM показывает лучшие характеристики. Я полностью отключил поддержку InnoDB для освобождения оперативной памяти. Настройки хранятся в файле /etc/mysql/my.cnf. Опишу только те директивы, которые я изменил:
# Кэш для работы с ключами и индексами
key_buffer = 64M
# Кэш запросов
query_cache_size = 32M
# Установка MyISAM в качестве стандартного движка
default-storage-engine=MyISAM
# Отключение движка InnoDB
skip-innodb
После сохранения изменений перезапускаем сервис:
service mysql restart
Настройка WordPress — плагин «Varnish HTTP Purge»
Устанавливаем в панели администрирования WP плагин «Varnish HTTP Purge». Теперь при обновлении данных на измененные страницы будет отправлен PURGE-запрос, очищающий кэш в Varnish, и для посетителей данные всегда будут обновлёнными.
Дополнительная оптимизация
Для оптимизации клиентской стороны с помощью Varnish мы указываем браузеру на необходимость хранения статических данных в локальном кэше клиента. Но если вы жаждете ещё большей оптимизации, перейдите на страничку developers.google.com/speed/pagespeed/insights и введите URL вашего сайта или даже конкретной страницы. Вам предоставится список рекомендаций, а так же предложат архив со сжатыми версиями ваших css и js стилей. Замените их на своём сайте и получите ещё большую скорость загрузки за счёт уменьшенного объема передаваемых данных, так же уменьшится нагрузка на сервер и место, занимаемое данными файлами в кэше.
Как поступить с документами, запрашиваемыми со сторонних серверов, например, шрифтами или библиотекой jquery? Можно перенести их к себе, и тут за счёт установки соединения только с одним сервером возрастёт скорость загрузки страниц, однако, в то же время, возрастёт список обращений и общая нагрузка. Какой вариант выбрать — решайте сами, в зависимости от загруженности вашего сервера и вашей лени.
Итог
По большей части наибольший эффект дали сжатие gzip и кэширование в Varnish. В комментариях уже написали много дополнительных методов оптимизации, которые я непременно изучу и по мере необходимости внедрю. Пока же результаты оптимизации следующие:
До
После
Полноценные стресс-тесты проведу чуть позже.
Комментарии (45)
ibKpoxa
29.02.2016 13:10+3Совсем не плохо приведены примеры конфигов, но совсем нет обоснования выбранному решению, что от подобной статьи ожидается.
Почему не используется кеширование в nginx?
Используется ли memcache в WordPress? Он умеет, если попросить и плагин поставить.
Какой смысл использовать MariaDB при использовании MyISAM?ivashkevitch
29.02.2016 13:52-2В первую очередь было интересно изучить возможности Varnish, а ещё Varnish быстрее по результатам тестирования, например — http://www.uptimemadeeasy.com/cloud/nginx-or-varnish-which-is-faster/
memcache не используется, по тому как я до него пока не добрался. Есть рекомендации, с чего начать?
При выборе СУБД руководствовался данным результатом https://habrahabr.ru/post/242337/ibKpoxa
29.02.2016 14:01+4В любом проекте должна быть еще и надежность и рациональность, чем больше инструментов мы используем — тем больше точек отказа.
Обработка запросов в цепочке nginx-varnish-nginx-php будет в любом случае медленнее, чем nginx-php, даже если varnish в разы быстрее, чем nginx, хотя и судя по вашей ссылке, nginx не всегда медленнее чем varnish.
для мемкеша есть модуль у wordpress, он легко ищется.ivashkevitch
29.02.2016 14:09Спасибо за пояснения.
Я имел в виду, может посоветуете статей на тему грамотной настройки memcache с подробными комментариями?ibKpoxa
29.02.2016 15:44основная настройка мемкеша — размер занимаемой памяти, конечно есть еще число тредов, фактор размеров таблиц и т.п., но число требов запросто можно сделать равным числу тредов в пыхе + 1, а фактор размеров таблиц оставить по умолчанию и эффект будет достаточным, в процессе работы надо следить на числов эвикшенов, т.е. за удалением элементов из кеша при записи новых элементов, и на соотношение hit/miss, если соотношение нормальное, например 90% нужной информации находится в мемкеше, то все ок, если информации мало, и много эвикшенов, то не хватает памяти, а если число эвикшенов при этом не велико, то просто запросы такие, что они плохо кешируются.
maxxannik
01.03.2016 04:13Вот тут есть подборка с кейсом http://systemo.biz/kesh-wordpress-varianty-keshirovaniya-i-uskoreniya-sajta/
alekciy
29.02.2016 13:19+1# Отключаем лог доступа
Специальное значение off отменяет все директивы access_log для текущего уровня
Это именно отмена, а не отключение файла лога. Лог будет писаться в файл off. Что бы действительно отключить запись лога в файл нужно писать access_log /dev/null
include fastcgi_params;
include в контексте PHP должен быть вначале.1it
29.02.2016 14:37+4Это именно отмена, а не отключение файла лога. Лог будет писаться в файл off. Что бы действительно отключить запись лога в файл нужно писать access_log /dev/null
Бред.
The special value off cancels all access_log directives on the current level.
http://nginx.org/en/docs/http/ngx_http_log_module.html
access_log off; это директива отключающая лог (в конкретном блоке server или location), про "файл off" в документации нет ни слова (и на практике такой файл не возникает).
coh
29.02.2016 13:19На заметку, в MariaDB нет MyISAM, storage engine называется Aria. Выбор движка не очевиден, чем вам не понравился XtraDB?
Вы не сравнивали производительность WP + Varnish vs WP + memcached (например w3 total cache) vs WP +Varnish + Memcached ?
alekciy
29.02.2016 13:40+6Я возможно что-то пропустил в статье, но где цифры "было-стало"?
ivashkevitch
29.02.2016 14:57+1Отключил gzip и убрал из цепочки Varnish — основные компоненты, обеспечивающие повышение производительности. Примерно улучшения следующие (повторное посещение странички):
nikitasius
29.02.2016 15:56+2gzip_comp_level 9;
неверно. Вот замечательная статья, "единички" хватит за глаза.
Для статики используйте активно ngx_http_gzip_static_module:
for i in `find ./* -type f -name '*.js'`; do echo $i; gzip -c -9 $i > $i.gz; done;
for i in `find ./* -type f -name '*.css'`; do echo $i; gzip -c -9 $i > $i.gz; done;
И не забыть chown'ом юзера вернуть, ибо файлы будут под учеткой, с которой запускали скрипт.
Отключите server_tokens, чтобы был просто nginx в ответах.
Использую send_file, используйте и чанки.ivashkevitch
29.02.2016 18:51Перенёс сжатие на выход бэкенда, теперь в кэше будут храниться уже сжатые варианты. То есть для статики теперь компрессия будет происходить раз в сутки (время хранения в кэше Varnish). Как думаете, оправданно ли теперь оставить уровень сжатия на 9?
nikitasius
29.02.2016 19:20Если у вас посетилелей мало — 9 на одном ядре много от самого ядра не съест. Но если будет большой наплыв, то nginx без кеша будет сжимать в девятку каждый раз ответ динамики через ваш варниш (=ответ кеша, как я понимаю), что скажется на использовании CPU (которое как минимум делят система, бд, варнишь и nginx).
На картинке у вас страница весит 8кб, подозреваю что сжатая. Значит на единичке она будет 9-11кб. Выиграшь копеечный, при таком расходе цпу.
Вы вообще можете отказаться от варниша и обыграть тонкую настройку через location, как делают на проектах, где nginx управляет и кешем и сжатием. Будет менее красиво (в визуальном плане листинга), чем варнишь.
*отщепяткиivashkevitch
29.02.2016 19:29будет сжимать в девятку каждый раз ответ динамики через ваш варниш
Прошу прощения, Вы имели в виду сжатие динамики на выходе бэкенда каждый раз, перед отдачей Varnish?nikitasius
29.02.2016 19:42Почти..
Пересмотрел ваш конфиг, у вас там php -> nginx -> varnish -> nginx.
Мой комментарий был бы к месту, если бы у вас там не было промежуточного nginx. В вашем случае 9тка будет в кеше варниша, так что все ОК :)ivashkevitch
29.02.2016 19:51Да, но Вы до этого всё же были правы. Актуально это будет только для статики, а для динамики будет происходить сжатие каждый раз. Так что нужно переделать. Два правила, например, в зависимости от типа файлов: статику сжимать на выходе из бэкенда на 9 уровне и пусть хранится в кэше Varnish'a, а динамику сжимать на выходе фронтенда на 1 уровне компрессии.
И ещё, сейчас стоит сжатие только на бэкенде, динамический контент при этом при отдаче в браузер отдаётся без сжатия. Кажется, Varnish что-то делает не так, как задумывалось, впрочем, при вышеописанной схеме данной проблемы не будет.
laviro
29.02.2016 14:46Может кто то на опыте сказать, реально ли есть смысл к nginx еще varnish добавлять?
А то как то кеш всегда на nginx делал, а смотрю часто люди в связку еще varnish добавляют.
А тестировали нагрузку?
И как тестировали?ivashkevitch
29.02.2016 14:53На http://www.host-tracker.com/ в 10 вкладках по разным адресам запускал, выжило, даже не тупило. Взялся было запустить синтетические тесты нагрузочные, но они требуют поддержки SSLv3. Пока не до этого, на следующих выходных думаю потестировать.
nikitasius
29.02.2016 16:37У nginx замечательный кеш, в том числе и для fastcgi:
fastcgi_cache_lock on;
fastcgi_cache_lock_timeout 6s;
В чем плюс такой блокировки:
на страничку блога (если ключ только включает путь, без cookies) привалило 1000 человек, nginx проверил наличие в кеше, если их там нету, то послал всего 1 запрос на бекенд, записал в кешт и затем отдал первому юзеру и остальным 999. И только через 6 секунд запрос будет передан на бекенд для обновления кеша и выдачи нового результата, если толпа не утихает.
Принципиальное отличие — пришло много народа на один ключ, запросили 1н результат, затем раздали всем, залочив на 6 секунд.nikitasius
29.02.2016 16:39Но я с варнишом никогда не работал, и, судя по статье, там очень гибко и удобно (=точечно) настраивается кеш.
fear86
01.03.2016 03:09Есть смысл ради https://www.varnish-cache.org/docs/3.0/tutorial/esi.html но тут должна быть поддержка на стороне приложения.
MechanisM
29.02.2016 16:28Похожую связку использовал. Только у меня вместо php-fpm был uwsgi с php плагином.
ennau
29.02.2016 17:52Для дополнения по оптимизации, рекомендую все имиджи оптимизировать, напрм. jpegoptim и optipng утилитами.
Лучше gzip_level снизить до 5.
В gzip_types можно добавить jpg и png майм-типы.nikitasius
29.02.2016 18:04Зачем вам тратить ресурсы на ужимку картинок? Там не многократный выигрыш, как в сравнении с текстами.
И величина 5 — это чересчур.ennau
29.02.2016 21:45Эти утилиты не сжимают картинки, а удаляют мета информацию и всякий "мусор" в них, тем самым уменьшая размер картинок. И ресурсы не тратятся, т.к. это единаразовая "акция":-)
Об уровнях сжатия тут отлично расписано: https://habrahabr.ru/post/99256/nikitasius
01.03.2016 01:36Так я эту статью выше линковал.
А удалять теги… вас за это SEO покарают. Сейчас наоборот надо в картинках иметь мета инфу и сайте и страницах. Да и не много там ее будет, в сравнении с общим объемом.
veter
29.02.2016 18:06И что получилось? Какая нагрузка была раньше, а какая выдерживается теперь?
ivashkevitch
29.02.2016 18:29Добавил информацию по поводу производительности в конец статьи. Стресс-тест проведу чуть позже.
farcaller
29.02.2016 23:51+2нужно зайти в файл /lib/systemd/system/varnish.service и прописать там в директиве ExecStart те же параметры запуска
Не нужно, нужно оверрайд сделать в/etc/systemd/system/varnish.service.d/port.conf
:
[Service] ExecStart= ExecStart=/usr/sbin/varnishd -a :6081 -T 127.0.0.1:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,128m
antonwork
01.03.2016 00:46+2Все тоже самое делал только силами одного nginx, без Varnish. Вот типовая конфигурация nginx: (многое упростил)
fastcgi_cache_path /tmp/nginx_fcgi levels=1 keys_zone=zone1:512m; ... location ~ /help/([047][0-9]+)\.html { fastcgi_pass unix:/var/run/php-cgi.sock; ... include /etc/nginx/fastcgi_params; fastcgi_cache zone1; fastcgi_cache_valid 10m; fastcgi_cache_key "$host|$document_uri|$args"; }
В результате nginx получает банальный хеш md5 от строки, которую вы сами формируете в качестве ключа. Потом он, соблюдая иерархию вложения (задается конфигом), сохраняет ответ бэкенда в определенную директорию. Все что вам нужно — просто удалить этот файл, это и есть purge cahce. Можно все файлы удалить, можно выборочно. Из скрипта, мы знаем url страницы, которую нужно обновить. Просто вызываем функцию, удаляем файл и все.
function task_dropfrom_nginx ($hash) { if (file_exists ($path = sprintf ("/tmp/nginx_fcgi/%s/%s", substr($hash, -1), $hash))) { @unlink ($path); } } function cache_urldrop ($url, $args = '') { $hosts = array('ru.example.com', 'www.example.com', 'example.com'); foreach ($hosts as $host) { task_dropfrom_nginx ($hash = md5(sprintf ("%s|%s|%s", $host, $url, $args))); } }
У меня была еще следующая надстройка: на фронтендах крутился скрипт на пхп в 15 строчек, который слушал определенный udp порт (в моем случае обращение к нему было закрыто всем кроме внутренней подсети). С бэкэнда, обновившего страницу, просто делаем по адресам фронтендов (их было несколько) рассылку, один udp пакет — один сервер. И через пару миллисекунд кеш отчищен. Гипотетический пакет мог потеряться. Конкретно в моем случае это было не страшно, если кеш не сбросился бы. Если для вас это важно — используйте способы, гарантирующие доставку — очереди.
Плюс можно еще использовать ssi для этой связки. В результате можно главную страницу отдавать со скоростью статики (из кеша), разбавляя ее разными ssi инклудами, которые либо будут вытащены из кеша (мгновенно), либо будут сгенерированы на бэкенде. Еще модуль memcached творит чудеса, все тоже самое, но без обращений к диску.nikitasius
01.03.2016 01:56SSI очень мощная смесь на nginx для работы с бекендом.
А еще интереснее nginx (SSI), который формирует контент на страницу (картинки или тексты), который в свою очередь запрашивается с некоего подобия API за cloudflare (напрямую для медия или через JS).
Я все самописные вещи стараюсь делать через SSI и API за CF (тут CDN и как допкеш и для скорости).
Очень хочу вписать какой-нибудь сайт прямо в конфиг nginx (чтобы генерация была на стороне nginx "на лету" с его логикой).ivashkevitch
09.03.2016 21:17В Varnish есть подобная вещь — называется ESI. Если интересно, написал статью по использованию — https://habrahabr.ru/post/278899/
sfedosimov
01.03.2016 11:08+1Таким образом снижается скорость загрузки сайта и нагрузка на веб-сервер.
Может быть так:
Таким образом повышается скорость загрузки сайта и снижается нагрузка на веб-сервер.
evilbot
Прикрутите PHP 7.
ivashkevitch
В ближайших планах.