git |
---|
478c8a3d66ffa31118831bfd3365db9fa0e2baa4 |
Redis – это расширенное хранилище ключ-значение с открытым исходным кодом. Его часто называют сервером структуры данных, поскольку ключи могут содержать строки, хеши, списки, наборы и отсортированные наборы.
Перед использованием Redis с Laravel мы рекомендуем вам установить и использовать расширение PhpRedis PHP через PECL. Расширение сложнее установить по сравнению с пакетами PHP пользовательского слоя, но оно может обеспечить лучшую производительность для приложений, интенсивно использующих Redis. Если вы используете Laravel Sail, то это расширение уже установлено в контейнере Docker вашего приложения.
Если вы не можете установить расширение PhpRedis, то установите пакет predis/predis
через Composer. Predis – это клиент Redis, полностью написанный на PHP и не требующий дополнительных расширений:
composer require predis/predis:^2.0
Вы можете настроить параметры Redis для своего приложения с помощью конфигурационного файла config/database.php
. В этом файле вы увидите массив redis
, содержащий серверы Redis, используемые вашим приложением:
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],
Каждый сервер Redis, определенный в вашем конфигурационном файле, должен иметь имя, хост и порт, либо единый URL соединения Redis:
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'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:
'default' => [
'scheme' => 'tls',
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'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'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'clusters' => [
'default' => [
[
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
],
],
// ...
],
По умолчанию Laravel будет использовать встроенное кластерирование Redis, так как значение конфигурации options.cluster
установлено на redis
. Кластеризация Redis - отличный вариант по умолчанию, так как она гармонично обрабатывает аварийные ситуации.
Laravel также поддерживает клиентское разделение данных (sharding). Однако клиентское разделение данных не обрабатывает аварийные ситуации, поэтому оно в основном подходит для временных кешированных данных, доступных из другого основного хранилища данных.
Если вы хотите использовать клиентское разделение данных вместо встроенной кластеризации Redis, вы можете удалить значение конфигурации options.cluster
в файле конфигурации вашего приложения config/database.php
:
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'clusters' => [
// ...
],
// ...
],
Если вы хотите, чтобы ваше приложение взаимодействовало с Redis через пакет Predis, то вы должны убедиться, что значение переменной окружения REDIS_CLIENT
установлено как predis
:
'redis' => [
'client' => env('REDIS_CLIENT', 'predis'),
// ...
],
Помимо параметров конфигурации по умолчанию, Predis поддерживает дополнительные параметры подключения, которые могут быть определены для каждого из ваших серверов Redis. Чтобы использовать эти дополнительные параметры конфигурации, добавьте их в конфигурацию вашего сервера Redis в файле конфигурации вашего приложения config/database.php
:
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'read_write_timeout' => 60,
],
По умолчанию Laravel будет использовать расширение PhpRedis для соединения с Redis. Клиент, который Laravel будет использовать для соединения с Redis, определяется значением параметра redis.client
конфигурации, который обычно проксирует значение переменной REDIS_CLIENT
окружения:
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
// ...
],
Помимо параметров конфигурации по умолчанию, PhpRedis поддерживает следующие дополнительные параметры подключения: name
, persistent
, persistent_id
, prefix
, read_timeout
, retry_interval
, timeout
и context
. Вы можете добавить любой из этих параметров в конфигурацию вашего сервера Redis в файле конфигурации вашего приложения config/database.php
:
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'read_timeout' => 60,
'context' => [
// 'auth' => ['username', 'secret'],
// 'stream' => ['verify_peer' => false],
],
],
Расширение PhpRedis также можно настроить для использования различных алгоритмов сериализации и сжатия. Эти алгоритмы можно настроить с помощью массива options
вашей конфигурации Redis:
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
'serializer' => Redis::SERIALIZER_MSGPACK,
'compression' => Redis::COMPRESSION_LZ4,
],
// ...
],
В настоящее время поддерживаются следующие сериализаторы: Redis::SERIALIZER_NONE
(default), Redis::SERIALIZER_PHP
, Redis::SERIALIZER_JSON
, Redis::SERIALIZER_IGBINARY
, и Redis::SERIALIZER_MSGPACK
.
Поддерживаемые алгоритмы сжатия: Redis::COMPRESSION_NONE
(default), Redis::COMPRESSION_LZF
, Redis::COMPRESSION_ZSTD
, и Redis::COMPRESSION_LZ4
.
Вы можете взаимодействовать с 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]);
Конфигурационный файл 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. Все команды Redis в рамках замыкания будут выполняться в одной атомарной транзакции:
use Redis;
use Illuminate\Support\Facades;
Facades\Redis::transaction(function (Redis $redis) {
$redis->incr('user_visits', 1);
$redis->incr('total_visits', 1);
});
Warning
При определении транзакции Redis вы не можете получать какие-либо значения из соединения Redis. Помните, ваша транзакция выполняется как одна атомарная операция, и эта операция не выполнится, пока не завершится выполнение всех команд замыкания.
Метод 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');
Warning
Пожалуйста, обратитесь к документации 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);
}
});
Laravel предлагает удобный интерфейс для команд publish
и subscribe
Redis. Эти команды 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;
});