Налаштування Redis для кешування даних веб-приложення
Redis як кэш працює за простим принципом: читати з Redis на порядок швидше, ніж з PostgreSQL або обчислювати заново. Latency Redis — 0.1–1 мс проти 5–50 мс для простого SQL запиту та 100–500 мс для важкого. Завдання не в тому, щоб кешувати все, а щоб кешувати правильно: знати, що кешувати, на скільки, та як інвалідувати.
Установка та базова конфігурація
apt install redis-server
/etc/redis/redis.conf — ключові параметри:
# Привязка тільки до localhost, якщо Redis на тому ж сервері
bind 127.0.0.1
# Пароль (обов'язково для продакшену)
requirepass YourStrongRedisPassword
# Максимальний об'єм пам'яті
maxmemory 2gb
# Політика вилучення при досягненні ліміту
maxmemory-policy allkeys-lru
# Персистентність: для чистого кеша можна відключити
save ""
appendonly no
# Кількість баз даних
databases 16
# Таймаут клієнтського з'єднання
timeout 300
# TCP keepalive
tcp-keepalive 300
maxmemory-policy:
-
allkeys-lru— вилучати давно невикористовувані ключі з усієї БД. Найкращий вибір для чистого кеша. -
volatile-lru— вилучати тільки ключі з TTL. Якщо набір ключів без TTL, вони ніколи не вилучаються. -
allkeys-lfu— Least Frequently Used — краще LRU для Zipf-розподілу. -
noeviction— при вичерпанні пам'яті повертати помилку. Для не-кеша (очереди, сессії).
Базові паттерни кешування
Cache-Aside (Lazy Loading) — приложення саме керує кешем: спочатку читає з Redis, при промахе — з БД, кладе в Redis.
Приклад PHP:
class ProductRepository
{
private const CACHE_TTL = 3600; // 1 година
public function findById(int $id): ?Product
{
$cacheKey = "product:{$id}";
$cached = $this->redis->get($cacheKey);
if ($cached !== false) {
return unserialize($cached);
}
$product = $this->db->find(Product::class, $id);
if ($product) {
$this->redis->setex($cacheKey, self::CACHE_TTL, serialize($product));
}
return $product;
}
public function save(Product $product): void
{
$this->db->persist($product);
$this->db->flush();
// Інвалідація кеша після збереження
$this->redis->del("product:{$product->getId()}");
}
}
Write-Through — при записі в БД одночасно оновлювати кеш. Плюс: кеш завжди актуальний. Мінус: запис повільніший, кешуються дані, які, можливо, не будуть читатися.
Read-Through — кеш сам запитує дані з БД при промахе. Реалізується через Redis-модулі або зовнішні бібліотеки (RedisGears).
Laravel Cache
Laravel підтримує Redis як cache driver з коробки:
// config/cache.php
'default' => env('CACHE_DRIVER', 'redis'),
'stores' => [
'redis' => [
'driver' => 'redis',
'connection' => 'cache',
'lock_connection' => 'default',
],
],
config/database.php:
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'), // phpredis швидше predis
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', 'myapp_'),
],
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'), // Окремна БД для кеша
],
],
Використання:
// Кеш з автоматичним обчисленням при промахе
$products = Cache::remember('products:featured', 3600, function () {
return Product::where('is_featured', true)->with('category')->get();
});
// Теги для групової інвалідації
$product = Cache::tags(['products', 'category:5'])->remember(
"product:{$id}",
3600,
fn() => Product::find($id)
);
// Інвалідація всієї групи
Cache::tags(['products'])->flush();
Теги Redis вимагають redis або memcached драйвера — не працюють з file/database кешем.
Кешування запитів до БД
Для важких агрегаційних запитів, які рідко змінюються:
$stats = Cache::remember('dashboard:stats', 300, function () {
return DB::table('orders')
->selectRaw('
COUNT(*) as total_orders,
SUM(total_amount) as revenue,
AVG(total_amount) as avg_order
')
->whereDate('created_at', today())
->first();
});
5 хвилин TTL для статистики дашборда — розумний компроміс між свіжістю та навантаженням.
Моніторинг кеша
# Статистика Redis
redis-cli -a password INFO stats | grep -E "keyspace_hits|keyspace_misses|used_memory_human"
# Hit rate = hits / (hits + misses)
# Добре: > 90%
# Активні ключі та TTL
redis-cli -a password SCAN 0 MATCH "product:*" COUNT 100
# Розмір кожної групи
redis-cli -a password --bigkeys
# Топ команд
redis-cli -a password MONITOR # Увага: навантажує сервер, тільки для дебугу
Production моніторинг — Redis Exporter + Grafana:
docker run -d \
--name redis_exporter \
-p 9121:9121 \
oliver006/redis_exporter \
--redis.addr=redis://localhost:6379 \
--redis.password=YourPassword
Ключові метрики Grafana (ID 11835): redis_keyspace_hits_total, redis_keyspace_misses_total, redis_memory_used_bytes, redis_connected_clients.
Серіалізація даних
Серіалізовані PHP об'єкти займають більше місця, ніж JSON. Для простих структур — JSON швидше та читаніше:
// Повільно та об'ємно
$this->redis->set($key, serialize($object));
$object = unserialize($this->redis->get($key));
// Швидше для простих DTO
$this->redis->set($key, json_encode($data));
$data = json_decode($this->redis->get($key), true);
// Для великих об'єктів — igbinary (розширення PHP)
$this->redis->set($key, igbinary_serialize($object));
$object = igbinary_unserialize($this->redis->get($key));
igbinary дає ~50% стиснення порівняно з serialize та працює швидше.
Таймлайн
Базова установка Redis з налаштуванням Laravel cache driver — 4–6 годин. Впровадження кешування в конкретних контролерах/репозиторіях з правильною інвалідацією — 1–2 дні залежно від обсягу. Налаштування моніторингу — половина дня.







