1. База данных
  2. Redis

Присоединяйся к нашему Telegram сообществу @webblend!

Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.

Введение

Redis - это открытое программное обеспечение для создания распределенного хранилища данных. Его часто называют сервером структурированных данных, поскольку ключи могут содержать строки, хэши, списки, множества и сортированные множества.

Перед использованием Redis в Laravel мы рекомендуем установить и использовать расширение PHP phpredis через PECL. Установка этого расширения сложнее по сравнению с "user-land" PHP-пакетами, но она может обеспечить лучшую производительность для приложений, которые часто используют Redis. Если вы используете Laravel Sail, это расширение уже установлено в контейнере Docker вашего приложения.

Если вы не можете установить расширение phpredis, вы можете установить пакет predis/predis с помощью Composer. Predis - это клиент Redis, написанный исключительно на PHP и не требует дополнительных расширений:

composer require predis/predis

Настройка

Вы можете настроить настройки Redis вашего приложения с помощью файла конфигурации config/database.php. В этом файле вы увидите массив redis, содержащий серверы Redis, используемые вашим приложением:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
'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),
],
 
],

Каждый сервер Redis, определенный в вашем файле конфигурации, обязан иметь имя, хост и порт, если вы не определите единственный URL для представления соединения с Redis:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
'default' => [
'url' => 'tcp://127.0.0.1:6379?database=0',
],
 
'cache' => [
'url' => 'tls://user:[email protected]:6380?database=1',
],
 
],

Настройка схемы соединения

По умолчанию клиенты Redis будут использовать схему tcp при подключении к вашим серверам Redis; однако вы можете использовать шифрование TLS / SSL, указав параметр конфигурации scheme в массиве конфигурации сервера Redis:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
'default' => [
'scheme' => 'tls',
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DB', 0),
],
 
],

Кластеры

Если ваше приложение использует кластер серверов Redis, вы должны определить эти кластеры в ключе clusters вашей конфигурации Redis. Этот ключ конфигурации не существует по умолчанию, поэтому вам нужно создать его в файле конфигурации вашего приложения config/database.php:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
'clusters' => [
'default' => [
[
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
],
 
],

По умолчанию кластеры выполнят разделение данных на стороне клиента среди ваших узлов, что позволяет объединять узлы и создавать большое количество доступной оперативной памяти. Однако разделение данных на стороне клиента не обрабатывает сбои; поэтому оно в основном подходит для временных кешированных данных, доступных из другого основного источника данных.

Если вы хотите использовать нативное кластерное разделение Redis вместо разделения данных на стороне клиента, вы можете указать это, установив значение options.cluster в redis в файле конфигурации вашего приложения config/database.php:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
],
 
'clusters' => [
// ...
],
 
],

Predis

Если вы хотите, чтобы ваше приложение взаимодействовало с Redis с использованием пакета Predis, убедитесь, что значение переменной окружения REDIS_CLIENT равно predis:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'predis'),
 
// ...
],

Помимо опций конфигурации сервера по умолчанию, таких как host, port, database и password, Predis поддерживает дополнительные параметры соединения, которые могут быть определены для каждого из ваших серверов Redis. Чтобы использовать эти дополнительные параметры конфигурации, добавьте их в конфигурацию вашего сервера Redis в файле конфигурации вашего приложения config/database.php:

'default' => [
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
'read_write_timeout' => 60,
],

Псевдоним Redis Facade

Файл конфигурации Laravel config/app.php содержит массив aliases, который определяет все псевдонимы классов, которые будут зарегистрированы фреймворком. По умолчанию ни один псевдоним Redis не включен, потому что это может конфликтовать с именем класса Redis, предоставляемым расширением phpredis. Если вы используете клиент Predis и хотите добавить псевдоним Redis, вы можете добавить его в массив aliases в файле конфигурации вашего приложения config/app.php:

'aliases' => Facade::defaultAliases()->merge([
'Redis' => Illuminate\Support\Facades\Redis::class,
])->toArray(),

phpredis

По умолчанию Laravel будет использовать расширение phpredis для связи с Redis. Клиент, который Laravel будет использовать для связи с Redis, определяется значением опции конфигурации redis.client, которая обычно отражает значение переменной окружения REDIS_CLIENT:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
// Остальная конфигурация Redis...
],

Помимо опций конфигурации сервера по умолчанию, таких как scheme, host, port, database и password, phpredis поддерживает следующие дополнительные параметры соединения: name, persistent, persistent_id, prefix, read_timeout, retry_interval, timeout и context. Вы можете добавить любой из этих параметров в конфигурацию вашего сервера Redis в файле конфигурации config/database.php:

'default' => [
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
'read_timeout' => 60,
'context' => [
// 'auth' => ['username', 'secret'],
// 'stream' => ['verify_peer' => false],
],
],

Сериализация и сжатие phpredis

Расширение phpredis также может быть настроено для использования различных алгоритмов сериализации и сжатия. Эти алгоритмы могут быть настроены с использованием массива options в вашей конфигурации Redis:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
'options' => [
'serializer' => Redis::SERIALIZER_MSGPACK,
'compression' => Redis::COMPRESSION_LZ4,
],
 
// Остальная конфигурация Redis...
],

В настоящее время поддерживаются следующие алгоритмы сериализации: Redis::SERIALIZER_NONE (по умолчанию), Redis::SERIALIZER_PHP, Redis::SERIALIZER_JSON, Redis::SERIALIZER_IGBINARY и Redis::SERIALIZER_MSGPACK.

Поддерживаются следующие алгоритмы сжатия: Redis::COMPRESSION_NONE (по умолчанию), Redis::COMPRESSION_LZF, Redis::COMPRESSION_ZSTD и Redis::COMPRESSION_LZ4.

Взаимодействие с Redis

Вы можете взаимодействовать с Redis, вызывая различные методы на фасаде Redis. Фасад Redis поддерживает динамические методы, что означает, что вы можете вызывать любую команду Redis на фасаде, и команда будет передана непосредственно в Redis. В этом примере мы вызовем команду Redis GET, вызвав метод get на фасаде Redis:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Redis;
use Illuminate\View\View;
 
class UserController extends Controller
{
/**
* Показать профиль для указанного пользователя.
*/
public function show(string $id): View
{
return view('user.profile', [
'user' => Redis::get('user:profile:'.$id)
]);
}
}

Как упоминалось выше, вы можете вызывать любые команды Redis на фасаде Redis. Laravel использует магические методы для передачи команд серверу Redis. Если команда Redis ожидает аргументы, вы должны передать их соответствующему методу фасада:

use Illuminate\Support\Facades\Redis;
 
Redis::set('name', 'Taylor');
 
$values = Redis::lrange('names', 5, 10);

Кроме того, вы можете передавать команды серверу, используя метод command фасада Redis, который принимает имя команды в качестве первого аргумента и массив значений в качестве второго аргумента:

$values = Redis::command('lrange', ['name', 5, 10]);

Использование нескольких соединений с Redis

Файл конфигурации вашего приложения config/database.php позволяет вам определить несколько соединений/серверов Redis. Вы можете получить соединение с определенным сервером Redis, используя метод connection фасада Redis:

$redis = Redis::connection('connection-name');

Чтобы получить экземпляр соединения с сервером Redis по умолчанию, вы можете вызвать метод connection без дополнительных аргументов:

$redis = Redis::connection();

Транзакции

Метод transaction фасада Redis предоставляет удобную обертку вокруг нативных команд MULTI и EXEC Redis. Метод transaction принимает замыкание в качестве единственного аргумента. Это замыкание получит экземпляр соединения Redis и может выполнять любые команды на этом экземпляре. Все команды Redis, выпущенные внутри замыкания, будут выполнены в единственной, атомарной транзакции:

use Redis;
use Illuminate\Support\Facades;
 
Facades\Redis::transaction(function (Redis $redis) {
$redis->incr('user_visits', 1);
$redis->incr('total_visits', 1);
});

Внимание При определении транзакции Redis вы не можете извлекать значения из соединения Redis. Помните, что ваша транзакция выполняется как единая, атомарная операция, и эта операция не выполняется, пока ваше замыкание не закончит выполнение своих команд.

Сценарии Lua

Метод eval предоставляет еще один способ выполнения нескольких команд Redis в единой, атомарной операции. Однако метод eval имеет преимущество в том, что он может взаимодействовать и проверять значения ключей Redis во время этой операции. Скрипты Redis написаны на языке программирования Lua.

Метод eval может показаться сложным сначала, но мы рассмотрим базовый пример, чтобы снять напряжение. Метод eval ожидает несколько аргументов. Во-первых, вы должны передать скрипт Lua (в виде строки) методу. Во-вторых, вы должны передать количество ключей (в виде целого числа), с которыми взаимодействует скрипт. В-третьих, вы должны передать имена этих ключей. Наконец, вы можете передать любые другие дополнительные аргументы, которые вам нужны для доступа в вашем скрипте.

В этом примере мы увеличим счетчик, проверим его новое значение и увеличим второй счетчик, если значение первого счетчика больше пяти. Наконец, мы вернем значение первого счетчика:

$value = Redis::eval(<<<'LUA'
local counter = redis.call("incr", KEYS[1])
 
if counter > 5 then
redis.call("incr", KEYS[2])
end
 
return counter
LUA, 2, 'first-counter', 'second-counter');

Внимание Пожалуйста, ознакомьтесь с документацией Redis для получения дополнительной информации о скриптах Redis.

Пайплайнинг команд

Иногда вам может потребоваться выполнить десятки команд Redis. Вместо того чтобы делать сетевой запрос к вашему серверу Redis для каждой команды, вы можете использовать метод pipeline. Метод pipeline принимает один аргумент: замыкание, которое получает экземпляр Redis. Вы можете выполнять все свои команды на этом экземпляре Redis, и все они будут отправлены на сервер Redis одновременно для уменьшения сетевых запросов к серверу. Команды будут выполнены в том порядке, в котором они были выпущены:

use Redis;
use Illuminate\Support\Facades;
 
Facades\Redis::pipeline(function (Redis $pipe) {
for ($i = 0; $i < 1000; $i++) {
$pipe->set("key:$i", $i);
}
});

Pub / Sub

Laravel предоставляет удобный интерфейс для команд Redis publish и subscribe. Эти команды Redis позволяют прослушивать сообщения на заданном «канале». Вы можете отправлять сообщения на канал из другого приложения или даже с использованием другого языка программирования, обеспечивая легкую связь между приложениями и процессами.

Сначала давайте настроим прослушиватель канала с использованием метода subscribe. Мы поместим вызов этого метода в команду Artisan, поскольку вызов метода subscribe начинает долгий процесс:

<?php
 
namespace App\Console\Commands;
 
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
 
class RedisSubscribe extends Command
{
/**
* Имя и сигнатура консольной команды.
*
* @var string
*/
protected $signature = 'redis:subscribe';
 
/**
* Описание консольной команды.
*
* @var string
*/
protected $description = 'Subscribe to a Redis channel';
 
/**
* Выполнить консольную команду.
*/
public function handle(): void
{
Redis::subscribe(['test-channel'], function (string $message) {
echo $message;
});
}
}

Теперь мы можем отправлять сообщения на канал с использованием метода publish:

use Illuminate\Support\Facades\Redis;
 
Route::get('/publish', function () {
// ...
 
Redis::publish('test-channel', json_encode([
'name' => 'Adam Wathan'
]));
});

Подписка на события с использованием шаблонов

С использованием метода psubscribe вы можете подписаться на канал с использованием подстановочных символов, что может быть полезно для перехвата всех сообщений на всех каналах. Имя канала будет передано вторым аргументом в предоставленное замыкание:

Redis::psubscribe(['*'], function (string $message, string $channel) {
echo $message;
});
 
Redis::psubscribe(['users.*'], function (string $message, string $channel) {
echo $message;
});