Кэширование в Webim Server (hosted-режим)
В статье описывается система кэширования Webim Server при работе в hosted-режиме. Понимание механизмов кэширования помогает быстрее находить причины задержки применения настроек, появления устаревших данных в виджете и других подобных проблем.
Уровни кэширования
Webim Server использует многоуровневую архитектуру кэширования. Каждый уровень отвечает за свою область данных и имеет собственное время жизни записей.
| Уровень | Хранение | Что кэшируется | TTL / inactive по умолчанию |
|---|---|---|---|
| Nginx proxy cache | /var/cache/webim/nginx |
visitor-configs, HTTP-ответы | задаётся в конфиге развёртывания (proxy_cache_valid, fastcgi_cache_valid, inactive; примеры см. ниже) |
| Admin Backend (Python) | RAM процесса | операторы, отделы, настройки аккаунта, кнопки, размещения, опросы, роли, токены авторизации, тарифы, категории, приглашения, правила маршрутизации, политики доступа, конфигурации метрик, отчётов и дашбордов (полный список типов см. в разделе «Сброс кэша Admin Backend») | 5 мин (300 сек; константа DEFAULT_CACHE_INVALIDATION_TIMEOUT в коде Admin Backend) |
| Chat Backend (PHP) | файловая система | настройки аккаунта и отделов, операторы, данные аккаунта, тариф | settings и settings_department_*: 6000 сек; tariff: 900 сек; operators и accounts: 3600 сек |
| button.js | файл на диске | скомпилированный JS-виджет посетителя | до явного сброса |
Nginx proxy cache
Кэш Nginx в hosted-режиме хранится в каталоге /var/cache/webim/nginx; при развёртывании без hosted-режима — в /var/cache/nginx. Используются зоны fastcgi_cache и proxy_cache с levels=1:2. Разбиение по подкаталогам задаётся путями proxy_cache_path и fastcgi_cache_path в конфиге Nginx.
Где что хранится: в этой директории лежат ответы, закэшированные разными location-блоками. Пути к каталогам задаются в директивах proxy_cache_path / fastcgi_cache_path: первый аргумент — путь на диске, по нему создаётся подкаталог верхнего уровня.
Среди каталогов кэша в конфигурации развёртывания есть visitor-configs (конфигурации виджета для посетителя): /var/cache/webim/nginx/visitor-configs в hosted-режиме и /var/cache/nginx/visitor-configs без него.
Внутри каждого такого каталога Nginx с levels=1:2 создаёт двухуровневую структуру подкаталогов (один символ + два символа от хэша ключа), затем имя файла — MD5 от ключа кэша. Для visitor-configs в webim-dockchain ключ кэша в конфиге задаётся как $account_name:$1:$query_string (имя аккаунта, ключ размещения из URL, строка запроса, например jsonp=true для JSONP). Путь к файлу: visitor-configs/{последний_символ_MD5}/{два_символа_MD5}/{полный_MD5}.
При точечной инвалидации visitor-configs код Admin Backend формирует ключ как account_name:location_key. Поскольку точечная инвалидация не учитывает $query_string, она не затрагивает записи с непустой строкой запроса (например, JSONP-запросы). Для гарантированного сброса используйте полный сброс кэша Nginx по аккаунту (например, при изменении размещения) — он выполняется по содержимому файлов и затрагивает все записи аккаунта. Конкретный набор зон и имён подкаталогов зависит от конфигурации развёртывания.
Нагрузка при полном сбросе Nginx по аккаунту
Полный сброс кэша Nginx по аккаунту читает содержимое файлов кэша в поисках имени аккаунта. На большом кэше это нагружает диск и процесс Admin Backend.
Служебные каталоги Nginx (proxy_temp, client_temp, fastcgi_temp, scgi_temp, uwsgi_temp) находятся в том же корне кэша и используются для временных данных. При ручной очистке их содержимое удалять нельзя.
Почему в разных location разные параметры кэша: каждому location (например, отдача visitor-configs, статика виджета, API) задаётся свой ключ кэша и свои директивы proxy_cache_valid / fastcgi_cache_valid. Так можно выставлять разный TTL и точечно инвалидировать только нужные данные при изменении настроек (например, сброс только visitor-configs без затрагивания статики).
Примеры TTL и рекомендации по окружениям:
| Окружение | Рекомендация | Пример для visitor-configs |
|---|---|---|
| Тест | Уменьшенный TTL или отключение кэша для части location, чтобы быстрее видеть изменения при отладке. | 1–5 мин или proxy_cache off для соответствующего location. |
| Прод | Увеличенный TTL для снижения нагрузки на бэкенды; кэш включать везде, где допустима задержка применения настроек. | 10–60 мин в зависимости от частоты изменений конфигурации. |
Значения в таблице — ориентир; итоговые настройки задаются в nginx-конфиге развёртывания (директивы proxy_cache_valid, fastcgi_cache_valid и при необходимости proxy_cache_key). Для зоны visitor-configs в продакшн-конфигах задано inactive=5m.
Для диагностики при наличии в конфиге Nginx директивы add_header X-Cache-Status $upstream_cache_status; в ответах доступен заголовок X-Cache-Status со значениями HIT, MISS, EXPIRED, STALE, BYPASS, REVALIDATED или UPDATING, позволяющий определить, был ли ответ отдан из кэша и в каком состоянии. Без этой директивы заголовок не добавляется.
Кэш Admin Backend (Python)
Хранится в оперативной памяти процесса Admin Backend. Кэшируются данные операторов, отделов, настроек аккаунта, кнопок, размещений, опросов, ролей, токенов авторизации, тарифов, категорий, приглашений, правил маршрутизации, политик доступа, конфигураций метрик, отчётов и дашбордов. Полный список типов см. в разделе Сброс кэша Admin Backend. При перезапуске процесса кэш создаётся заново.
При работе нескольких узлов Admin Backend инвалидация кэша между ними выполняется через Redis Streams (см. раздел Многоузловая инвалидация).
Файловый кэш Chat Backend (PHP)
Файловый кэш Chat Backend хранится на диске по пути:
{online_dir}/{первый_символ_md5(accountName)}/{accountName}/key-value-{kind}/
Где {первый_символ_md5(accountName)} — один символ (первый символ MD5-хэша от имени аккаунта), а не полный хэш. Переменная {online_dir} и допустимые значения {kind} задаются в конфигурации Chat Backend (PHP).
Каждая запись — файл с сериализованным массивом: ключ, TTL, данные и версия Webim. Кэшируются настройки аккаунта (settings), настройки отделов (settings_department_{id}, где {id} — идентификатор отдела), данные операторов (operators), данные текущего аккаунта (accounts) и тариф (tariff).
Вид (kind) |
TTL |
|---|---|
settings, settings_department_* |
6000 сек (~1.67 ч) |
tariff |
900 сек (15 мин) |
operators, accounts |
3600 сек (1 ч) |
Срок 30 000 сек — запасное значение KeyValueCache::put(), если при записи TTL не передан. Для видов из таблицы используются сроки выше.
Просроченные записи автоматически удаляются при чтении. При обновлении версии Webim кэш инвалидируется автоматически.
Chat Backend (Python)
Chat Backend на Python имеет отдельный эндпоинт сброса кэша: GET или POST /l/i/reset-cache. Обработчик принимает оба метода: POST выполняет тот же сброс, что и GET. Admin Backend вызывает эндпоинт методом POST. При диагностике учитывайте оба компонента (PHP и Python).
Кэш button.js
Скомпилированный виджет посетителя хранится по пути:
{web_cache_dir}/{accountName}/js/button.js
Переменная {web_cache_dir} задаётся в конфигурации развёртывания (hosted-режим). Файл пересоздаётся при изменении конфигурации кнопки. Отдаётся клиенту с заголовком Last-Modified.
Автоматическая инвалидация
При изменении данных через административный интерфейс Webim автоматически сбрасывает соответствующие кэши. Например, при изменении оператора сбрасывается кэш операторов и токенов, при изменении кнопки — кэш кнопок и файл button.js, при изменении размещения — кэш размещений и Nginx (visitor-configs).
В большинстве случаев ручное вмешательство не требуется — изменения применяются автоматически в течение TTL соответствующего уровня кэширования.
Многоузловая инвалидация (Redis)
Admin Backend при нескольких узлах синхронизирует инвалидацию кэша через Redis Streams. Узел, на котором изменились данные, сбрасывает свой RAM-кэш напрямую. Для остальных узлов в поток отправляется событие invalidate_cache. Получатель пропускает сообщения со своим идентификатором узла. В конфигурации Admin Backend указываются параметры cluster_name и redis_connection. В потоке хранятся события за последние примерно 5 минут; при появлении новых событий старые удаляются по порогу времени (xtrim). При длительном отсутствии новых событий записи в потоке могут сохраняться дольше.
Chat Backend (PHP) при нескольких узлах рассылает сброс кэша через MQService, а не через Redis. При расхождении кэша на PHP-узлах проверяйте доступность и настройки этого сервиса очередей, а не только Redis.
Недоступность Redis
Если Redis недоступен (обрыв сети, перезапуск, ошибка конфигурации), события инвалидации не доходят до остальных узлов. Кэш на других узлах Admin Backend будет обновлён только по истечении TTL RAM-кэша (порядка 5 минут) или после перезапуска процесса. Рекомендуется мониторить доступность Redis и при длительной недоступности рассмотреть ручной сброс кэша на всех узлах или перезапуск Admin Backend.
Сброс кэшей
Доступность эндпоинтов
Описанные ниже эндпоинты сброса кэша (/service/flush, /internal/admin-backend/cache, /service/reset-cache.php) доступны только из внутренней сети. При стандартной конфигурации Nginx прямой доступ к ним извне закрыт.
Полный сброс всех уровней
GET /service/flush
Последовательно сбрасывает все уровни кэширования: button.js, файловый кэш Chat Backend (PHP), кэш Chat Backend (Python, эндпоинт /l/i/reset-cache), кэш Admin Backend и Nginx proxy cache.
Важно!
Полный сброс увеличивает нагрузку на сервер — все данные будут перечитаны из базы при следующем обращении. Используйте только при реальной необходимости.
Сброс кэша Admin Backend
DELETE /internal/admin-backend/cache
DELETE /internal/admin-backend/cache/{type}
DELETE /internal/admin-backend/cache/{type}/{id}
Позволяет сбросить все кэши Admin Backend, конкретный тип или отдельную сущность по идентификатору. В URL типа кэша указываются через дефис (например, account-config); подчёркивание в пути не допускается.
Типы кэша (в URL — через дефис):
| Тип в URL | Описание |
|---|---|
account |
Объект аккаунта (данные аккаунта как сущности). Не путать с account-config. |
account-config |
Настройки аккаунта (конфигурация). |
account-key-value |
Сбрасывает кэш только на уровне мультиаккаунта; кэш отдельного аккаунта не затрагивается. |
account-policy-tree |
Дерево политик доступа. |
auth-token |
Сессии авторизации операторов. |
button |
Кнопки размещения, скомпилированный button.js. |
category |
Категории. |
dashboard-report-config |
Конфигурации отчётов дашборда. |
departments |
Отделы. |
invitation |
Приглашения. |
location |
Размещения. |
metric-config |
Конфигурации метрик. |
nginx |
Кэш Nginx (visitor-configs по аккаунту). |
operators |
Операторы. |
private-keys |
Приватные ключи. |
prompter |
Суфлёры. |
report-config |
Конфигурации отчётов. |
report-group |
Группы отчётов. |
role |
Роли. |
security-group |
Группы безопасности. |
survey-configs |
Конфигурации опросов. |
tariff |
Тарифные опции. |
visitor-routing-rule |
Правила маршрутизации посетителей. |
Сброс файлового кэша Chat Backend (PHP)
GET /service/reset-cache.php?type={type}
Допустимые значения type: all, accounts, operators, departments, auth-token, settings, tariff. При указании departments очищается кэш настроек каждого отдела (settings_department_*).
Значение auth-token без параметров auth_token или operator_id обрабатывается как ошибка: ответ 400 Bad Request. Скрипт reset-cache.php передаёт в обработчик только type и не подставляет эти параметры из запроса, поэтому отдельно сбросить кэш токенов этим эндпоинтом нельзя. Токены очищаются при type=all.
Очистка nginx-кэша вручную
Команда с явным исключением содержимого служебных каталогов (флаг -prune исключает только сами каталоги глубины 1, но не их содержимое на глубине 2; для корректного исключения используйте -not -path '…/DIR/*'):
sudo find /var/cache/webim/nginx -mindepth 2 -maxdepth 2 \
-not -path '/var/cache/webim/nginx/proxy_temp/*' \
-not -path '/var/cache/webim/nginx/client_temp/*' \
-not -path '/var/cache/webim/nginx/fastcgi_temp/*' \
-not -path '/var/cache/webim/nginx/scgi_temp/*' \
-not -path '/var/cache/webim/nginx/uwsgi_temp/*' \
-exec rm -rf {} +
sudo nginx -s reload
Удаляются только объекты кэша на глубине 2; содержимое каталогов *_temp не затрагивается.
Автоматическая очистка при деплое
При обновлении Webim deploy-скрипт автоматически очищает:
-
/var/cache/nginx— объекты на глубине 2. Условие-pruneиз‑за-mindepth 2не исключает содержимое каталогов*_tempна этой глубине, поэтому оно тоже удаляется. Сами каталоги*_temp(глубина 1) остаются. Это отличается от ручной очистки выше: там-not -pathоставляет содержимое*_tempнетронутым; -
/var/cache/webim/*— всё содержимое рекурсивно (кроме подкаталоговcompilesиnginx); -
/var/cache/webim/compiles/*— всё содержимое рекурсивно.
Сами родительские каталоги не удаляются.
Кэш Nginx в hosted-режиме
Каталог /var/cache/webim/nginx (кэш Nginx в hosted-режиме) не очищается при деплое — он исключён в скрипте. При необходимости сбросить его используйте ручную очистку (см. выше).
Типичные сценарии
Оператор изменил настройки, но они не применились
Сбросьте кэши account-config и settings:
DELETE /internal/admin-backend/cache/account-config
GET /service/reset-cache.php?type=settings
Виджет на сайте показывает старую конфигурацию
Сбросьте кэш кнопки и Nginx:
DELETE /internal/admin-backend/cache/button
DELETE /internal/admin-backend/cache/nginx
После обновления Webim видны старые данные
Выполните полный сброс:
GET /service/flush
Настройки размещения не обновляются
Сбросьте кэш размещений и Nginx (visitor-configs):
DELETE /internal/admin-backend/cache/location
DELETE /internal/admin-backend/cache/nginx