OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

HAProxy HTTP Cache: практическое руководство для реверс‑прокси

Разбираем встроенный HTTP cache в HAProxy: когда он уместен, как писать правила и учитывать headers, выбирать TTL, нормализовать запросы, следить за метриками и избегать ловушек. Материал для админов и DevOps, кто строит быстрый reverse proxy и хочет срезать задержки и нагрузку на origin.
HAProxy HTTP Cache: практическое руководство для реверс‑прокси

Встроенный HTTP cache в HAProxy — лёгкий способ ускорить ответы и разгрузить origin без отдельного слоя вроде Varnish. Он особенно полезен, когда уже используете HAProxy как reverse proxy и балансировщик, а кэшировать нужно небольшие и часто запрашиваемые объекты: статические JSON/конфиги, небольшие изображения и иконки, ответы health/status, метаданные. Если вы планируете держать HAProxy на выделенном сервере, удобно развернуть его на облачном VDS — так проще масштабировать и контролировать ресурсы.

Как работает HAProxy HTTP cache: краткий обзор

Кэш HAProxy хранит объекты в оперативной памяти, использует политику вытеснения LRU и обслуживает запросы напрямую из процесса прокси. Это даёт очень низкую задержку ответа и минимальную нагрузку на origin, но накладывает ограничения:

  • Память: общий объём кэша ограничивается конфигурацией и физической RAM; кэш «дорогой», большие файлы хранить невыгодно.
  • Ключ: базовый ключ — URL запроса (путь и query). Это хорошо для версионируемых URL и статических путей, но требует нормализации запросов (срезать «мусорные» параметры, фиксировать порядок параметров, если нужно).
  • TTL: срок жизни берётся из ответа origin (директивы Cache-Control и Expires) или дефолтного max-age в секции cache, если заголовков нет. Фоновой ре-валидации нет.
  • Функциональность: это не полноценный кэш с глубоким учётом Vary и условной валидацией; ориентируйтесь на «тёплые» небольшие ответы и простые правила.

Именно из-за этих ограничений HAProxy-кэш отлично выступает как edge-оптимизация, но не претендует на роль CDN или сложного фрагментного кэширования.

Когда включать HAProxy HTTP cache

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

  • Короткие JSON/JS/конфигурационные эндпойнты (метаданные, роутинг, настройки), запрашиваемые тысячами клиентов.
  • Микросервисы со «соглашённой» консистентностью: допустимо обновление раз в 30–300 секунд.
  • Статика повышенного спроса, но небольшого объёма: иконки, SVG, фавиконки, маленькие PNG, открытые шрифты.
  • API с версионируемыми URL (cache-busting через версии в пути/параметрах) и одинаковыми ответами для многих клиентов.

Избегайте кэшировать большие файлы, ответы с персональными данными или зависящие от авторизации/куков, а также всё, что отдаётся с учётом устройства/языка без нормализации заголовков.

Диаграмма потоков: запросы в HAProxy, попадание в кэш (hit) и обращение к origin (miss)

Базовая схема конфигурации

Минимально рабочая конфигурация кэша в HAProxy: объявляем секцию cache с лимитами, включаем cache-use на запросах и отмечаем ответы для сохранения через cache-store при нужных условиях.

# Раздел cache: лимиты и дефолтный TTL
cache mycache
    total-max-size 256
    max-object-size 1m
    max-age 300

# Фронтенд (пример)
frontend fe_http
    bind :80
    mode http
    option httplog

    # Обслуживать из кэша, если объект найден
    http-request cache-use mycache

    default_backend be_app

# Бэкенд к приложению
backend be_app
    mode http

    # Кэшируем только успешные GET-ответы без приватных директив
    acl is_get method GET
    acl ok_status status 200
    acl no_private res.hdr(Cache-Control) -m sub private
    acl no_nostore res.hdr(Cache-Control) -m sub no-store

    http-response cache-store mycache if is_get ok_status no_private no_nostore

    server app1 10.0.0.10:8080 check
    server app2 10.0.0.11:8080 check

Здесь мы сознательно не кэшируем ответы, если сервер помечает их Cache-Control: private или no-store. За основу TTL берётся Cache-Control: max-age или Expires (если сервер их вернул), иначе — дефолт max-age из секции cache.

Дизайн ключа кэша и нормализация запросов

Поскольку ключ кэша определяется URL, важно сделать ответы детерминированными для одинаковых запросов. Несколько практических шагов:

  • Нормализуйте бессмысленные параметры: если есть трекинг-параметры (например, utm_*) и они не влияют на ответ, срезайте их на уровне приложения или маршрутизации.
  • Единый формат: порядок параметров, регистр в пути и т. п. Лучше обеспечивать на уровне приложения, часть можно выровнять на входе.
  • Выносите вариативность в версию ресурса: /api/v2/config.json или /config.json?v=2025-02-01. Замена версии — «инвалидирование» кэша без purge.

