Files
XC_VM/docs/ru/development/caching-and-redis.md
T
Divarion-D 76844fef11 docs: restructure, fix PSR-4 drift, and unify en/ru
Overhaul the Docsify documentation (English + Russian) so it matches the current
codebase and follows one consistent pattern.

Content accuracy (post-migration):
- Rewrite development/autoloader.md to PSR-4 / Composer (the old XC_Autoloader
  scanner, igbinary tmp/cache/autoload_map and registerDirectories are gone).
- PascalCase every source path (src/core -> src/Core, domain/Stream, cli/Commands,
  public/Controllers, Infrastructure/Redis, ...) across all docs.
- Replace the removed autoload.php references with vendor/autoload.php
  (build_system, bootstrap-contexts, error-handling, modules).
- ssl-generation: note that the installer now auto-generates a unique self-signed
  certificate before Nginx starts.

Common pattern (Clean & uniform):
- Strip emoji from headings; remove the in-page Navigation blocks (the Docsify
  sidebar already provides navigation).
- One H1 + intro per doc; uniform "Related files" / "Связанные файлы" section,
  added to the code-centric docs that lacked it.

Structure:
- Remove the empty stray docs/api/; move updates_checklist.md into builds/;
  link the previously-orphaned ucs-integration.md.
- Regroup the sidebars (split the oversized guides group into Developer Guides /
  Security & Access / Integrations; fold builds into Build & Release).

Augment:
- dev-workflow: Local Setup (make dev-tools) + Quality Checks (phpstan, cs, gates).
- build_system: Composer Dependencies section (committed prod-only vendor,
  committed lock, dev tools via composer install, no build-time vendor step).

en/ru parity:
- Apply the same structure, fixes and pattern to docs/ru/ (translated), including
  a new Russian ucs-integration.md. The en and ru file sets are now identical.
2026-06-26 15:56:15 +03:00

11 KiB
Raw Blame History

Кэширование и стратегия Redis

XC_VM использует двухуровневую стратегию кэширования:

  • Файловый кэш (igbinary) — основной уровень, используемый как стриминговым, так и административным путём
  • Redis/KeyDB — опциональный высокопроизводительный уровень для состояния подключений и продвинутых операций

Стриминговый путь читает исключительно из файлового кэша (без запросов к базе данных). Административный путь читает напрямую из базы данных с опциональным короткоживущим кэшем.


Интерфейс кэша

Файл: src/Core/Cache/CacheInterface.php

get($key, $maxAge = null)
set($key, $data, $ttl = 0)
delete($key)
has($key, $maxAge = null)
flush()
  • $ttl = 0 означает кэш навсегда (до ручного удаления или сброса).
  • $maxAge проверяет время изменения файла для свежести (только FileCache).

FileCache

Файл: src/Core/Cache/FileCache.php

Реализация кэша по умолчанию. Хранит igbinary-сериализованные данные в виде плоских файлов.

$cache = new FileCache(CACHE_TMP_PATH);
$cache->set('my_key', $data, 3600);
$data = $cache->get('my_key', 120);     // только если меньше 2 минут

Статический упрощённый API (обратная совместимость):

FileCache::setCache($key, $data)
FileCache::getCache($key, $maxAge = null)

Характеристики:

  • Сериализация: igbinary (если доступна) или резервный PHP serialize.
  • Блокировка: LOCK_EX при записи во избежание повреждения.
  • Расположение файла: {basePath}/{key} (без подкаталогов для основных ключей).
  • Восстановление при повреждении: определяет битые данные, автоматически удаляет повреждённые файлы.

RedisCache

Файл: src/Core/Cache/RedisCache.php

Опциональная высокопроизводительная реализация.

$redis = new RedisCache('127.0.0.1', 6379, $password, 'prefix:');
$redis->set($key, $data, 600);          // TTL 10 минут через SETEX
$redis->getConnection();                 // сырой phpredis для sorted sets, pipelines
  • Ленивое подключение: подключается при первой операции.
  • Нативная поддержка TTL через SETEX в Redis.
  • Используется в первую очередь для ConnectionTracker (sorted sets для состояния активных подключений).

Управление подключением к Redis

Файл: src/Infrastructure/Redis/RedisManager.php

Жизненный цикл singleton:

RedisManager::instance()                 // получить активный Redis или null
RedisManager::ensureConnected()          // подключиться, если ещё не подключено
RedisManager::isConnected()              // проверка состояния
RedisManager::closeInstance()            // отключение

Проверка состояния пингует Redis каждые 30 секунд (с дебаунсом). Автоматически переподключается при сбое. Возвращает null при сбое подключения (плавная деградация).

Конфигурация:

Настройка Источник По умолчанию
hostname config.ini —
port hardcoded 6379
password settings.redis_password —
read_timeout hardcoded 2.0 с
tcp_keepalive hardcoded 60 с

Наполнение кэша

Файлы кэша генерируются двумя cron-задачами:

Лёгкий кэш (CacheCronJob)

Запускается каждый cron-цикл. Перестраивает быстро меняющиеся данные (~1 секунда):

  • settings — настройки панели
  • servers — список серверов
  • bouquets — пакеты каналов
  • categories — категории потоков
  • Блок-листы: blocked_isp, blocked_ua, blocked_ips, blocked_servers
  • allowed_ips, output_formats, hmac_keys, rtmp_ips

Тяжёлый кэш (CacheEngineCronJob)

Перестраивает данные о потоках, линиях и сериях. Ограничен запуском раз в 5 минут через маркер heavy_cache_built:

  • STREAMS_TMP_PATH/stream_{id} — метаданные отдельного потока
  • LINES_TMP_PATH/line_i_{user_id} — данные аккаунта пользователя
  • LINES_TMP_PATH/line_c_{username_password} — username → user_id lookup
  • LINES_TMP_PATH/line_t_{access_token} — token → user_id lookup
  • SERIES_TMP_PATH/series_{id} — метаданные сериала

Режим детекции изменений (если включено cache_changes): сравнивает временную метку updated в БД с mtime файла, перестраивает только изменённые элементы.

Режим полной перестройки: пересоздаёт все записи. Управляется настройкой cache_thread_count.

Готовность кэша

Файл cache_complete записывается после каждой полной перестройки кэша. Стриминговый путь проверяет этот файл и завершается с ошибкой, если он отсутствует.


Соглашения о ключах кэша

Системные ключи (CACHE_TMP_PATH)

Ключ Содержимое
settings массив настроек панели
servers array[server_id] → конфигурация сервера
bouquets array[bouquet_id] → определение букета
categories array[category_id] → данные категории
bouquet_map array[stream_id] → array[bouquet_id]
category_map array[bouquet_id] → array[category_id]
permissions_{group_id} набор прав группы
cache_complete временная метка time() последней полной перестройки

Ключи потоков (STREAMS_TMP_PATH)

Ключ Содержимое
stream_{id} информация о потоке + букеты + состояние по серверам
channels_categories array[stream_id] → array[category_id]

Ключи линий (LINES_TMP_PATH)

Ключ Содержимое
line_i_{user_id} полная запись пользователя
line_c_{username_password} user_id (lookup по учётным данным)
line_t_{access_token} user_id (lookup по токену)

Ключи сериалов (SERIES_TMP_PATH)

Ключ Содержимое
series_{id} метаданные сериала
series_map array[stream_id] → series_id
episodes_{series_id} array[season_num] → список эпизодов

Паттерны инвалидации

Триггер Затронутые ключи Механизм
Админ редактирует поток stream_{id}, bouquet_map сигнал → следующий cron:cache_engine
Админ редактирует линию line_i_*, line_c_*, line_t_* следующий cron:cache_engine
Изменены настройки settings, categories, blocklists SettingsManager::clearCache() + cron
Обновлён список серверов servers, bouquet_map cron
Старт потока (FFprobe) {md5(source)} TTL 5 минут через проверку mtime файла
Кнопка flush в админке все файлы в CACHE_TMP_PATH rm -rf

Стриминговый путь vs административный

Стриминговый путь (www/stream/*)

  • cached: true по умолчанию.
  • Читает только из файлового кэша (без запросов к БД).
  • Сырая igbinary-десериализация: igbinary_unserialize(file_get_contents(...)).
  • Если cache_complete отсутствует — выход с ошибкой.

Административный путь (Public/Controllers/Admin/*)

  • cached: false по умолчанию.
  • Читает напрямую из базы данных через доменные сервисы.
  • Опциональный короткоживущий кэш (пример из BouquetService::getAll()):
$rCache = FileCache::getCache('bouquets', 60);  // только если меньше 60 с
if (!empty($rCache)) {
    return $rCache;
}
// промах: запрос к базе и запись кэша
FileCache::setCache('bouquets', $rOutput);

Структура файлов кэша

/home/xc_vm/tmp/cache/
├── settings
├── servers
├── bouquets
├── categories
├── bouquet_map
├── category_map
├── cache_complete
├── heavy_cache_built
├── streams/
│   ├── stream_{id}
│   └── channels_categories
├── lines/
│   ├── line_i_{user_id}
│   ├── line_c_{username_password}
│   └── line_t_{access_token}
└── series/
    ├── series_{id}
    ├── series_map
    └── episodes_{series_id}

Связанные файлы

Файл Назначение
src/Core/Cache/CacheInterface.php контракт кэша
src/Core/Cache/FileCache.php реализация файлового кэша
src/Core/Cache/RedisCache.php реализация Redis-кэша
src/Infrastructure/Redis/RedisManager.php singleton подключения к Redis
src/Infrastructure/Cache/CacheReader.php мост для legacy-чтения кэша
src/Cli/CronJobs/CacheCronJob.php генерация лёгкого кэша
src/Cli/CronJobs/CacheEngineCronJob.php генерация тяжёлого кэша (потоки, линии, сериалы)
src/Domain/Bouquet/BouquetService.php пример кэширования на админ-пути
src/Domain/Stream/ConnectionTracker.php Redis sorted sets для состояния подключений