BMC IO DocsBMC IO Docs
IO v6
IO v7
Notes
Docs
IO v6
IO v7
Notes
Docs
  • IO Framework v7

    • О фреймворке
    • Что изменилось в 7 версии
    • IO7 Framework vs Laravel 13 — Сравнение
    • Структура
    • Варианты проектов
    • Доступ к участкам проекта
    • Разворачивание нового проекта
    • Установка проекта
    • Запуск локальной разработки
  • API

    • Обзор API
    • IOCore::call() и IOCore::callAction()
    • Создание API
  • CLI

    • Обзор CLI
    • iocli
    • Кастомные CLI команды
  • Работа с базами данных

    • Обзор работы с базами данных
    • Cron / Планировщик задач (Schedule)
    • Фабрики
    • Миграции
    • Сидеры
    • Query Builder
    • Подключение MinIO
    • Подключение MongoDB
    • Подключение MySQL
    • Подключение PostgreSQL
    • Подключение ProxySQL
    • Подключение RabbitMQ
    • Подключение Redis
  • Логирование

    • Обзор логирования
    • IOEvent - Логирование событий
    • Pinba (PinbaManager) - Профилировщик
  • Модели

    • Обзор моделей
    • CRUD операции
    • Связи моделей
  • Очереди

    • Обзор очередей
    • RabbitMQ
  • Маршруты

    • Обзор маршрутов
    • Определение маршрутов
    • Middleware
  • Сессии

    • Обзор сессий
    • Кроссдоменная SSO
    • JWT авторизация
    • Социальная авторизация
    • OAuth2
    • Keycloak
  • Twig

    • Обзор Twig
    • Формы (FormBuilder)
    • Twig функции
  • Тестирование

    • Обзор тестирования
    • Unit тесты
  • Backend

    • Настройки проекта Conf.php
    • Настройки модуля Module.php
    • Настройки composer
    • Функции фреймворка
    • Вспомогательные функции (Helpers)
    • Глобальные переменные
    • Константы фреймворка
    • Event класс
    • Core класс
    • Route и работа с ними
    • Request и работа с ними
    • Middleware и работа с ними
    • Class и работа с ними
    • Api model и работа с ними
    • Template и работа с ними
    • Мультиязычность и словарь фраз
    • Bin скрипты и работа с ними
    • Cron скрипты и работа с ними
    • $ioSession и работа с сессией
    • $ioHash и работа с кешем
    • $ioXCache и работа с кешем
    • $iodb и работа с базой данных
    • Миграции
  • Frontend

    • Twig шаблонизатор и работа с ним
    • Twig функции
    • Twig фильтры
    • Twig контекст
    • Настройка NPM
    • Сборка Frontend составляющей
    • Обращение к Api через JS
    • Хранилище (store)
    • Навигация в хосте
    • Навигация в микрофронтенде
    • Параметры микрофронтенда
    • Проверка полномочий
  • Tailux UI Компоненты

    • Базовый UI

      • AvatarDot
      • Avatar
      • Badge
      • Button
      • Card
      • ConfirmModal
      • Divider
      • Highlight
      • Tag
    • Загрузка

      • Circlebar
      • Progress
      • Skeleton
      • Spinner
    • Навигация

      • Accordion
      • AccordionButton
      • AccordionHeader
      • AccordionItem
      • AccordionPanel
      • AccordionProvider
      • Pagination
      • PaginationControl
      • PaginationItems
      • PaginationDots
      • PaginationFirst
      • PaginationLast
      • PaginationNext
      • PaginationPrevious
    • Отображение данных

      • Box
      • Collapse
      • ContextualHelp
      • ScrollShadow
      • Timeline
      • TimelineItem
    • Элементы таблиц

      • Table
      • CollapsibleSearch
      • ColumnFilter
      • CopyableCell
      • DateFilter
      • FacetedFilter
      • FilterSelector
      • PaginationSection
      • RadioFilter
      • RangeFilter
      • ResponsiveFilter
      • RoleFilter
      • SelectedRowsActions
      • TableColumnVisibility
      • TableSettings
      • TableSortIcon
    • Элементы форм

      • Checkbox
      • Combobox
      • DatePicker
      • Filepond
      • Input
      • Listbox
      • Radio
      • Range
      • Select
      • StyledSwitch
      • Swap
      • SwapOn
      • SwapOff
      • Switch
      • Textarea
      • TextEditor
      • Upload

Подключение Redis

Внимание

Данная статья документации написана нейросетью. Возможны некоторые расхождения и неточность информации!

  • Содержание
  • Требования
  • RedisManager
    • Инициализация
  • Типы данных
    • Строки
    • Хеши
    • Списки (очереди)
    • Множества
    • Сортированные множества
    • Pub/Sub
    • Транзакции
    • Lua скрипты
  • Примеры
    • Кэширование
    • Сессии
    • Очередь задач
    • Rate Limiting
    • Pub/Sub для уведомлений
    • Leaderboard
  • Рекомендации
  • FAQ
    • Как проверить подключение?
    • Как работать с несколькими Redis серверами?
    • Что хранится в кэше?
    • Как очистить кэш?
    • Как узнать размер кэша?

