Redis

Introduzione

Redis è un avanzato key-value store open source. Spesso viene definito un server di strutture dati poiché le chiavi possono contenere stringhe, hashes, liste, set e sorted sets.

Prima di usare Redis con Laravel, ti consigliamo di installare e usare l’estensione PHP PhpRedis tramite PECL. L’estensione è più complessa da installare rispetto ai pacchetti PHP normali, ma può offrire migliori prestazioni per applicazioni che fanno un uso intensivo di Redis. Se usi Laravel Sail, questa estensione è già installata nel container Docker della tua applicazione.

Se non puoi installare l’estensione PhpRedis, puoi installare il pacchetto predis/predis tramite Composer. Predis è un client Redis scritto interamente in PHP e non richiede estensioni aggiuntive:

composer require predis/predis:^2.0

Configurazione

Puoi impostare le configurazioni Redis della tua applicazione nel file config/database.php. In questo file, troverai un array redis che elenca i server Redis utilizzati dalla tua applicazione:

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

],

Ogni server Redis nell’array di configurazione deve avere un nome, un host e una porta, a meno che tu non specifichi un URL unico per la connessione 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',
    ],

],

Configurazione dello schema di connessione

Di default, i client Redis utilizzeranno lo schema tcp quando si connettono ai server Redis; tuttavia, puoi usare la crittografia TLS / SSL specificando un’opzione di configurazione scheme nell’array di configurazione del server 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'),
],

Cluster

Se la tua applicazione utilizza un cluster di server Redis, dovresti definire questi cluster all’interno della chiave clusters della configurazione di Redis. Questa chiave di configurazione non esiste di default, quindi dovrai crearla nel file di configurazione config/database.php della tua applicazione:

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

    // ...
],

Per impostazione predefinita, Laravel utilizzerà il clustering nativo di Redis poiché il valore di configurazione options.cluster è impostato su redis. Il clustering di Redis è un’ottima opzione predefinita, in quanto gestisce efficacemente il failover.

Laravel supporta anche lo sharding lato client. Tuttavia, lo sharding lato client non gestisce il failover; pertanto, è principalmente adatto per dati cache transitori che sono disponibili da un altro datastore principale.

Se desideri utilizzare lo sharding lato client anziché il clustering nativo di Redis, puoi rimuovere il valore di configurazione options.cluster nel file di configurazione config/database.php della tua applicazione:

'redis' => [

    'client' => env('REDIS_CLIENT', 'phpredis'),

    'clusters' => [
        // ...
    ],

    // ...
],

Predis

Se desideri che la tua applicazione interagisca con Redis tramite il pacchetto Predis, assicurati che il valore della variabile d’ambiente REDIS_CLIENT sia predis:

'redis' => [

    'client' => env('REDIS_CLIENT', 'predis'),

    // ...
],

Oltre alle opzioni di configurazione predefinite, Predis supporta ulteriori parametri di connessione che possono essere definiti per ciascuno dei tuoi server Redis. Per utilizzare queste opzioni di configurazione aggiuntive, aggiungile alla configurazione del tuo server Redis nel file di configurazione config/database.php della tua applicazione:

'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

Per impostazione predefinita, Laravel utilizza l’estensione PhpRedis per comunicare con Redis. Il client che Laravel utilizzerà per comunicare con Redis è determinato dal valore dell’opzione di configurazione redis.client, che solitamente riflette il valore della variabile d’ambiente REDIS_CLIENT:

    'redis' => [

        'client' => env('REDIS_CLIENT', 'phpredis'),

        // ...
    ],

Oltre alle opzioni di configurazione predefinite, PhpRedis supporta i seguenti parametri di connessione aggiuntivi: name, persistent, persistent_id, prefix, read_timeout, retry_interval, timeout e context. Puoi aggiungere una qualsiasi di queste opzioni alla configurazione del tuo server Redis nel file di configurazione 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],
        ],
    ],

Serializzazione e Compressione con PhpRedis

L’estensione PhpRedis può essere configurata per utilizzare diversi serializer e algoritmi di compressione. Questi algoritmi possono essere configurati tramite l’array options della tua configurazione 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,
    ],

    // ...
],

Attualmente i serializer supportati includono: Redis::SERIALIZER_NONE (predefinito), Redis::SERIALIZER_PHP, Redis::SERIALIZER_JSON, Redis::SERIALIZER_IGBINARY e Redis::SERIALIZER_MSGPACK.

Gli algoritmi di compressione supportati includono: Redis::COMPRESSION_NONE (predefinito), Redis::COMPRESSION_LZF, Redis::COMPRESSION_ZSTD e Redis::COMPRESSION_LZ4.

Interagire con Redis

Puoi interagire con Redis chiamando vari metodi sulla facade Redis. La facade Redis supporta metodi dinamici, il che significa che puoi chiamare qualsiasi comando Redis sulla facade e il comando verrà inviato direttamente a Redis. In questo esempio, chiameremo il comando GET di Redis utilizzando il metodo get sulla facade Redis:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Redis;
use Illuminate\View\View;

class UserController extends Controller
{
    /**
     * Mostra il profilo dell'utente specificato.
     */
    public function show(string $id): View
    {
        return view('user.profile', [
            'user' => Redis::get('user:profile:'.$id)
        ]);
    }
}

Come accennato sopra, puoi chiamare qualsiasi comando di Redis sulla facade Redis. Laravel utilizza metodi magici per inviare i comandi al server Redis. Se un comando Redis richiede argomenti, dovresti passarli al metodo corrispondente della facade:

use Illuminate\Support\Facades\Redis;

Redis::set('name', 'Taylor');

$values = Redis::lrange('names', 5, 10);

In alternativa, puoi inviare comandi al server usando il metodo command della facade Redis, che accetta il nome del comando come primo argomento e un array di valori come secondo argomento:

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

Utilizzo di Multiple Connessioni Redis

Il file di configurazione config/database.php della tua applicazione ti permette di definire più connessioni/server Redis. Puoi ottenere una connessione specifica a Redis utilizzando il metodo connection della facade Redis:

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

Per ottenere un’istanza della connessione Redis predefinita, puoi chiamare il metodo connection senza argomenti:

$redis = Redis::connection();

Transazioni

Il metodo transaction della facade Redis offre un comodo wrapper attorno ai comandi nativi MULTI ed EXEC di Redis. Il metodo transaction accetta una closure come unico argomento. Questa closure riceverà un’istanza di connessione Redis e potrà eseguire qualsiasi comando su questa istanza. Tutti i comandi Redis emessi all’interno della closure saranno eseguiti in una singola transazione atomica:

    use Redis;
    use Illuminate\Support\Facades;

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

Quando definisci una transazione Redis, non puoi recuperare alcun valore dalla connessione Redis. Ricorda, la tua transazione viene eseguita come un’unica operazione atomica e tale operazione non viene eseguita finché l’intera closure non ha terminato l’esecuzione dei suoi comandi.

Script Lua

Il metodo eval fornisce un ulteriore modo per eseguire più comandi Redis in un’unica operazione atomica. Tuttavia, il metodo eval ha il vantaggio di poter interagire e ispezionare i valori delle chiavi Redis durante tale operazione. Gli script Redis sono scritti nel linguaggio di programmazione Lua.

Il metodo eval può sembrare un po’ complicato all’inizio, ma esploreremo un esempio di base per rompere il ghiaccio. Il metodo eval si aspetta diversi argomenti. Prima, dovresti passare lo script Lua (come stringa) al metodo. In secondo luogo, devi passare il numero di chiavi (come intero) con cui lo script interagisce. In terzo luogo, devi passare i nomi di queste chiavi. Infine, puoi passare eventuali altri argomenti aggiuntivi di cui hai bisogno all’interno del tuo script.

In questo esempio, incrementeremo un contatore, ne ispezioneremo il nuovo valore e incrementeremo un secondo contatore se il valore del primo contatore è maggiore di cinque. Infine, restituiremo il valore del primo contatore:

    $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');

Consulta la documentazione di Redis per maggiori informazioni sugli script Redis.

Esecuzione in Pipeline dei Comandi

A volte potresti dover eseguire decine di comandi Redis. Invece di fare una richiesta di rete al tuo server Redis per ogni comando, puoi usare il metodo pipeline. Il metodo pipeline accetta un argomento: una closure che riceve un’istanza Redis. Puoi inviare tutti i tuoi comandi a questa istanza Redis e saranno inviati al server Redis contemporaneamente, riducendo le richieste di rete al server. I comandi verranno comunque eseguiti nell’ordine in cui sono stati inviati:

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 fornisce un’interfaccia comoda per i comandi Redis publish e subscribe. Questi comandi Redis ti permettono di ascoltare i messaggi su un determinato "canale". Puoi pubblicare messaggi sul canale da un’altra applicazione, o anche usando un altro linguaggio di programmazione, permettendo una comunicazione semplice tra applicazioni e processi.

Prima, impostiamo un ascoltatore di canale usando il metodo subscribe. Inseriremo questa chiamata al metodo all’interno di un comando Artisan poiché chiamare il metodo subscribe avvia un processo a lungo termine:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

class RedisSubscribe extends Command
{
    /**
     * Il nome e la firma del comando console.
     *
     * @var string
     */
    protected $signature = 'redis:subscribe';

    /**
     * La descrizione del comando console.
     *
     * @var string
     */
    protected $description = 'Subscribe to a Redis channel';

    /**
     * Esegui il comando console.
     */
    public function handle(): void
    {
        Redis::subscribe(['test-channel'], function (string $message) {
            echo $message;
        });
    }
}

Ora possiamo pubblicare messaggi sul canale usando il metodo publish:

use Illuminate\Support\Facades\Redis;

Route::get('/publish', function () {
    // ...

    Redis::publish('test-channel', json_encode([
        'name' => 'Adam Wathan'
    ]));
});

Subscription con Wildcard

Usando il metodo psubscribe, puoi iscriverti a un canale con caratteri jolly, utile per ricevere tutti i messaggi su tutti i canali. Il nome del canale sarà passato come secondo argomento alla closure fornita:

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

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *