1. Base de datos
  2. Redis

Introducción

Redis es un almacén avanzado de clave y valor de código abierto. A menudo se le llama servidor de estructura de datos ya que las claves pueden contener cadenas, hashes, listas, conjuntos y conjuntos ordenados.

Antes de usar Redis con Laravel, le recomendamos que instale y use la extensión phpredis a través de PECL. La extensión es más compleja de instalar en comparación con los paquetes PHP "de usuario", pero puede ofrecer un mejor rendimiento para aplicaciones que hacen un uso intensivo de Redis. Si está utilizando Laravel Sail, esta extensión ya está instalada en el contenedor Docker de su aplicación.

Si no puede instalar la extensión phpredis, puede instalar el paquete predis/predis a través de Composer. Predis es un cliente de Redis escrito completamente en PHP y no requiere extensiones adicionales:

composer require predis/predis

Configuración

Puede configurar los ajustes de Redis de su aplicación a través del archivo de configuración config/database.php. En este archivo, verá una matriz redis que contiene los servidores Redis utilizados por su aplicación:

'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),
],
 
],

Cada servidor Redis definido en su archivo de configuración debe tener un nombre, host y un puerto a menos que defina una sola URL para representar la conexión 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',
],
 
],

Configuración del Esquema de Conexión

De forma predeterminada, los clientes de Redis utilizarán el esquema tcp al conectarse a sus servidores Redis; sin embargo, puede utilizar cifrado TLS / SSL especificando una opción de configuración scheme en la matriz de configuración de su servidor 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),
],
 
],

Clusters

Si su aplicación utiliza un clúster de servidores Redis, debe definir estos clústeres dentro de una clave clusters de su configuración de Redis. Esta clave de configuración no existe por defecto, así que deberá crearla dentro del archivo de configuración config/database.php de su aplicación:

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

De forma predeterminada, los clústeres realizarán fragmentación en el lado del cliente entre sus nodos, lo que le permite agrupar nodos y crear una gran cantidad de RAM disponible. Sin embargo, la fragmentación en el lado del cliente no maneja el cambio automático; por lo tanto, es adecuada principalmente para datos en caché transitorios que están disponibles desde otro almacenamiento de datos primario.

Si desea utilizar el clúster nativo de Redis en lugar de la fragmentación en el lado del cliente, puede especificarlo configurando el valor options.cluster en redis dentro del archivo de configuración config/database.php de su aplicación:

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

Predis

Si desea que su aplicación interactúe con Redis a través del paquete Predis, asegúrese 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 del servidor predeterminadas host, port, database y password, Predis admite parámetros de conexión adicionales que se pueden definir para cada uno de sus servidores Redis. Para utilizar estas opciones de configuración adicionales, agréguelas a la configuración de su servidor Redis en el archivo de configuración config/database.php de su aplicación:

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

El Alias de la Fachada Redis

El archivo de configuración config/app.php de Laravel contiene una matriz aliases que define todos los alias de clase que registrará el marco. Por defecto, no se incluye ningún alias Redis porque entraría en conflicto con el nombre de clase Redis proporcionado por la extensión phpredis. Si está utilizando el cliente Predis y desea agregar un alias Redis, puede agregarlo a la matriz aliases en el archivo de configuración config/app.php de su aplicación:

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

phpredis

De forma predeterminada, 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 refleja típicamente el valor de la variable de entorno REDIS_CLIENT:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
// Resto de la configuración de Redis...
],

Además de las opciones de configuración del servidor predeterminadas scheme, host, port, database y password, phpredis admite los siguientes parámetros de conexión adicionales: name, persistent, persistent_id, prefix, read_timeout, retry_interval, timeout y context. Puede agregar cualquiera de estas opciones a la configuración de su servidor Redis en el archivo de configuración config/database.php de su aplicación:

'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],
],
],

Serialización y Compresión de phpredis

La extensión phpredis también se puede configurar para utilizar una variedad de algoritmos de serialización y compresión. Estos algoritmos se pueden configurar a través del array options en su configuración de Redis:

'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
'options' => [
'serializer' => Redis::SERIALIZER_MSGPACK,
'compression' => Redis::COMPRESSION_LZ4,
],
 
// Resto de la configuración de Redis...
],

Los algoritmos de serialización admitidos actualmente incluyen: Redis::SERIALIZER_NONE (predeterminado), Redis::SERIALIZER_PHP, Redis::SERIALIZER_JSON, Redis::SERIALIZER_IGBINARY y Redis::SERIALIZER_MSGPACK.

Los algoritmos de compresión admitidos incluyen: Redis::COMPRESSION_NONE (predeterminado), Redis::COMPRESSION_LZF, Redis::COMPRESSION_ZSTD, y Redis::COMPRESSION_LZ4.

Interacción con Redis

Puede interactuar con Redis llamando a varios métodos en la fachada Redis. La fachada Redis admite métodos dinámicos, lo que significa que puede llamar a cualquier comando Redis en la fachada y el comando se enviará directamente a Redis. En este ejemplo, llamaremos al comando GET de Redis llamando al método get en la fachada Redis:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Redis;
use Illuminate\View\View;
 
class UserController extends Controller
{
/**
* Muestra el perfil del usuario dado.
*/
public function show(string $id): View
{
return view('user.profile', [
'user' => Redis::get('user:profile:'.$id)
]);
}
}

Como se mencionó anteriormente, puede 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 Redis espera argumentos, debe pasarlos al método correspondiente de la fachada:

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

Alternativamente, puede pasar 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]);

Uso de Múltiples Conexiones Redis

El archivo de configuración config/database.php de su aplicación le permite definir múltiples conexiones / servidores Redis. Puede obtener una conexión a un servidor Redis específico utilizando el método connection de la fachada Redis:

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

Para obtener una instancia de la conexión Redis predeterminada, puede 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 un cierre como su único argumento. Este cierre recibirá una instancia de conexión Redis y podrá emitir cualquier comando que desee a esta instancia. Todos los comandos Redis emitidos dentro del cierre se ejecutarán en una única 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);
});

Advertencia Al definir una transacción de Redis, no puede recuperar ningún valor de la conexión de Redis. Recuerde, su transacción se ejecuta como una operación única y atómica, y esa operación no se ejecuta hasta que su cierre completo haya terminado de ejecutar sus comandos.

Scripts Lua

El método eval proporciona otra forma de ejecutar múltiples comandos Redis en una sola operación atómica. Sin embargo, el método eval tiene la ventaja de poder interactuar y inspeccionar los valores de las claves Redis durante esa operación. Los scripts Redis están escritos en el lenguaje de programación Lua.

El método eval puede ser un poco intimidante al principio, pero exploraremos un ejemplo básico para romper el hielo. El método eval espera varios argumentos. Primero, debe pasar el script Lua (como una cadena) al método. En segundo lugar, debe pasar el número de claves (como un entero) con las que el script interactúa. En tercer lugar, debe pasar los nombres de esas claves. Finalmente, puede pasar cualquier otro argumento adicional que necesite acceder dentro de su 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 counter
LUA, 2, 'first-counter', 'second-counter');

Advertencia Consulte la documentación de Redis para obtener más información sobre la escritura de scripts en Redis.

Pipelining de Comandos

En ocasiones, puede ser necesario ejecutar docenas de comandos de Redis. En lugar de realizar un viaje de red a su servidor Redis para cada comando, puede utilizar el método pipeline. El método pipeline acepta un argumento: un cierre que recibe una instancia de Redis. Puede emitir todos sus 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 se emitieron:

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 le permiten escuchar mensajes en un "canal" dado. Puede publicar mensajes en el canal desde otra aplicación, o incluso usando otro lenguaje de programación, lo que permite una comunicación fácil entre aplicaciones y procesos.

Primero, configuremos un escucha 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 que se ejecuta durante mucho tiempo:

<?php
 
namespace App\Console\Commands;
 
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
 
class RedisSubscribe extends Command
{
/**
* El nombre y la firma del comando de consola.
*
* @var string
*/
protected $signature = 'redis:subscribe';
 
/**
* La descripción del comando de consola.
*
* @var string
*/
protected $description = 'Subscribe to a Redis channel';
 
/**
* Ejecuta el comando de consola.
*/
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 Comodines

Utilizando el método psubscribe, puede suscribirse a un canal comodín, lo que puede ser útil para capturar todos los mensajes en todos los canales. El nombre del canal se pasará como segundo argumento al cierre proporcionado:

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