Руководство по подключению к Redis в IO7 фреймворке.

Содержание

  • Требования
  • RedisManager
  • Типы данных
  • Примеры
  • Рекомендации
  • FAQ

Требования

Для работы с Redis необходимо PHP расширение redis:

pecl install redis

Или через apt:

apt-get install php-redis

RedisManager

Пространство имён: IO

Менеджер Redis с поддержкой строк, хешей, списков, множеств, сортированных множеств, Pub/Sub и Lua скриптов. Реализован как синглтон.

Инициализация

init()

public static function init(array $config): self

Инициализировать или получить существующий экземпляр.

ПараметрТипЗначение по умолчаниюОбязателенОписание
$configarray<string, mixed>—ДаКонфигурация подключения

Параметры конфигурации:

КлючТипПо умолчаниюОбязателенОписание
hoststring—ДаАдрес сервера
portint6379НетПорт сервера
timeoutint0НетТаймаут подключения (сек)
passwordstring—ДаПароль
databaseint0НетНомер базы данных
persistentboolfalseНетPersistent-подключение
use IO\RedisManager;

RedisManager::init([
    'host'       => '127.0.0.1',
    'port'       => 6379,
    'timeout'    => 0,
    'password'   => 'secret',
    'database'   => 0,
    'persistent' => false,
]);

getInstance()

public static function getInstance(): self

Получить синглтон-экземпляр. Выбрасывает \Exception если не инициализирован.

$redis = RedisManager::getInstance();

getClient()

public function getClient(): \Redis

Получить объект \Redis для прямого доступа.

$redis = RedisManager::getInstance()->getClient();
$redis->ping();

Типы данных

Строки

get()

public function get(string $key): mixed

Получить значение по ключу. Возвращает null если ключ не найден.

$value = RedisManager::getInstance()->get('user:123');

set()

public function set(string $key, mixed $value, ?int $ttl = null): bool

Установить значение с опциональным TTL.

ПараметрТипЗначение по умолчаниюОбязателенОписание
$keystring—ДаКлюч
$valuemixed—ДаЗначение (сериализуется)
$ttl?\intnullНетВремя жизни в секундах (null — без ограничений)
RedisManager::getInstance()->set('user:123', ['name' => 'Иван'], 3600);

exists()

public function exists(string $key): int

Проверить существование ключа.

if (RedisManager::getInstance()->exists('cache:users')) {
    // Ключ существует
}

expire()

public function expire(string $key, int $seconds): bool

Установить время жизни ключа.

ttl()

public function ttl(string $key): int

Получить оставшееся время жизни ключа. -1 — без срока, -2 — ключ не найден.


Хеши

hSet()

public function hSet(string $key, string $field, mixed $value): bool

Установить поле хеша.

RedisManager::getInstance()->hSet('user:123', 'email', 'ivan@example.com');

hGet()

public function hGet(string $key, string $field): mixed

Получить значение поля хеша.

$email = RedisManager::getInstance()->hGet('user:123', 'email');

hGetAll()

public function hGetAll(string $key): array

Получить все поля и значения хеша.

$user = RedisManager::getInstance()->hGetAll('user:123');
// ['name' => 'Иван', 'email' => 'ivan@example.com']

Списки (очереди)

lPush()

public function lPush(string $key, mixed $value): int

Добавить элемент в начало списка.

RedisManager::getInstance()->lPush('queue:tasks', ['task' => 'process']);

rPop()

public function rPop(string $key): mixed

Извлечь элемент из конца списка.

$task = RedisManager::getInstance()->rPop('queue:tasks');

lRange()

public function lRange(string $key, int $start, int $stop): array

Получить диапазон элементов списка.

$items = RedisManager::getInstance()->lRange('list:abc', 0, -1);

Множества

sAdd()

public function sAdd(string $key, mixed $value): bool

Добавить значение в множество.

RedisManager::getInstance()->sAdd('tags:post:1', 'php');
RedisManager::getInstance()->sAdd('tags:post:1', 'redis');

sMembers()

public function sMembers(string $key): array

Получить все элементы множества.

$tags = RedisManager::getInstance()->sMembers('tags:post:1');
// ['php', 'redis']

Сортированные множества

zAdd()

public function zAdd(string $key, float $score, mixed $value): bool

Добавить значение с весом.

RedisManager::getInstance()->zAdd('leaderboard', 100.5, ['player' => 'Alice']);
RedisManager::getInstance()->zAdd('leaderboard', 200.0, ['player' => 'Bob']);

zRange()

public function zRange(
    string $key,
    int $start,
    int $stop,
    bool $withScores = false
): array

Получить диапазон элементов.

$top = RedisManager::getInstance()->zRange('leaderboard', 0, 9, true);
// [['player' => 'Bob', score], ['player' => 'Alice', score]]

Pub/Sub

publish()

public function publish(string $channel, mixed $message): int

Опубликовать сообщение в канал.

RedisManager::getInstance()->publish('notifications', [
    'type' => 'alert',
    'msg'  => 'Новое уведомление',
]);

