Автономная работа frontend (заглушка, proxy_store, use_stale)

от автора

Введение

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

  • заглушка
  • proxy_store
  • proxy_cache_use_stale + memcache ttl=0

1. Заглушка

Это самый простой способ — положить статичную страничку на локальный диск по всей ферме и настроить rewrite на нее всех запросов.

server {   listen 80;   location / {     rewrite ^.*$ /maintance.html;   }   location /maintance.html {     alias .../maintance.html;   } } 

Преимущества

  • скорость подготовки
  • отсутствие сюрпризов во время работы
  • это лучше сообщений браузера о невозможности подключиться к серверу

Проблемы

  • пользователь получает не то, что хотел бы
  • проекты теряют деньги во время проведения технических работ

1.5

Долго так продолжаться конечно же не могло и, перед следующим плановым downtime на 8 часов, нам поставили задачу

откручивать рекламу любой ценой

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

2. proxy_store

На время проведения работ в ферму был включен nginx-night со следующими настройками

  • балансировщик отправлял на него четверть запросов пользователей
  • в качестве upstream по всем проектам выступали три основных узла фермы
  • все проходящие ответы записывались на SSD-массив с помощью директивы nginx proxy_store
location / {   proxy_pass              http://nginx-farm;   proxy_set_header        Host    $host;   proxy_set_header		X-Forwarded-For $remote_addr;   proxy_pass_header	X-Accel-Redirect;   proxy_pass_header	X-Accel-Expires;   proxy_ignore_headers	X-Accel-Redirect;   set $store_path         ---$request_uri---$query_string;   if ($store_path ~ "(.*)(.{1})(.{2})"){     set $new_store_path $3/$2/$store_path;   }   proxy_store             /data/cache/store/$host/$new_store_path; }  location ~ \.(flv|asf|mp4)$ {   proxy_pass              http://nginx-farm;   proxy_set_header        Host    $host;   proxy_set_header        X-Real-IP       $remote_addr; } 

В час Х основные узлы были выведены из балансировки, конфиг nginx-night изменен на примерно такой

location / {   root /data/cache/store/$host/;   set $store_path ---$request_uri---$query_string;   if ($store_path ~ "(.*)(.{1})(.{2})"){     set $new_store_path $3/$2/$store_path;   }   rewrite ^.*$ /$new_store_path break;   expires 1m; }  location ~ css {   default_type text/css;   root /data/cache/store/$host/;   set $store_path ---$request_uri---$query_string;   if ($store_path ~ "(.*)(.{1})(.{2})"){     set $new_store_path $3/$2/$store_path;   }   rewrite ^.*$ /$new_store_path break;   expires 1m; } 

По сравнению с заглушкой это был огромный шаг вперед, но

  • 700 MB/sec — именно такой была скорость записи на массив в режиме накопления данных
  • нет возможности сохранять статусы ответов и заголовки
  • для обработки user friendly urls, разбиения страниц на подкаталоги пришлось разбивать uri регуляркой и дописывать query_string — это исключает возможность определения content type для большинства сохраненных файлов (именно для этого пришлось уже в боевом режиме вводить дополнительный location для css)
  • никто не гарантирует, что 1 url = 1 страница (персонализированные блоки, pjax)
  • при накоплении больше 200GB SSD-массив начинал уходить в себя
2.5

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

  • локальные кеши легли на ramdisk, размеры проектных кешей за счет этого увеличились более чем на порядок, inactive выставлен в десять часов
  • чтение статики с хранилища вынесено на отдельный пул процессов nginx на каждом узле, раздающий проксирует запросы на него, для мелкой статики организованный локальный кеш на ramdisk
  • на нескольких узлах memcache организован глобальный кеш, управляемый приложениями

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

3. proxy_use_stale

На всех проектах выставлен

proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; 

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

  • на nginx узлах подняты memcache, все проекты, пишущие данные в memcache, дополнительно записывали их в эти instance с ttl=0 (бесконечным временем жизни)
  • наведен некоторый порядок в проектных конфигах — все настройки upstream (app и memcache) вынесены в отдельные файлы
  • для персонализированных блоков предусмотрен downgrade при недоступности backend

И далее идет штатная эксплуатация всей площадки до момента Х, когда проводятся следующие манипуляции

  • опускаем пул процессов, читающих с хранилища — мелкая статика, не попавшая в CDN, отдается с кеша по use_stale
  • переписываем app upstream’s на несуществующий локальный порт и ставим ему connection_timeout 5ms, снова работает use_stale
  • переписываем адреса memcache, эта часть работает штатно

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

  • потребовались некоторые изменения в приложениях
  • часть проектов у нас делают no-cache, часть из них из-за ошибок в конфигурациях, для таких кусков стоит делать degrade
  • локальность кешей не гарантирует наличие свежих статей на всех узлах, пользователи натыкались на 404-ые и 502-ые
  • отдельно стоят малопосещаемые проекты, их кеши перед такими работами следует прогревать
  • по прежнему не имеем защиты от некорректных данных в кешах

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

3.5

Для следующего шага основной целью станет научиться говорить «ДА» в ситуации «все пропало, нам срочно надо откатить проект на 15/30 минут назад, можете ли вы это сделать, а мы пока исправим причины» )

proxy_store
proxy_cache_use_stale
proxy_cache_path
Memcache::set

ссылка на оригинал статьи http://habrahabr.ru/post/162949/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *