применение Redis - IlyaKovanov/lib GitHub Wiki

1. Установка и подключение

<?php
// Установка через композер: composer require predis/predis

require 'vendor/autoload.php';

$redis = new Predis\Client([
    'scheme' => 'tcp',
    'host'   => '127.0.0.1',
    'port'   => 6379,
]);

// Проверка подключения
try {
    $redis->ping();
    echo "Успешное подключение к Redis";
} catch (Exception $e) {
    echo "Ошибка подключения: " . $e->getMessage();
}
?>

2. Кеширование результатов запросов к БД

<?php
function getPopularProducts($redis, $db) {
    $cacheKey = 'popular_products';
    $cacheTime = 300; // 5 минут
    
    // Пытаемся получить данные из кеша
    $cachedData = $redis->get($cacheKey);
    
    if ($cachedData !== null) {
        echo "Данные из кеша\n";
        return json_decode($cachedData, true);
    }
    
    // Если в кеше нет, делаем запрос к БД
    echo "Запрос к базе данных\n";
    $products = $db->query("SELECT * FROM products WHERE views > 1000 LIMIT 10")->fetchAll();
    
    // Сохраняем в кеш
    $redis->setex($cacheKey, $cacheTime, json_encode($products));
    
    return $products;
}

// Использование
$products = getPopularProducts($redis, $pdo);
print_r($products);
?>

3. Управление сессиями пользователей

<?php
class RedisSessionHandler {
    private $redis;
    private $prefix = 'session:';
    
    public function __construct($redis) {
        $this->redis = $redis;
        session_set_save_handler(
            [$this, 'open'],
            [$this, 'close'],
            [$this, 'read'],
            [$this, 'write'],
            [$this, 'destroy'],
            [$this, 'gc']
        );
    }
    
    public function open($savePath, $sessionName) {
        return true;
    }
    
    public function close() {
        return true;
    }
    
    public function read($sessionId) {
        $key = $this->prefix . $sessionId;
        $data = $this->redis->get($key);
        return $data ?: '';
    }
    
    public function write($sessionId, $data) {
        $key = $this->prefix . $sessionId;
        $this->redis->setex($key, 3600, $data); // 1 час
        return true;
    }
    
    public function destroy($sessionId) {
        $key = $this->prefix . $sessionId;
        $this->redis->del($key);
        return true;
    }
    
    public function gc($maxlifetime) {
        return true;
    }
}

// Использование
$sessionHandler = new RedisSessionHandler($redis);
session_start();

// Теперь сессии хранятся в Redis
$_SESSION['user_id'] = 123;
$_SESSION['last_activity'] = time();
?>

4. Счетчики просмотров

<?php
function incrementViewCount($redis, $articleId) {
    $key = "article_views:{$articleId}";
    
    // Увеличиваем счетчик
    $views = $redis->incr($key);
    
    // Устанавливаем время жизни ключа (30 дней)
    if ($views == 1) {
        $redis->expire($key, 2592000);
    }
    
    return $views;
}

function getTopArticles($redis, $limit = 10) {
    $pattern = "article_views:*";
    $keys = $redis->keys($pattern);
    
    $articles = [];
    foreach ($keys as $key) {
        $articleId = str_replace('article_views:', '', $key);
        $views = $redis->get($key);
        $articles[$articleId] = $views;
    }
    
    arsort($articles);
    return array_slice($articles, 0, $limit, true);
}

// Использование
$articleId = 15;
$views = incrementViewCount($redis, $articleId);
echo "Статья {$articleId} просмотрена {$views} раз\n";

$topArticles = getTopArticles($redis);
print_r($topArticles);
?>

5. Простая очередь задач

<?php
class SimpleQueue {
    private $redis;
    private $queueName;
    
    public function __construct($redis, $queueName) {
        $this->redis = $redis;
        $this->queueName = $queueName;
    }
    
    // Добавление задачи в очередь
    public function push($task) {
        return $this->redis->lpush($this->queueName, json_encode($task));
    }
    
    // Получение задачи из очереди
    public function pop() {
        $task = $this->redis->rpop($this->queueName);
        return $task ? json_decode($task, true) : null;
    }
    
    // Получение длины очереди
    public function length() {
        return $this->redis->llen($this->queueName);
    }
}

// Использование
$emailQueue = new SimpleQueue($redis, 'email_queue');

// Добавляем задачи
$emailQueue->push([
    'to' => '[email protected]',
    'subject' => 'Добро пожаловать!',
    'body' => 'Приветствуем в нашем сервисе!'
]);

$emailQueue->push([
    'to' => '[email protected]',
    'subject' => 'Отчет',
    'body' => 'Ежедневный отчет'
]);

// Обработчик очереди (запускается в фоне)
while (true) {
    $task = $emailQueue->pop();
    
    if ($task) {
        echo "Отправляем email: " . $task['to'] . "\n";
        // Здесь код отправки email
        // sendEmail($task['to'], $task['subject'], $task['body']);
    } else {
        echo "Очередь пуста, ждем...\n";
        sleep(5);
    }
}
?>

6. Ограничение частоты запросов (Rate Limiting)

<?php
function checkRateLimit($redis, $userId, $maxRequests = 10, $timeWindow = 60) {
    $key = "rate_limit:{$userId}";
    $currentTime = time();
    
    // Удаляем старые запросы
    $redis->zremrangebyscore($key, 0, $currentTime - $timeWindow);
    
    // Получаем количество запросов в текущем окне
    $requestCount = $redis->zcard($key);
    
    if ($requestCount < $maxRequests) {
        // Добавляем новый запрос
        $redis->zadd($key, $currentTime, $currentTime . '_' . uniqid());
        $redis->expire($key, $timeWindow);
        return true;
    }
    
    return false;
}

// Использование
$userId = 123;

if (checkRateLimit($redis, $userId, 5, 60)) {
    echo "Запрос разрешен\n";
    // Выполняем действие
} else {
    echo "Слишком много запросов. Попробуйте позже.\n";
    http_response_code(429);
}
?>