Если у вас есть варианты ответа по языку/региону/платформе, избегайте зависимостей от непредсказуемых headers. Лучше явно отражайте их в URL (например, /v2/ru/config.json), чтобы ключ кэша был однозначным.

Учёт заголовков: что пропускать и что нормализовать

Правила простые, но критичные для безопасности и корректности:

  • Не кэшируйте, если присутствует Authorization или сессионные Cookie. Проще всего запретить cache-store при таких заголовках и/или разделить локации на публичные и приватные.
  • Избегайте зависимостей от Accept-Encoding, если не готовы к аккуратной нормализации. В идеале отдавайте на origin либо без сжатия, либо стабильно сжатую версию. Смешение сжатого и несжатого без Vary приведёт к неверной раздаче.
  • Сохраняйте ETag и Last-Modified — клиенты смогут валидировать объекты напрямую с origin после истечения TTL. Сам HAProxy не делает условную валидацию и просто перестаёт использовать истёкший объект.
# Запрет кэширования при наличии авторизации или кук
backend be_app
    acl is_get method GET
    acl ok_status status 200
    acl no_private res.hdr(Cache-Control) -m sub private
    acl no_nostore res.hdr(Cache-Control) -m sub no-store
    acl has_auth req.hdr(Authorization) -m found
    acl has_cookie req.hdr(Cookie) -m found

    http-response cache-store mycache if is_get ok_status no_private no_nostore !has_auth !has_cookie

Выбор TTL и стратегии обновления

Выбор TTL — баланс между «свежестью» и разгрузкой origin. Несколько практик:

  • Для простых статических JSON/JS: 60–300 секунд. Клиенты редко страдают от минутной задержки обновления.
  • Для иконок/шрифтов: 1 час и больше при версионировании в URL. Тогда «вечный» кэш допустим.
  • Для чувствительных метаданных: 10–30 секунд, и обязательно предусмотреть быструю смену версии URL для «тёплой» прокатки.

Если origin рассылает корректные Cache-Control, используйте их как источник истины. Если нет — задавайте дефолты в секции cache и постепенно переводите управление TTL на сторону приложения.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Что не стоит кэшировать

Лучше исключить из HAProxy HTTP cache следующее:

  • Крупные медиа-файлы и архивы: RAM-дорогие, часто с Range-запросами, ограниченная выгода (см. разбор нюансов в статье про Range и кэш).
  • Персонализированный контент и любые ответы, зависящие от сессии, куков или авторизации.
  • Ответы с высокими требованиями к консистентности (платёжные статусы, корзины) — здесь лучше кэш приложения с точной инвалидацией.

Наблюдаемость: как понять, что кэш работает

В полевых условиях удобно проверять кэш через повторные запросы и заголовки. Появление Age на повторном запросе — хороший признак кэш‑хита на стороне прокси.

# Простой ручной тест
curl -I http://your-proxy.example/config.json
sleep 1
curl -I http://your-proxy.example/config.json

Для постоянной наблюдаемости используйте:

  • Логи HAProxy с метриками времени ответа: падение латентности и количества обращений к backend — основной индикатор.
  • Счётчики backend (из stats) — уменьшение RPS на приложении при стабильном клиентском трафике означает, что кэш снимает нагрузку.

Наблюдаемость: лог и графики задержек до и после включения HAProxy HTTP cache

Производительность и лимиты памяти

Основные «ручки» для планирования объёма кэша:

  • total-max-size — общий лимит RAM под кэш. Начинайте скромно (128–512 МБ) и расширяйте по факту.
  • max-object-size — максимальный размер объекта. Ставьте потолок, чтобы случайные крупные файлы не «выели» кэш.
  • Доля «горячих» объектов: чем более Zipf-подобный запросный поток, тем выше отдача даже при небольшом объёме.

Помните, что кэш живёт в процессе HAProxy. Планируйте запас под буферы, TLS и сжатие (если включено).

Безопасность и гигиена заголовков

Кэш — это не только про скорость, но и про безопасность. Несколько правил гигиены:

  • Не кэшируйте ответы с Set-Cookie, если они могут течь между пользователями. Общее правило — любые ответы с Set-Cookie исключать.
  • Уважайте директивы Cache-Control origin: private, no-store, no-cache — запрет на cache-store. При необходимости делайте адресные исключения.
  • Не смешивайте gzip/identity без нормализации. Если нужно, приводите Accept-Encoding к единому значению или разносите варианты по URL.

Если вы терминируете TLS на фронте, заранее позаботьтесь о сертификатах. Для продакшена подойдут проверенные SSL-сертификаты.

Инвалидация: как жить без purge

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

Полный сброс кэша как крайняя мера — через перезапуск/перечтение конфигурации; это затрагивает соединения и не годится как регулярный инструмент. Когда нужна строгая инвалидация и сложные зависимости, используйте кэш приложения — см. кэширование на стороне приложения (Memcached/Redis).

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Типовые рецепты правил

