Стратегия кэширования и Redis¶
XC_VM использует двухуровневую стратегию кэширования:
- Файловый кэш (igbinary) — основной уровень, используемый как потоковыми, так и административными путями
- Redis/KeyDB — дополнительный высокопроизводительный уровень для определения состояния соединения и расширенных операций
Путь потоковой передачи считывается исключительно из файлового кэша (никаких запросов к базе данных). Путь администратора считывается из базы данных с дополнительным кратковременным кэшем.
Интерфейс кэширования¶
Файл: src/Core/Cache/CacheInterface.php
$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 (обратная совместимость):
Характеристики:
- Сериализация: 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 отсортированные наборы для определения состояния соединения |