Redis
Introducción
Redis es un almacén de clave-valor avanzado y de código abierto. A menudo se le llama servidor de estructuras de datos, ya que las claves pueden contener cadenas, hashes, listas, conjuntos y conjuntos ordenados.
Antes de usar Redis con Laravel, te recomendamos que instalas y uses la extensión PHP PhpRedis a través de PECL. La extensión es más compleja de instalar en comparación con los paquetes PHP "user-land", pero puede ofrecer un mejor rendimiento para aplicaciones que hacen un uso intensivo de Redis. Si estás utilizando Laravel Sail, esta extensión ya está instalada en el contenedor Docker de tu aplicación.
Si no puedes instalar la extensión PhpRedis, puedes instalar el paquete predis/predis
a través de Composer. Predis es un cliente Redis escrito completamente en PHP y no requiere extensiones adicionales:
composer require predis/predis:^2.0
Configuración
Puedes configurar la configuración de Redis de tu aplicación a través del archivo de configuración config/database.php
. Dentro de este archivo, verás un array redis
que contiene los servidores Redis utilizados por tu aplicación:
'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'), ], ],
Cada servidor Redis definido en tu archivo de configuración debe tener un nombre, host y un puerto, a menos que definas una sola URL para representar la conexión 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:password@127.0.0.1:6380?database=1', ], ],
Configurando el Esquema de Conexión
Por defecto, los clientes de Redis utilizarán el esquema tcp
al conectarse a tus servidores Redis; sin embargo, puedes usar cifrado TLS / SSL especificando una opción de configuración scheme
en el array de configuración de tu servidor 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'),],
Clústeres
Si tu aplicación está utilizando un clúster de servidores Redis, debes definir estos clústeres dentro de una clave clusters
de tu configuración de Redis. Esta clave de configuración no existe por defecto, así que necesitarás crearla dentro del archivo de configuración config/database.php
de tu aplicación:
'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'), ], ], ], // ...],
Por defecto, Laravel utilizará el clustering nativo de Redis ya que el valor de configuración options.cluster
está configurado en redis
. El clustering de Redis es una excelente opción predeterminada, ya que maneja la conmutación por error de manera eficiente.
Laravel también admite sharding del lado del cliente. Sin embargo, el sharding del lado del cliente no maneja la conmutación por error; por lo tanto, se adapta principalmente a datos en caché transitorios que están disponibles desde otro almacén de datos primario.
Si deseas utilizar sharding del lado del cliente en lugar del clustering nativo de Redis, puedes eliminar el valor de configuración options.cluster
dentro del archivo de configuración config/database.php
de tu aplicación:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), 'clusters' => [ // ... ], // ...],
Predis
Si deseas que tu aplicación interactúe con Redis a través del paquete Predis, debes asegurarte de que el valor de la variable de entorno REDIS_CLIENT
sea predis
:
'redis' => [ 'client' => env('REDIS_CLIENT', 'predis'), // ...],
Además de las opciones de configuración predeterminadas, Predis admite parámetros de conexión adicionales que pueden definirse para cada uno de tus servidores Redis. Para utilizar estas opciones de configuración adicionales, agrégalas a la configuración de tu servidor Redis en el archivo de configuración config/database.php
de tu aplicación:
'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,],
PhpRedis
Por defecto, Laravel utilizará la extensión PhpRedis para comunicarse con Redis. El cliente que Laravel utilizará para comunicarse con Redis está dictado por el valor de la opción de configuración redis.client
, que típicamente refleja el valor de la variable de entorno REDIS_CLIENT
:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), // ...],
Además de las opciones de configuración predeterminadas, PhpRedis admite los siguientes parámetros de conexión adicionales: name
, persistent
, persistent_id
, prefix
, read_timeout
, retry_interval
, timeout
y context
. Puedes añadir cualquiera de estas opciones a la configuración de tu servidor Redis en el archivo de configuración 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], ],],
Serialización y Comprensión de PhpRedis
La extensión PhpRedis también se puede configurar para usar una variedad de serializadores y algoritmos de compresión. Estos algoritmos se pueden configurar a través del array options
de tu configuración de 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, ], // ...],
Los serializers actualmente soportados incluyen: Redis::SERIALIZER_NONE
(por defecto), Redis::SERIALIZER_PHP
, Redis::SERIALIZER_JSON
, Redis::SERIALIZER_IGBINARY
y Redis::SERIALIZER_MSGPACK
.
Los algoritmos de compresión compatibles incluyen: Redis::COMPRESSION_NONE
(predeterminado), Redis::COMPRESSION_LZF
, Redis::COMPRESSION_ZSTD
y Redis::COMPRESSION_LZ4
.
Interactuando Con Redis
Puedes interactuar con Redis llamando a varios métodos en la facade
de Redis
facade. La facade
de Redis
admite métodos dinámicos, lo que significa que puedes llamar a cualquier comando de Redis en la facade
y el comando será pasado directamente a Redis. En este ejemplo, llamaremos al comando GET
de Redis llamando al método get
en la facade
de Redis
:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use Illuminate\Support\Facades\Redis;use Illuminate\View\View; class UserController extends Controller{ /** * Show the profile for the given user. */ public function show(string $id): View { return view('user.profile', [ 'user' => Redis::get('user:profile:'.$id) ]); }}
Como se mencionó anteriormente, puedes llamar a cualquiera de los comandos de Redis en la fachada Redis
. Laravel utiliza métodos mágicos para pasar los comandos al servidor Redis. Si un comando de Redis espera argumentos, debes pasarlos al método correspondiente de la fachada:
use Illuminate\Support\Facades\Redis; Redis::set('name', 'Taylor'); $values = Redis::lrange('names', 5, 10);
Alternativamente, puedes enviar comandos al servidor utilizando el método command
de la fachada Redis
, que acepta el nombre del comando como su primer argumento y un array de valores como su segundo argumento:
$values = Redis::command('lrange', ['name', 5, 10]);
Usando Múltiples Conexiones Redis
El archivo de configuración config/database.php
de tu aplicación te permite definir múltiples conexiones / servidores Redis. Puedes obtener una conexión a una conexión Redis específica utilizando el método connection
de la fachada Redis
:
$redis = Redis::connection('connection-name');
Para obtener una instancia de la conexión Redis predeterminada, puedes llamar al método connection
sin argumentos adicionales:
$redis = Redis::connection();
Transacciones
El método transaction
de la fachada Redis
proporciona un envoltorio conveniente alrededor de los comandos nativos MULTI
y EXEC
de Redis. El método transaction
acepta una función anónima como su único argumento. Esta función anónima recibirá una instancia de conexión a Redis y puede emitir cualquier comando que desee a esta instancia. Todos los comandos de Redis emitidos dentro de la función anónima se ejecutarán en una sola transacción atómica:
use Redis;use Illuminate\Support\Facades; Facades\Redis::transaction(function (Redis $redis) { $redis->incr('user_visits', 1); $redis->incr('total_visits', 1);});
[!WARNING] Al definir una transacción de Redis, no puedes recuperar ningún valor de la conexión Redis. Recuerda que tu transacción se ejecuta como una sola operación atómica y que esa operación no se ejecuta hasta que tu
función anónima
haya terminado de ejecutar sus comandos.
Scripts de Lua
El método eval
proporciona otro método para ejecutar múltiples comandos Redis en una sola operación atómica. Sin embargo, el método eval
tiene la ventaja de poder interactuar con e inspeccionar los valores clave de Redis durante esa operación. Los scripts de Redis están escritos en el lenguaje de programación Lua.
El método eval
puede dar un poco de miedo al principio, pero exploraremos un ejemplo básico para romper el hielo. El método eval
espera varios argumentos. Primero, debes pasar el script Lua (como una cadena) al método. En segundo lugar, debes pasar el número de claves (como un entero) con las que interactúa el script. En tercer lugar, debes pasar los nombres de esas claves. Finalmente, puedes pasar cualquier otro argumento adicional que necesites acceder dentro de tu script.
En este ejemplo, incrementaremos un contador, inspeccionaremos su nuevo valor e incrementaremos un segundo contador si el valor del primer contador es mayor que cinco. Finalmente, devolveremos el valor del primer contador:
$value = Redis::eval(<<<'LUA' local counter = redis.call("incr", KEYS[1]) if counter > 5 then redis.call("incr", KEYS[2]) end return counterLUA, 2, 'first-counter', 'second-counter');
[!WARNING] Por favor, consulta la documentación de Redis para obtener más información sobre la programación de scripts en Redis.
Comando de Pipelining
A veces es posible que necesites ejecutar docenas de comandos de Redis. En lugar de hacer un viaje de red a tu servidor Redis por cada comando, puedes usar el método pipeline
. El método pipeline
acepta un argumento: una función anónima que recibe una instancia de Redis. Puedes emitir todos tus comandos a esta instancia de Redis y se enviarán todos al servidor Redis al mismo tiempo para reducir los viajes de red al servidor. Los comandos aún se ejecutarán en el orden en que fueron emitidos:
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 proporciona una interfaz conveniente para los comandos publish
y subscribe
de Redis. Estos comandos de Redis te permiten escuchar mensajes en un "canal" dado. Puedes publicar mensajes en el canal desde otra aplicación, o incluso utilizando otro lenguaje de programación, lo que permite una fácil comunicación entre aplicaciones y procesos.
Primero, configuremos un listener de canal utilizando el método subscribe
. Colocaremos esta llamada al método dentro de un comando Artisan ya que llamar al método subscribe
inicia un proceso de larga duración:
<?php namespace App\Console\Commands; use Illuminate\Console\Command;use Illuminate\Support\Facades\Redis; class RedisSubscribe extends Command{ /** * The name and signature of the console command. * * @var string */ protected $signature = 'redis:subscribe'; /** * The console command description. * * @var string */ protected $description = 'Subscribe to a Redis channel'; /** * Execute the console command. */ public function handle(): void { Redis::subscribe(['test-channel'], function (string $message) { echo $message; }); }}
Ahora podemos publicar mensajes en el canal utilizando el método publish
:
use Illuminate\Support\Facades\Redis; Route::get('/publish', function () { // ... Redis::publish('test-channel', json_encode([ 'name' => 'Adam Wathan' ]));});
Suscripciones con Wildcard
Usando el método psubscribe
, puedes suscribirte a un canal con un wildcard, lo que puede ser útil para capturar todos los mensajes en todos los canales. El nombre del canal se pasará como segundo argumento a la función anónima
proporcionada:
Redis::psubscribe(['*'], function (string $message, string $channel) { echo $message;}); Redis::psubscribe(['users.*'], function (string $message, string $channel) { echo $message;});