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

Apache mod_cache: CacheQuickHandler, cache_disk vs cache_socache

Если Apache — фронтенд или бэкенд для PHP/FCGI/прокси, mod_cache заметно разгружает приложение. Разбираем CacheQuickHandler, выбор cache_disk или cache_socache, настройку микрокэша в памяти, корректный Vary и безопасное кэширование авторизованных зон.
Apache mod_cache: CacheQuickHandler, cache_disk vs cache_socache

Кэширование в Apache — тема с историей, но с приходом Apache 2.4 стек стал гибче: mod_cache выполняет политику кэширования, а провайдеры (cache_disk и cache_socache) хранят объекты на диске или в памяти/внешнем socache. Ключевую роль в производительности играет CacheQuickHandler: этот флаг определяет, будет ли кэш обслуживать запрос ещё до большинства хуков (переписывания, авторизации), или же отдача из кэша произойдёт позже, после стандартной обработки. Разберёмся, как это устроено на практике и какие режимы выбирать под разные нагрузки.

Как устроен mod_cache и откуда берётся выигрыш

Архитектурно mod_cache принимает решение: кэшировать ли ответ и можно ли отдать кэш вместо запроса к бэкенду. Для этого используется ключ кэша (обычно URL со схемой/хостом/портом/путём и строкой запроса плюс вариации по заголовкам из Vary). Факт кэшируемости определяется HTTP-заголовками (Cache-Control, Expires, ETag, Last-Modified) и локальными правилами (CacheIgnore..., CacheStore...). Провайдер хранит объект и метаданные: cache_disk — в файловой системе, cache_socache — в общем кэше (shared object cache: shmcb, memcache, redis и т.п.).

Выгода простая: если вы отдаёте статические файлы, проксируете до приложения или API — кэш способен сократить TTFB и резко уменьшить RPS на бэкенд. В микрокэш-сценарии (1–5 секунд) удаётся погасить всплески и дедуплицировать одинаковые запросы.

CacheQuickHandler: быстрый путь или «по правилам»

CacheQuickHandler определяет, где именно в конвейере Apache будет отдан кэш:

  • On — кэш отрабатывает максимально рано, до большинства модулей (переписывание URL, авторизация, директории и т.д.). Это самый быстрый вариант: меньше оверхеда, минимум файловых операций, чаще всего — лучший TTFB и RPS.
  • Off — кэш участвует позже. Так вы сохраняете предсказуемость сложных цепочек с mod_rewrite, авторизацией, mod_security, пользовательскими SetEnvIf и пр. Цена — небольшое падение производительности.

Правило: включайте CacheQuickHandler On в простых ветках (публичный контент, картинки, статические файлы, CDN-ориджин). Отключайте (Off) там, где безопасность и логика критичнее микровыгрышей скорости: авторизация, сложные переписи, индивидуальные куки.

Подводные камни CacheQuickHandler

  • Если для ресурса требуется авторизация, ранний кэш теоретически может отдать публичный ответ раньше проверки. Решение — CacheQuickHandler Off на уровне нужного <Location> или <Directory>.
  • Сложные правила с mod_rewrite и условиями на заголовки/переменные могут не сработать при раннем возврате кэша. Если логика переписывания влияет на кэш-ключ, отключайте QuickHandler в этой ветке.
  • При отладке «хит/миссов» учитывайте, что ранний кэш может обойти часть логов. Настройте отдельный формат логирования для заметок кэша, чтобы видеть реальный статус запроса.

cache_disk vs cache_socache: что выбрать

Роль провайдера кэша — быстро и надёжно хранить закэшированные объекты. В Apache 2.4 основных два:

cache_disk

  • Постоянство: переживает перезапуски сервера; можно держать десятки и сотни гигабайт.
  • Универсальность: хорошо для больших объектов (изображения, архивы) и долгих TTL.
  • Стоимость: IO медленнее RAM, чувствителен к мелким объектам и глубокой структуре каталогов (настроить CacheDirLevels/CacheDirLength).

cache_socache

  • Скорость: хранение в забэкенженном socache (shmcb, memcache, redis). Отличный выбор для микрокэша (1–10 секунд).
  • Ограничения размера: разумный потолок для каждого объекта; большие файлы — не сюда.
  • Жизненный цикл: в памяти исчезает при рестарте (если shmcb). Memcached/Redis — сохраняют кэш до очистки/TTL, но это внешний сервис.

