Распределенный кеш на основе Nginx и proxy_cache

При использовании кеширования место на диске рано или поздно закончится. В таком случае обычно используют очистки кеша. Например, удалять все файлы, которые на запрашивались больше 7 дней. В Nginx это настраивается так:

proxy_cache_path /var/cache/nginx inactive=7d levels=1:2:2 keys_zone=local_cache:50m max_size=10g;

# правило удаления файлов из кеша

Но ясно, это ухудшит опыт пользователей.

Распределенный кеш

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

Такой вариант будет полезен при отдаче большого количества файлов. Особенно больших, вроде видео или фоток. Применять это стоит, например, в рамках системы оптимизации затрат на CDN.

Распределение запросов

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

Пусть у нас есть два сервера:

  • 165.227.150.69
  • 207.154.211.168

Если запрос пришел на первый сервер, мы хотим только половину запросов отдать с него же. А вторую половину отправить на второй сервер. То же самое и для второго сервера, только для второй половины запросов:

Распределение делается на основе upstream hash:

upstream cluster {
    hash $request_uri consistent;

    server 165.227.150.69:81;
    server 207.154.211.168:81;
}

server {
	listen 80;
	location / {
		proxy_pass http://cluster;
	}
}

server {
	listen 81;
	root /var/www/html;

	rewrite ^(.*)$ index.php;

        location ~* \.(php)$ {
            fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME /var/www/html/index.php;
        }
}

# Распределение запросов в Nginx на основе consistent hash

Тут мы:

  • С помощью блока upstream cluster определяем список серверов. На них будет отправлен исходный запрос. Так, один из них — это и есть сам сервер, а второй — его сосед.
  • hash $request_uri consistent определяет принцип распределения запросов (в нашем случае — consistent hashing).
  • Первый виртуальный сервер слушает порт 80. Он просто отправляет запрос на upstream.
  • Второй виртуальный сервер обслуживает запрос (в примере — php скрипт).

Добавляем кеш

Теперь достаточно в нашу конфигурацию добавить промежуточный виртуальный сервер, который будет кешировать данные. Виртуальный сервер с порта 81 перенесем на 82. А порт 81 займем сервером для кеширования:

upstream cache_cluster {
    hash $request_uri consistent;

    server 165.227.150.69:81;
    server 207.154.211.168:81;
}

server {
	listen 80;
	location / {
		proxy_pass http://cache_cluster;
	}
}


proxy_cache_path /var/cache/nginx levels=1:2:2 keys_zone=local_cache:50m max_size=10g;
proxy_cache_key "$uri";
server {
	listen 81;

        location / {
            proxy_cache local_cache;
            proxy_pass http://127.0.0.1:82;
	    proxy_cache_valid 200 21d;
	    proxy_cache_methods GET;
        }
}

server {
	listen 82;
	root /var/www/html;

	rewrite ^(.*)$ index.php;

        location ~* \.(php)$ {
            fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME /var/www/html/index.php;
        }
}

# Распределенный кеш запросов

Теперь, кроме распределения запросы еще и кешируются. Часть файлов кеша будет складываться на один сервер. Вторая часть — на другой. Места для хранения кеша стало в два раза больше. То, что мы и хотели получить.

Внутренний трафик

Обратите внимание. Один сервер проксирует часть запросов со второго. Это может вызвать проблемы, если сервера отдалены географически. В таком случае, имеет смысл использовать группы серверов, которые расположены рядом (в одном ДЦ).

Трафик между узлами значительно вырастит, если серверов станет очень много. Также решается группировкой серверов (например, по 10 в одной группе).

Доступность

Теперь сервера зависят друг от друга. И если поломается один, эту ошибку сразу увидят пользователи. Для обеспечения высокой доступности, следует всегда ставить (минимум) по паре серверов, которые будут выступать копиями друг друга. Тогда при сбое одного можно будет автоматически переключаться на другой.

TL;DR

  • Nginx позволяет настроить распределенный кеш между несколькими серверами. Его стоит использовать для повышения эффективности кеша (больше места = больше hitrate).
  • Не стоит использовать более 10 серверов в одной группе распределенного кеша.
  • Для обеспечения высокой доступности стоит иметь работающую копию каждого сервера.

Подпишитесь на Хайлоад с помощью Google аккаунта
или закройте эту хрень