MyTetra Share
Делитесь знаниями!
Использование nginx для кэширования статического контента на frontend-сервере
Время создания: 13.07.2018 15:31
Текстовые метки: nginx cache
Раздел: Nginx

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


Автор этих строк принимал участие в разработке и развёртывании комплекса серверов для большого веб-проект (одним из разработчиков которого он является) и далее вниманию читателей предлагается конфигурация веб-сервера nginx с одного из серверов проекта, которую можно в ряде случаев рекомендовать другим проектам, которые "переросли" простые и популярные конфигурации.


Немного подробнее о комплексе серверов: Схема стоит из трёх серверов: front, back1 и back2. front имеет два сетевых интерфейса. Один смотрит в интернет, а второй - на локальную сеть, в которой находятс back1 и back2. Это иллюстрирует схема:


Схема комплекса сереров


В реальности всё немного сложнее, как минимум есть ещё сервер базы данных и ещё кое-какие вспомогательные сервера, но рассмотрение этих серверов выходит за рамки данной статьи.


Основная задача фронтенда (сервер front) пересылать запросы на бэкенды (back1 и back2) разделяя нагрузку поровну, а в случае сбоя одного из бэкендов перенести всю нагрузку на оставшийся.


Фронтенд работает под управлением операционной системы FreeBSD 8.1 и на нём запущена тестовая версия nginx (в портах FreeBSD доступна как www/nginx-devel). Nginx собран со следующими опциями:


WITHOUT_DEBUG=true

WITHOUT_DEBUGLOG=true

WITHOUT_FILE_AIO=true

WITHOUT_IPV6=true

WITHOUT_GOOGLE_PERFTOOLS=true

WITH_HTTP_MODULE=true

WITHOUT_HTTP_ADDITION_MODULE=true

WITH_HTTP_CACHE_MODULE=true

WITHOUT_HTTP_DAV_MODULE=true

WITHOUT_HTTP_FLV_MODULE=true

WITHOUT_HTTP_GEOIP_MODULE=true

WITHOUT_HTTP_GZIP_STATIC_MODULE=true

WITHOUT_HTTP_IMAGE_FILTER_MODULE=true

WITHOUT_HTTP_PERL_MODULE=true

WITHOUT_HTTP_RANDOM_INDEX_MODULE=true

WITHOUT_HTTP_REALIP_MODULE=true

WITH_HTTP_REWRITE_MODULE=true

WITHOUT_HTTP_SECURE_LINK_MODULE=true

WITHOUT_HTTP_SSL_MODULE=true

WITH_HTTP_STATUS_MODULE=true

WITHOUT_HTTP_SUB_MODULE=true

WITHOUT_HTTP_XSLT_MODULE=true

WITHOUT_MAIL_MODULE=true

WITHOUT_MAIL_IMAP_MODULE=true

WITHOUT_MAIL_POP3_MODULE=true

WITHOUT_MAIL_SMTP_MODULE=true

WITHOUT_MAIL_SSL_MODULE=true

WITH_WWW=true

WITHOUT_CACHE_PURGE_MODULE=true

WITHOUT_ECHO_MODULE=true

WITHOUT_HEADERS_MORE_MODULE=true

WITHOUT_HTTP_ACCEPT_LANGUAGE=true

WITHOUT_HTTP_ACCESSKEY_MODULE=true

WITHOUT_HTTP_AUTH_PAM_MODULE=true

WITHOUT_HTTP_AUTH_REQ_MODULE=true

WITHOUT_HTTP_EVAL_MODULE=true

WITHOUT_HTTP_FANCYINDEX_MODULE=true

WITHOUT_HTTP_GUNZIP_FILTER=true

WITHOUT_HTTP_MOGILEFS_MODULE=true

WITHOUT_HTTP_MP4_H264_MODULE=true

WITHOUT_HTTP_NOTICE_MODULE=true

WITHOUT_HTTP_PUSH_MODULE=true

WITHOUT_HTTP_REDIS_MODULE=true

WITHOUT_HTTP_RESPONSE_MODULE=true

WITHOUT_HTTP_UPLOAD_MODULE=true

WITHOUT_HTTP_UPLOAD_PROGRESS=true

WITHOUT_HTTP_UPSTREAM_FAIR=true

WITHOUT_HTTP_UPSTREAM_HASH=true

WITHOUT_HTTP_UPSTREAM_KEEPALIVE=true

WITHOUT_HTTP_ZIP_MODULE=true

WITHOUT_MEMC_MODULE=true

WITHOUT_SLOWFS_CACHE_MODULE=true

WITHOUT_SUPERVISORD_MODULE=true

WITHOUT_UDPLOG_MODULE=true


Приведём сразу готовую конфигурацию nginx (файл /usr/local/etc/nginx/nginx.conf) опустив специфичные для проекта моменты:


# Количество форков основого процесса. Рекомендуется по одному форку на каждое процессорное ядрое

worker_processes 4;


# Для обработки очереди используем механизм kqueue

# На каждый форк устанавливаем ограничение в 1024 tcp-соединения

events {

worker_connections 1024;

use kqueue;

}



http {

# Не будем включать в http-заголовки информацию о сервере. Это немного повысит производительность.

server_tokens off;

# Описание MIME-типов

include mime.types;

# Неизвестные документы получат этот MIME-тип

default_type application/octet-stream;


# Без нужды в логи мусорить не будем

access_log /dev/null;


# Тонкие настройки обработки запросов

sendfile on;

aio off;

tcp_nodelay on;

tcp_nopush on;

# Именно столько и не больше будут жить устойчивые соединения

# Слишком большое значение приведёт к большому количеству полуоткрытых сокетов

# Слишком маленькое - не позволит клиентам насладиться всеми прелестями HTTP/1.1

keepalive_timeout 3;

# Настройки проксирования

client_body_buffer_size 128K;

client_header_buffer_size 128K;

client_max_body_size 1M;

large_client_header_buffers 1 1k;

proxy_temp_path /usr/home/nginx/proxy_temp;

proxy_cache_path /usr/home/nginx/proxy_cache levels=1:2 keys_zone=one:30m max_size=1g;

client_body_temp_path /usr/home/nginx/client_body_temp;

fastcgi_temp_path /usr/home/nginx/fastcgi_temp;

proxy_pass_header Cookie;

proxy_pass_header Set-Cookie;

proxy_cache_key $scheme$proxy_host$request_uri$http_cookie$http_set-cookie;

# Сжатие позволит отдавать контент клиентам быстрее

gzip on;

gzip_types application/x-javascript application/javascript text/css text/plain application/xml application/rss+xml text/vnd.wap.wml;

gzip_vary on;

gzip_comp_level 9;



# Описание апстрима - место, куда мы будем пересылать http-запросы

# Количество бэков может быть любым

# Параметр weight описывает приоритет бэка

# Параметр max_fails описывает количество сбоев подряд прежде чем бэк считаемся мёртвым

# Параметр fail_timeout указывает время, через которое можно попробовать снова использовать мёртвые бэки

upstream project_backends {

server back1 weight=10 max_fails=3 fail_timeout=30s;

server back2 weight=10 max_fails=3 fail_timeout=30s;

}

# Собственно описание сервера

server {

# Слушаем 80-й порт

listen *:80;

# Имя севера

server_name front;

# При пересылке запросов не будем менять значение заголовка Host

server_name_in_redirect off;

# Имя файла журнала

access_log /usr/home/logs/nginx-access.log;

# Все запросы

location / {

# Пересылаем запросы на бэкенды

proxy_pass http://project_backends;

proxy_redirect off;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

client_max_body_size 10m;

client_body_buffer_size 128k;

proxy_connect_timeout 30;

proxy_send_timeout 90;

proxy_read_timeout 90;

proxy_buffer_size 8k;

proxy_buffers 4 32k;

proxy_busy_buffers_size 64k;

proxy_temp_file_write_size 10m;

}

# Запросы к статике

location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {

# Принудительно указываем заголовок Expire

expires 30d;

# Запросы по прежнему пересылаем на бэкенды

proxy_pass http://project_backends;

# Однако здесь мы их кэшируем на один час

# Это позволяет немного разгрузить бэкенды

proxy_cache_valid 60m;

proxy_redirect off;

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_cache_key $scheme$proxy_host$request_uri$host;

proxy_cache one;

}

}

}


Основная изюминка этой конфигурации - кэширование статического контента на фронтенде, что позволяет с одной стороны ускорить обработку запросов к статическому контенту, а с другой - немного разгрузить бэкенды. Статистика за один час работы всего комплекса выглядит так:

Сервер: front back1 back2

Количестно HTTP-запросов: 1010426 149716 149566


Видно что количество запросов, пересылаемых бэкендам сократилось на 70%! Не менее интересны графики трафика на сетевых интерфейсах. Трафик на внешнем интерфейсе фронтенда:


Трафик NIC1 на front


В то время как трафик на втором интерфейсе фронтенда:


Трафик NIC2 на front


То есть отдавая клиентам поток до девяти мегабайт в секунду фронтенд сам создаёт поток трафика с бэкендов не более четырёх мегабайт в секунду. Можно говорить о том что бэкенды избавлены от солидной части работы по обработке статического контента и могут спокойно заниматься обработкой динамического контента:)


На этом всё. Приятной работы!


Так же в этом разделе:
 
MyTetra Share v.0.53
Яндекс индекс цитирования