Итого: диск — для больших и «долго живущих» объектов; socache — для быстрых короткоживущих ответов, сглаживания пиков и микрокэширования динамики.

Диаграмма конвейера Apache с CacheQuickHandler до авторизации и переписываний

Типовые сценарии

1) Публичные статические файлы

Большие TTL, предсказуемые ключи, нет авторизации. Идеален cache_disk с CacheQuickHandler On. На небольших проектах на виртуальном хостинге часто достаточно правильно выставить TTL и заголовки (Cache-Control: public, max-age=...).

2) Микрокэш динамики

PHP/FCGI/прокси-апп отдаёт одинаковые ответы для большинства неавторизованных пользователей. Кэшируем на 1–5 секунд в cache_socache, включаем блокировку (CacheLock) против «стаи» одновременно идущих запросов.

3) API с Vary

Ответ зависит от Accept или Accept-Encoding — убедитесь, что бэкенд выставляет Vary. Это критично для правильного ключа кэша и отсутствия «склейки» ответов.

4) Авторизованные области

Обычно не кэшируем. Если требуется кэширование части ответов, изолируйте контекст, используйте CacheQuickHandler Off, внимательно работайте с Set-Cookie, Cache-Control: private/no-store и тестируйте, что персонализация не попадёт в общий кэш.

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

Убедитесь, что задействованы нужные модули: mod_cache, mod_cache_disk или mod_cache_socache, а также mod_headers, mod_expires при необходимости. На Debian/Ubuntu:

a2enmod cache cache_disk headers expires
systemctl reload apache2

Либо для cache_socache и выбранного провайдера (shmcb, memcache, redis):

a2enmod cache cache_socache socache_shmcb headers
# или с провайдером memcache/redis, если установлен соответствующий модуль
# a2enmod socache_memcache
# a2enmod socache_redis
systemctl reload apache2
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Настройка cache_disk: надёжный дисковый кэш

Пример VirtualHost с публичным статическим контентом. Включим быстрый обработчик, кэширование по префиксу и разумные лимиты размеров файлов.

<VirtualHost *:80>
    ServerName static.example

    CacheQuickHandler On
    CacheEnable disk /

    # Корень кэша, глубина каталогов, длина сегмента
    CacheRoot /var/cache/apache2/mod_cache_disk
    CacheDirLevels 2
    CacheDirLength 2

    # Размеры объектов
    CacheMinFileSize 1
    CacheMaxFileSize 104857600

    # Блокировка от «стаи»
    CacheLock On
    CacheLockPath /var/lock/apache2/mod_cache_lock
    CacheLockMaxAge 5

    # При ошибке бэкенда можно отдать устаревшее
    CacheStaleOnError On

    # Игнорируем отсутствие Last-Modified, если контент всё равно публичен
    CacheIgnoreNoLastMod On

    # Не кэшировать ответы, запрещённые политикой клиента
    CacheIgnoreCacheControl Off

    # Заголовки клиентского кэширования (если приложение не задаёт)
    <Location /assets/>
        ExpiresActive On
        ExpiresDefault "access plus 30 days"
        Header set Cache-Control "public, max-age=2592000, immutable"
    </Location>

    DocumentRoot /var/www/static
</VirtualHost>

Ключевые моменты:

  • CacheRoot вынесите на быстрый диск и мониторьте размер.
  • CacheDirLevels/CacheDirLength подбираются эмпирически: слишком мелко — перегрузка каталогов, слишком глубоко — много inode.
  • CacheStaleOnError пригоден для фронтов поверх нестабильных бэкендов: лучше старый ответ, чем 5xx.

Настройка cache_socache: микрокэш на памяти/внешнем k/v

Для короткого TTL и высоких RPS подходит cache_socache. Выберите провайдера: shmcb (общая память ОС), memcache или redis при наличии соответствующих модулей. Если поднимаете memcached/Redis на отдельном узле, это удобно делать на VDS — так проще масштабировать фронтенды горизонтально.