Кэшировать только «белый список» путей

acl cache_path path_beg /static/ /assets/ /public-api/
acl is_get method GET
acl ok_status status 200 301 404
acl has_auth req.hdr(Authorization) -m found
acl has_cookie req.hdr(Cookie) -m found
acl no_private res.hdr(Cache-Control) -m sub private
acl no_nostore res.hdr(Cache-Control) -m sub no-store

http-response cache-store mycache if is_get cache_path ok_status !has_auth !has_cookie no_private no_nostore

Уважать TTL origin, но иметь дефолт

Если приложение не расставляет Cache-Control, используем дефолт из секции cache. Когда заголовки появятся, HAProxy применит их автоматически — удобный переходный период.

Отдельный кэш для «живых» API и для статики

Если хотите по-разному ограничивать размер объектов и TTL, заведите две секции cache и используйте соответствующие правила cache-store/cache-use на нужных локациях. Например, для API — max-object-size 64k, для статики — 512k и больше.

Тестирование и контроль качества

План тестов перед включением кэша в прод:

  1. Соберите список эндпойнтов-кандидатов: только GET, публичные, без персонализации.
  2. Проверьте корректность заголовков origin: отсутствие Set-Cookie, ожидаемые Cache-Control, отсутствие приватных директив.
  3. Включите кэш в стейджинге, используйте повторные запросы и сравнивайте тайминги. Убедитесь, что логика приложения не нарушилась.
  4. Проверьте обновление контента: смените версию URL, убедитесь, что новые клиенты получают новую версию, а старая живёт до истечения TTL.
  5. Зафиксируйте алерты: рост 5xx на backend, неожиданные коды 304/412 у клиентов, всплески латентности — поводы пересмотреть правила.

Частые ошибки и как их избежать

  • Кэширование ответов с куками. Лечится жёстким запретом cache-store, если есть Cookie или Set-Cookie.
  • Смешение gzip/identity. Либо нормализуйте Accept-Encoding, либо выключите сжатие на origin для кэшируемых локаций, либо разнесите по URL.
  • Кэширование слишком крупных объектов. Подрежьте max-object-size, ведите «белые списки» путей.
  • Отсутствие версии в URL. Любые «вечные» TTL безопасны только при версионировании имён файлов/путей.
  • Попытка использовать кэш как механизм строгой консистентности. Для этого нужен application-level cache с управляемой инвалидацией.

Пошаговая стратегия внедрения

Рекомендую идти от простого к сложному:

  • Шаг 1. Включите кэш на узком наборе статических локаций. Отследите эффект на RPS и latency backend.
  • Шаг 2. Добавьте «лёгкие» API (конфиги, справочники) с TTL 60–120 секунд. Убедитесь, что для них нет зависимости от Cookie/Authorization.
  • Шаг 3. Отрефакторьте заголовки origin: выставляйте корректные Cache-Control, чтобы управлять TTL централизованно.
  • Шаг 4. Разделите кэш-пулы при необходимости, чтобы задать разные лимиты размера объектов и сроков хранения.
  • Шаг 5. Введите регламент: как «прокатывать» изменения через версию URL и как быстро сворачивать TTL в инцидентах.

Итог

HAProxy HTTP cache — прагматичный инструмент для ускорения публичных GET-ответов и снижения нагрузки на origin, когда вам уже нужен reverse proxy и нет желания поднимать отдельный кэширующий слой. Он прост, предсказуем, хорошо вписывается в инсталляции и дисциплинирует подход к headers, URL-версии и TTL. Ключ к успеху — держать область применения разумной: только публичный контент, маленькие объекты, чёткая нормализация запросов и уважение к Cache-Control. Тогда кэш будет работать быстро и безопасно, без неприятных сюрпризов.

Поделиться статьей

Вам будет интересно

Nginx proxy_cache_path: разбор keys_zone, max_size, inactive и тонкая настройка OpenAI Статья написана AI (GPT 5)

Nginx proxy_cache_path: разбор keys_zone, max_size, inactive и тонкая настройка

Если вы кэшируете ответы через Nginx, директива proxy_cache_path определяет каталог на диске, глубину levels, объём keys_zone и пр ...
Apache mod_md и ACME: автоматизация SSL без и с cron OpenAI Статья написана AI (GPT 5)

Apache mod_md и ACME: автоматизация SSL без и с cron

Покажу, как включить модуль mod_md в Apache и настроить автоматизацию ACME с Let’s Encrypt без внешних скриптов. Разберём рабочие ...
MTA-STS и TLSRPT: настраиваем защищённый SMTP и отчётность в Postfix OpenAI Статья написана AI (GPT 5)

MTA-STS и TLSRPT: настраиваем защищённый SMTP и отчётность в Postfix

MTA-STS и TLSRPT закрывают две болезненные точки SMTP: принудительный TLS для исходящих отправителей и прозрачность ошибок шифрова ...