subscribe()

public function subscribe(array $channels, callable $callback): void

Подписаться на каналы (блокирующий вызов).

RedisManager::getInstance()->subscribe(
    ['notifications', 'alerts'],
    function (string $channel, mixed $message): void {
        echo "Получено в {$channel}: " . json_encode($message) . "\n";
    }
);

Транзакции

multi()

public function multi(): \Redis

Начать транзакцию.

exec()

public function exec(): array

Выполнить транзакцию.

discard()

public function discard(): bool

Отменить транзакцию.

$redis = RedisManager::getInstance();
$redis->multi();
$redis->set('key1', 'value1');
$redis->set('key2', 'value2');
$results = $redis->exec();

Lua скрипты

eval()

public function eval(string $script, array $args = [], int $numKeys = 0): mixed

Выполнить Lua скрипт.

ПараметрТипЗначение по умолчаниюОбязателенОписание
$scriptstring—ДаLua скрипт
$argsarray[]НетАргументы (ключи и значения)
$numKeysint0НетКоличество ключей (начальная позиция в $args)
// Атомарное увеличение с лимитом
$result = RedisManager::getInstance()->eval('
    local current = tonumber(redis.call("GET", KEYS[1]) or "0")
    local max = tonumber(ARGV[1])
    if current < max then
        redis.call("INCR", KEYS[1])
        return current + 1
    end
    return -1
', ['counter:limited'], 1);

Примеры

Кэширование

use IO\RedisManager;

$redis = RedisManager::getInstance();
$cacheKey = 'user:' . $userId;

// Попытка получить из кэша
$user = $redis->get($cacheKey);

if ($user === null) {
    // Кэш промах — загружаем из БД
    $user = DB::table('users')->find($userId);
    $redis->set($cacheKey, $user, 3600);  // кэш на 1 час
}

echo $user['name'];

Сессии

$redis = RedisManager::getInstance();
$sessionId = session_id();

// Сохранить данные сессии
$redis->set("session:{$sessionId}", $data, 1800);  // 30 минут

// Получить данные сессии
$data = $redis->get("session:{$sessionId}");

// Продлить сессию
$redis->expire("session:{$sessionId}", 1800);

Очередь задач

$redis = RedisManager::getInstance();

// Добавить задачу
$redis->lPush('queue:email', [
    'to'      => 'user@example.com',
    'subject' => 'Привет!',
    'body'    => 'Текст письма',
]);

// Обработать задачи
while (true) {
    $task = $redis->rPop('queue:email');
    if ($task === null) {
        sleep(1);
        continue;
    }

    // Отправка email
    sendEmail($task['to'], $task['subject'], $task['body']);
}

Rate Limiting

$redis = RedisManager::getInstance();
$ip = $_SERVER['REMOTE_ADDR'];
$key = "ratelimit:{$ip}";

$count = $redis->get($key);
if ($count !== null && $count >= 100) {
    http_response_code(429);
    echo "Too many requests";
    exit;
}

$redis->set($key, ($count ?? 0) + 1, 60);  // окно 1 минута

Pub/Sub для уведомлений

// Publisher (в API-эндпоинте)
$redis = RedisManager::getInstance();
$redis->publish('user:' . $userId, [
    'type' => 'order_status',
    'data' => ['order_id' => 123, 'status' => 'shipped'],
]);

// Subscriber (в WebSocket-сервере)
$redis->subscribe(['user:' . $userId], function (string $channel, mixed $message): void {
    // Отправить клиенту через WebSocket
    sendToWebSocket($message);
});

Leaderboard

$redis = RedisManager::getInstance();

// Обновить результат
$redis->zAdd('game:leaderboard', $score, ['user' => $userId]);

// Топ-10
$top = $redis->zRange('game:leaderboard', 0, 9, true);

// Рейтинг пользователя
$rank = $redis->getClient()->zRevRank('game:leaderboard', ['user' => $userId]);

Рекомендации

  1. Используйте persistent => true для высоконагруженных приложений
  2. Разделяйте базы данных (database => N) для разных целей
  3. Устанавливайте TTL для временных данных
  4. Избегайте KEYS * в продакшене — используйте SCAN
  5. Используйте Lua скрипты для атомарных операций
  6. Мониторьте память через INFO memory

FAQ

Как проверить подключение?

$redis = RedisManager::getInstance();
if ($redis->getClient()->ping() === '+PONG') {
    echo "Redis подключён\n";
}

Как работать с несколькими Redis серверами?

RedisManager::init(['host' => 'cache1.local', 'database' => 0]);
// Или используйте不同的 database numbers

Что хранится в кэше?

Все значения сериализуются через serialize(). При чтении автоматически десериализуются.

Как очистить кэш?

$redis->getClient()->flushDB();  // Очистить текущую БД
$redis->getClient()->flushAll(); // Очистить все БД

Как узнать размер кэша?

$info = $redis->getClient()->info('memory');
echo "Использовано памяти: {$info['used_memory_human']}\n";
Prev
Подключение RabbitMQ