<VirtualHost *:80>
    ServerName app.example

    # В микрокэше часто хотим быстрый путь
    CacheQuickHandler On

    # Включаем кэш в socache
    CacheEnable socache /

    # Выбор провайдера socache (один из вариантов)
    # shmcb: сегмент общей памяти (указать файл и размер сегмента в байтах)
    CacheSocache shmcb:/var/cache/apache2/socache_shmcb(33554432)
    # memcache: внешний memcached кластер
    # CacheSocache memcache:127.0.0.1:11211
    # redis: внешний Redis (при наличии модуля)
    # CacheSocache redis:127.0.0.1:6379

    # Лимиты на размер объекта (микрокэш маленьких ответов)
    CacheSocacheMinObjectSize 1
    CacheSocacheMaxObjectSize 262144

    # Блокировка от «стаи» и устаревшее при ошибке
    CacheLock On
    CacheLockMaxAge 5
    CacheStaleOnError On

    # Секундные TTL применяем со стороны приложения или заголовками ниже
    <Location /api/public/>
        # Только публичные ответы без персонализации
        Header unset Set-Cookie
        Header set Cache-Control "public, max-age=3, s-maxage=3, stale-if-error=30"
    </Location>

    # Проксирование до приложения (пример)
    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>

Примечания:

  • shmcb живёт только в рамках одного процесса/узла и очищается при рестарте. Это честный RAM-кэш, быстрый и простой.
  • При memcache/redis кэш переживёт рестарт Apache и может быть общим для фронтендов.
  • Лимиты на объект защищают от попытки хранить большие ответы в RAM.
  • Строго избегайте кэширования персонализированных ответов с Set-Cookie и Cache-Control: private. В примере мы удаляем Set-Cookie только для зоны, где гарантированно нет персонализации.

Сравнение cache_disk и cache_socache: плюсы и минусы

Vary, ключ кэша и канонизация

Ключ кэша зависит от URL и набора заголовков из Vary. Практические советы:

  • Всегда выставляйте Vary: Accept-Encoding для компрессии, если она включена. Иначе возможна подмена gzip/identity.
  • Если ваш API действительно зависит от Accept или других заголовков — явно добавляйте их в Vary.
  • Стабилизируйте URL: избегайте «мусорных» параметров в строке запроса. При необходимости канонизируйте ключ с помощью CacheKeyBaseURL там, где фронтенд и бэкенд видят разные хосты/схемы.

Подробно о выборе TTL, директивах Cache-Control и ETag мы писали в материале как правильно выставлять Cache-Control и ETag. Для больших файлов пригодится разбор кэширования Range-запросов.

Контроль кэшируемости: заголовки и директивы

  • Приложение должно говорить, можно ли кэшировать: Cache-Control, Expires, ETag, Last-Modified.
  • Apache может помочь, когда приложение «молчит»: используйте mod_expires и mod_headers для установки Cache-Control/Expires.
  • Нельзя кэшировать то, что помечено no-store или персонализировано Set-Cookie без строгой изоляции. В крайнем случае — CacheIgnoreHeaders Set-Cookie только в заведомо публичных локациях.
  • Директивы CacheIgnoreNoLastMod и CacheIgnoreCacheControl аккуратно: не ломайте политику клиентов и кэш-семантику ответа.

Защита от «стаи»: CacheLock

Когда много клиентов одновременно запрашивают один и тот же несуществующий в кэше ключ, бэкенд получает «лавину». Включайте CacheLock On. Первый запрос «запирает» ключ, остальные ждут. Это особенно важно в микрокэше.

Диагностика и наблюдение

  • Смотрите на заголовок Age: ненулевой — ответ из кэша или с реконфирмацией по If-None-Match/If-Modified-Since.
  • Уточняйте, срабатывает ли кэширование по пути: временно задайте короткие TTL, проверяйте разницу в TTFB/CPU на бэкенде.
  • Логируйте статусы кэша: добавьте заметки в формат access log и анализируйте HIT/MISS/REVALIDATE. В тестовой среде полезно временно включить подробный уровень логирования модулей кэша.

Рецепт: смешанный режим — диск для статики, socache для микрокэша

Нередко идеальна комбинация: статические файлы и крупные объекты на диске; короткие ответы динамики — в socache на несколько секунд.

