Varnish: кэширование с учётом cookies
Date August 28th, 2012 Author Vitaly Agapov
Возникла задача поднять кэширующий прокси-сервер. Но не простой прокси-сервер, а такой, который сможет кэшировать страницы в зависимости от определённой куки, определённым образом влияющей на отображение страницы.
Вариантов решения скорее всего здесь может быть много, но я смотрел в сторону varnish, с которым раньше приходилось работать и который мне чрезвычайно симпатичен. Главным же препятствием казалось то, что varnish по умолчанию не кэширует страницы, содержащие куки – раньше никогда этого и не требовалось, а куки и вовсе вырезались. Но решение нашлось. Varnish не подвёл.
Зачин
Для начала сабж нужно поставить в систему. В Ubuntu, на которой ставились эксперименты, он есть в стандартных репозиториях, но не самой последней свежести. Самой же последней свежести (на момент написание этих строк – 3.0.3) можно поставить из оф.репа:
curl http://repo.varnish-cache.org/debian/GPG-key.txt | sudo apt-key add - echo "deb http://repo.varnish-cache.org/ubuntu/ lucid varnish-3.0" | sudo tee -a /etc/apt/sources.list sudo apt-get update sudo apt-get install varnish
Параметры демона можно подкрутить в /etc/default/varnish. А подкручивать на продакшене их надо. При нехватке тредов, например, варниш может перестать отвечать на запросы от апача. У меня стоит так:
NFILES=131072 MEMLOCK=82000 INSTANCE=$(uname -n) VARNISH_VCL_CONF=/etc/varnish/default.vcl VARNISH_LISTEN_PORT=6081 VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 VARNISH_ADMIN_LISTEN_PORT=6082 VARNISH_MIN_THREADS=1000 VARNISH_MAX_THREADS=20000 VARNISH_THREAD_TIMEOUT=120 VARNISH_STORAGE_FILE=/var/lib/varnish/$INSTANCE/varnish_storage.bin VARNISH_STORAGE_SIZE=2G VARNISH_SECRET_FILE=/etc/varnish/secret VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" VARNISH_TTL=120 DAEMON_OPTS="-a :${VARNISH_LISTEN_PORT} \ -f ${VARNISH_VCL_CONF} \ -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ -t ${VARNISH_TTL} \ -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \ -S ${VARNISH_SECRET_FILE} \ -s ${VARNISH_STORAGE}"
Кульминация
Логика работы описывается с помощью языка VCL в файле (по умолчанию) /etc/varnish/default.vcl. В листинге я раскидал кое-какие комментарии, но главный секрет заключается в блоке vcl_hash, задающем, из каких составляющих образуется хэш-ключ для сохранения кэша. Мы с помощью функции hash_data добавляем к хэшу куки, из которых заранее в vcl_recv вырезали все, кроме нужных.
Следует обратить внимание, что в версии 2.х hash_data ещё не было. Тогда надо было набивать хэш командами вида set req.hash += req.url.
# путь к бэкенду backend web1 { .host = "127.0.0.1"; .port = "8080"; } # обработка запросов sub vcl_recv { # можно удалить авторизацию и куки. Куки мы пока оставляем if (req.http.Authorization) { #unset req.http.cookie; unset req.http.authorization; } # удаляем все куки кроме нужных нам needed.cookie1 и needed.cookie2. if (req.http.Cookie) { set req.http.Cookie = ";"+req.http.Cookie; set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";"); set req.http.Cookie = regsuball(req.http.Cookie, ";(needed.cookie1|needed.cookie2)=", "; \1="); set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", ""); set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", ""); if (req.http.Cookie == "") { remove req.http.Cookie; } } set req.backend = web1; if (req.request != "GET" && req.request != "HEAD") { /* Работаем только с GET и HEAD */ return (pass); } return (lookup); } sub vcl_hash { # Создаём хэш из урла и кук hash_data(req.url); hash_data(req.http.cookie); return (hash); } # обработка ответа от бэкенда sub vcl_fetch { # нужный урл кэшируем на 10 секунд, остальные - не кэшируем if (req.url ~ "some-path-to-cache") { set beresp.ttl = 10s; } else { set beresp.ttl = 0s; } # удаляем заголовок Set-Cookie из ответа remove beresp.http.Set-Cookie; return (deliver); } # доставка ответа sub vcl_deliver { # удаляем ненужные специфичные заголовки varnish unset resp.http.Via; unset resp.http.X-Varnish; return (deliver); }
Развязка
Теперь надо спроксировать нужные урлы с apache на varnish. Для этого можно использовать mod-proxy или mod-rewrite. Вот пример с mod-rewrite:
RewriteRule ^/(.*/some-path-to-cache/.*)$ http://our.varnish.ip:6081/$1 [P]
Как проверить работу varnish? Во-первых, нужно смотреть firebug'ом заголовок Age в ответе от сервера. Там указывается возраст страницы в кэше в секундах. Во-вторых, очень много информации можно получить утилитой varnishstat. Среди прочей информации она показывает:
Hitrate avg: 0.9898 Что из кэша отдаётся 98% запросов.
5137426 Cache hits Сколько отдано запросов из кэша с момента запуска
83205 Cache misses Сколько было запросов к бэкенду
Tags: Varnish
Category:
Varnish, Web-dev |
1 Comment »
21 March 2013 - 11:34
polipo?