Перейти к содержанию

Стратегия кэширования и 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 проверяет время изменения файла на свежесть (только для файлового кэша).

Файловый кэш

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

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

$cache = new FileCache(CACHE_TMP_PATH);
$cache->set('my_key', $data, 3600);
$data = $cache->get('my_key', 120);     // only if < 2 min old

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

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

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

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

Заново спрятать

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

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

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

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

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

Жизненный цикл синглтона:

RedisManager::instance()                 // get active Redis or null
RedisManager::ensureConnected()          // connect if not already
RedisManager::isConnected()              // health check
RedisManager::closeInstance()            // disconnect

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

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

Установка Источник По умолчанию
hostname config.ini
port жестко запрограммированный 6379
password settings.redis_password
read_timeout жестко запрограммированный 2.0s
tcp_keepalive жестко запрограммированный 60s

Сохраняющиеся при отключении в режиме ожидания (долгоживущие демоны)

Кратковременные запросы (PHP-FPM stream/admin) открывают новое соединение для каждого процесса и на них не влияют тайм-ауты простоя. Демоны-долгожители — цикл watchdog, fanout_sync — вместо этого удерживайте соединение один через синглтон для их весь срок службы, при котором возможны два режима сбоя на загруженном сервере или на межсерверном сервере (LB → ГЛАВНАЯ) ссылка:

  • Сервер простаивает - закрывается. Redis закрывает любой клиент, который простаивает дольше своего timeout (300s в комплекте bin/redis/redis.conf). затем phpredis прозрачно откроется снова. сокет в следующей команде без повторного воспроизведения аутентификации, поэтому более поздняя команда отвечает NOAUTH — или просто возвращает false.
  • Устранен пробел в проверке работоспособности. instance() пингуется только каждые 30 секунд, так что между пингует, что сброшенное соединение еще не замечено.

Охранники на месте:

  • instance() обрабатывает любой ответ, не связанный сPONG пингом (беззвучное повторное подключение / NOAUTH состояние) как отключенное соединение и принудительно выполняет полное, повторная аутентификация повторное подключение через \XC_VM::redis_connect() — это не просто повторная попытка на уровне сокета.
  • Вызывайте сайты, которые командами конвейера проверяют объект конвейера. Например ConnectionTracker::getCapacity() проверяет, что $redis->multi() вернул \Redis (сломанный сокет возвращает false и вызывает zCard() для этого bool был бы фатальным вне пути повторного подключения) и выдает, чтобы его цикл повторных попыток снова подключился.

The server-side alternative (timeout 0) is deliberately not used — the вместо этого клиент становится устойчивым, и tcp-keepalive по-прежнему получает доступ к мертвым одноранговым узлам.


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

Файлы кэша генерируются двумя заданиями 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} — имя пользователя → поиск идентификатора пользователя
  • LINES_TMP_PATH/line_t_{access_token} — токен → поиск идентификатора пользователя
  • SERIES_TMP_PATH/series_{id} — метаданные серии

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

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

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

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

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

Потоковый загрузчик (LegacyInitializer::initStreaming()) считывает servers, блок-листы и proxy_servers из файлового кэша. Перед первой сборкой (fresh boot, cleared tmp) those files do not exist and CacheReader::get() возвращает null, поэтому для каждого такого глобального массива по умолчанию используется пустой массив. Холодный кэш следовательно, не удается закрыть — запрос не находит серверов и показывает "нет в эфире". — вместо предупреждения foreach(null) или in_array($x, null) со смертельным исходом (PHP 8) вниз по течению. Действительно поврежденный кэш сборка все еще отображается отдельно с помощью FileCache предупреждение о сбое записи, поэтому это значение по умолчанию маскирует только временный окно холодного пуска, а не настоящий сбой.


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

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

Ключ Содержание
settings массив настроек панели
servers array[server_id] → конфигурация сервера
bouquets array[bouquet_id] → bouquet определение
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 (поиск учетных данных)
line_t_{access_token} user_id (поиск токена)

Ключи серии (SERIES_TMP_PATH)

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

Шаблоны аннулирования

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

Потоковая передача против пути администратора

Путь потоковой передачи (www/stream/*)

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

Путь администратора (Public/Controllers/Admin/*)

  • cached: false по умолчанию.
  • Считывает данные из базы данных непосредственно через доменные службы.
  • Необязательный кратковременный кэш (пример из BouquetService::getAll()):
$rCache = FileCache::getCache('bouquets', 60);  // only if < 60s old
if (!empty($rCache)) {
    return $rCache;
}
// miss: query database and write cache
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 Redis одноэлементное соединение
src/Infrastructure/Cache/CacheReader.php устаревший мост для чтения кэша
src/Cli/CronJobs/CacheCronJob.php облегченная генерация кэша
src/Cli/CronJobs/CacheEngineCronJob.php генерация большого объема кэша (потоки, строки, серии)
src/Domain/Bouquet/BouquetService.php пример кэширования пути администратора
src/Domain/Stream/ConnectionTracker.php Redis отсортированные наборы для определения состояния соединения