<VirtualHost *:80>
    ServerName mixed.example

    # Статика: диск
    CacheQuickHandler On
    CacheEnable disk /assets/
    CacheRoot /var/cache/apache2/mod_cache_disk
    CacheDirLevels 2
    CacheDirLength 2
    CacheMaxFileSize 104857600

    # Динамика: микрокэш в памяти (шаред-мемори)
    CacheEnable socache /api/public/
    CacheSocache shmcb:/var/cache/apache2/socache_api(67108864)
    CacheSocacheMaxObjectSize 131072

    # Общие опции
    CacheLock On
    CacheLockMaxAge 5
    CacheStaleOnError On

    # Политики для каждой зоны
    <Location /assets/>
        ExpiresActive On
        ExpiresDefault "access plus 30 days"
        Header set Cache-Control "public, max-age=2592000, immutable"
    </Location>

    <Location /api/public/>
        Header unset Set-Cookie
        Header set Cache-Control "public, max-age=5, s-maxage=5, stale-if-error=60"
        Header append Vary "Accept,Accept-Encoding"
    </Location>

    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>

Когда отключать CacheQuickHandler

  • Внутри зон с авторизацией: <Location /private/> CacheQuickHandler Off </Location>, чтобы аутентификация и ACL сработали до кэша.
  • Где mod_rewrite меняет путь/параметры и это влияет на ключ кэша.
  • При тонком контроле заголовков через SetEnvIf/RequestHeader, которые должны выполниться до решения о кэше.
Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Тонкая настройка для высокой нагрузки

  • Выберите адекватный storage: быстрые SSD для cache_disk; достаточно RAM и размер сегмента для shmcb; отдельный кластер memcached/Redis для горизонтального масштабирования.
  • Правильно задайте лимиты размера объектов. Большие бинарники держите на диске, API-ответы — в памяти.
  • Следите за тем, что попадает в кэш: включите отчётность, раз в сутки анализируйте топ-ключи, TTL, соотношение HIT/MISS.
  • Используйте короткие TTL и stale-if-error/CacheStaleOnError вместо «вечного» кэша. Это повышает устойчивость при релизах и временных деградациях бэкенда.

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

  • Кэшируются персональные страницы. Симптом: пользователи видят чужие данные. Решение: исключить такие зоны из кэша, отключить QuickHandler, не игнорировать Set-Cookie, не снимать private/no-store.
  • Смешение gzip и не-gzip. Добавьте Vary: Accept-Encoding, проверьте, что сжатие включено последовательно.
  • Лавина запросов при истечении TTL. Включите CacheLock, используйте короткие TTL и «скользящее» обновление (revalidate), где возможно.
  • Медленный кэш на диске. Проверьте IO, размер каталога, параметры CacheDirLevels/CacheDirLength, вынесите кэш на отдельный SSD.

Итоги

mod_cache в Apache — хороший встроенный инструмент без внешних зависимостей. Для публичной статики и крупных файлов выбирайте cache_disk, для микрокэша динамики — cache_socache. CacheQuickHandler даёт ощутимый выигрыш, но его стоит отключать в чувствительных ветках с авторизацией и сложным переписыванием. Несколько точных директив (CacheLock, лимиты размера, корректные Vary и Cache-Control) — и вы получите предсказуемый рост производительности без риска кэшировать лишнее.

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

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

Docker BuildKit registry cache в CI: быстрые сборки на любом раннере OpenAI Статья написана AI (GPT 5)

Docker BuildKit registry cache в CI: быстрые сборки на любом раннере

Долгие Docker‑сборки в CI — классическая боль: свежие раннеры, мало диска и кэш каждый раз с нуля. Registry‑backed cache в BuildKi ...
MySQL 8: caching_sha2_password и TLS — безопасная аутентификация без сюрпризов OpenAI Статья написана AI (GPT 5)

MySQL 8: caching_sha2_password и TLS — безопасная аутентификация без сюрпризов

В MySQL 8 по умолчанию используется caching_sha2_password. Это повысило безопасность, но ломает старые клиенты без TLS. В статье — ...
CSP на практике: nonce и hash, безопасный старт с Report-Only OpenAI Статья написана AI (GPT 5)

CSP на практике: nonce и hash, безопасный старт с Report-Only

Пошаговое внедрение Content Security Policy для защиты от XSS: чем отличаются nonce и hash, как безопасно запустить режим Report-O ...