Giới thiệu

Redis là một dự án mã nguồn mở, dùng để lưu trữ các giá trị key-value. Nó thường được coi như là một server cấu trúc dữ liệu vì các key của nó có thể lưu strings, hashes, lists, sets, và sorted sets.

Trước khi sử dụng Redis cho Laravel, chúng tôi khuyến khích bạn cài đặt và sử dụng extension PhpRedis của PHP thông qua PECL. Extension này sẽ phức tạp hơn về mặt cài đặt so với các package PHP "user-land" nhưng có thể mang lại hiệu suất tốt hơn cho các ứng dụng mà sử dụng nhiều Redis. Nếu bạn đang sử dụng Laravel Sail, thì extension này đã được cài đặt sẵn trong Docker container của ứng dụng của bạn.

Nếu bạn không thể cài đặt extension PhpRedis, bạn có thể cài đặt package predis/predis thông qua Composer. Predis là một client Redis được viết hoàn toàn bằng PHP và nó không yêu cầu cài thêm bất kỳ extension nào:

composer require predis/predis

Cấu hình

Bạn có thể cấu hình cài đặt Redis của ứng dụng thông qua file cấu hình config/database.php. Trong file này, bạn sẽ thấy một mảng redis chứa các server Redis được application của bạn sử dụng:

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

],

Mỗi một server Redis được định nghĩa trong file cấu hình của bạn yêu cầu phải có tên, host và một cổng trừ khi bạn định nghĩa một URL để đại diện cho kết nối 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',
    ],

],

Configuring The Connection Scheme

Mặc định, các Redis client sẽ sử dụng scheme tcp khi kết nối với Redis server của bạn; tuy nhiên, bạn có thể sử dụng mã hóa TLS / SSL bằng cách chỉ định một tùy chọn cấu hình scheme trong mảng cấu hình của Redis server của bạn:

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

Cụm

Nếu application của bạn đang sử dụng một cụm server Redis, bạn nên định nghĩa các cụm này bằng một key là clusters trong file cấu hình Redis của bạn. Mặc định, khóa cấu hình này không tồn tại, do đó bạn sẽ cần tạo nó trong file cấu hình config/database.php của ứng dụng:

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

    // ...
],

Mặc định, Laravel sẽ sử dụng native Redis clustering vì giá trị cấu hình options.cluster được set thành redis. Redis clustering là một tùy chọn mặc định tuyệt vời, bởi vì nó xử lý failover một cách linh hoạt.

Laravel cũng hỗ trợ client-side sharding khi sử dụng Predis. Tuy nhiên, client-side sharding không xử lý được khi bị thất bại; do đó, nó chủ yếu phù hợp cho việc cache tạm thời các dữ liệu mà có sẵn từ một primary data store khác.

Nếu bạn muốn sử dụng client-side sharding thay vì native Redis clustering, bạn có thể xoá giá trị cấu hình options.cluster trong file cấu hình config/database.php của ứng dụng của bạn:

'redis' => [

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

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

    // ...
],

Predis

Nếu bạn muốn ứng dụng của bạn tương tác với Redis thông qua package Predis, bạn nên set giá trị của biến môi trường REDIS_CLIENTpredis:

'redis' => [

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

    // ...
],

Ngoài các tùy chọn cấu hình mặc định, Predis còn hỗ trợ thêm các tham số kết nối có thể định nghĩa cho mỗi server Redis của bạn. Để sử dụng thêm các tùy chọn cấu hình này, hãy thêm chúng vào cấu hình server Redis của bạn trong file cấu hình config/database.php của application của bạ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

Mặc định, Laravel sẽ sử dụng extension PhpRedis để giao tiếp với Redis. Client mà Laravel sẽ sử dụng để giao tiếp với Redis được quyết định bởi giá trị của tùy chọn cấu hình redis.client, thường phản ánh bởi giá trị của biến môi trường REDIS_CLIENT:

'redis' => [

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

    // ...
],

Ngoài các tùy chọn cấu hình mặc định, PhpRedis cũng hỗ trợ thêm các tham số kết nối bổ sung như sau: name, persistent, persistent_id, prefix, read_timeout, retry_interval, max_retries, backoff_algorithm, backoff_base, backoff_cap, timeout, và context. Bạn có thể thêm bất kỳ tùy chọn nào vào cấu hình server Redis của bạn trong file cấu hình 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],
    ],
],

Retry and Backoff Configuration

Các tùy chọn retry_interval, max_retries, backoff_algorithm, backoff_base, và backoff_cap có thể được sử dụng để cấu hình PhpRedis client sẽ thử kết nối lại với máy chủ Redis. Các thuật toán backoff sau đây được hỗ trợ: default, decorrelated_jitter, equal_jitter, exponential, uniform, và constant:

'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'),
    'max_retries' => env('REDIS_MAX_RETRIES', 3),
    'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'),
    'backoff_base' => env('REDIS_BACKOFF_BASE', 100),
    'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000),
],

Predis 3.4.0 và các phiên bản mới hơn sẽ hỗ trợ cấu hình retry và backoff được tích hợp sẵn thông qua class Retry. Bạn hãy cấu hình nó bằng cách sử dụng tùy chọn retry với một trong các chiến lược sau: NoBackoff, EqualBackoff, hoặc ExponentialBackoff:

use Predis\Retry;
use Predis\Retry\Strategy\ExponentialBackoff;

'default' => [
    'url' => env('REDIS_URL'),
    // ...
    'retry' => new Retry(
        new ExponentialBackoff(
            env('REDIS_BACKOFF_BASE', 100),
            env('REDIS_BACKOFF_CAP', 1000),
            true, // Enables jitter
        ),
        env('REDIS_MAX_RETRIES', 3)
    )
],

Unix Socket Connections

Các kết nối Redis cũng có thể được cấu hình để sử dụng Unix socket thay vì TCP. Điều này có thể mang lại hiệu suất tốt hơn bằng cách loại bỏ dữ liệu TCP dư thừa cho các kết nối tới các instance Redis trên cùng một server với ứng dụng của bạn. Để cấu hình Redis sử dụng Unix socket, hãy set biến môi trường REDIS_HOST thành đường dẫn của Redis socket và biến môi trường REDIS_PORT thành 0:

REDIS_HOST=/run/redis/redis.sock
REDIS_PORT=0

PhpRedis Serialization và Compression

Extension PhpRedis cũng có thể được cấu hình để sử dụng nhiều thuật toán nén và serializers khác nhau. Các thuật toán này có thể được cấu hình thông qua mảng options trong cấu hình Redis của bạn:

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

    // ...
],

Các serializers được hỗ trợ hiện tại là: Redis::SERIALIZER_NONE (mặc định), Redis::SERIALIZER_PHP, Redis::SERIALIZER_JSON, Redis::SERIALIZER_IGBINARYRedis::SERIALIZER_MSGPACK.

Các thuật toán nén được hỗ trợ là: Redis::COMPRESSION_NONE (mặc định), Redis::COMPRESSION_LZF, Redis::COMPRESSION_ZSTDRedis::COMPRESSION_LZ4.

Tương tác với Redis

Bạn có thể tương tác với Redis bằng cách gọi các phương thức khác nhau trên facade Redis. Facade Redis hỗ trợ các phương thức động, nghĩa là bạn có thể gọi bất kỳ lệnh Redis nào trên facade và lệnh đó sẽ được chuyển trực tiếp đến Redis để thực hiện. Trong ví dụ này, chúng ta sẽ gọi lệnh Redis GET bằng cách gọi phương thức get trên facade Redis:

<?php

namespace App\Http\Controllers;

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)
        ]);
    }
}

Như đã đề cập ở trên, bạn có thể gọi bất kỳ lệnh Redis nào trên facade Redis. Laravel sẽ sử dụng các phương thức magic để truyền các lệnh đó đến server Redis. Nếu lệnh Redis yêu cầu các tham số, bạn cũng có thể truyền chúng sang phương thức tương ứng của facade:

use Illuminate\Support\Facades\Redis;

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

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

Ngoài ra, bạn có thể truyền lệnh đến server Redis bằng phương thức command của facade Redis, chấp nhận tên của lệnh làm tham số đầu tiên và một mảng các giá trị làm tham số thứ hai:

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

Using Multiple Redis Connections

File cấu hình config/database.php của ứng dụng của bạn cho phép bạn định nghĩa nhiều kết nối máy chủ Redis. Bạn có thể nhận được kết nối đến một kết nối Redis cụ thể bằng cách sử dụng phương thức connection của facade Redis:

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

Để có được một instance của kết nối Redis mặc định, bạn có thể gọi phương thức connection mà không cần thêm bất kỳ tham số nào:

$redis = Redis::connection();

Transactions

Phương thức transaction của facade Redis cung cấp một wrapper thuận tiện xung quanh các lệnh MULTIEXEC gốc của Redis. Phương thức transaction chấp nhận một closure làm tham số duy nhất của nó. Closure này sẽ nhận vào một instance kết nối Redis và bạn có thể đưa vào bất kỳ lệnh nào mà bạn muốn cho instance này. Tất cả các lệnh Redis được đưa vào trong closure sẽ được thực thi trong một transaction nguyên tử duy nhất:

use Redis;
use Illuminate\Support\Facades;

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

[!WARNING] Khi định nghĩa một transaction Redis, bạn không được lấy bất kỳ giá trị nào từ kết nối Redis. Hãy nhớ rằng, transaction của bạn được thực thi dưới dạng một thao tác duy nhất và thao tác đó không được thực thi cho đến khi toàn bộ closure của bạn thực thi xong các lệnh của nó.

Lua Scripts

Phương thức eval sẽ cung cấp một phương thức khác để thực thi nhiều lệnh Redis trong một thao tác duy nhất. Tuy nhiên, phương thức eval có lợi ích là có thể tương tác và kiểm tra các giá trị khóa của Redis trong quá trình hoạt động đó. Script lệnh Redis được viết bằng ngôn ngữ lập trình Lua.

Phương thức eval lúc đầu có thể hơi đáng sợ, nhưng chúng ta sẽ xem một ví dụ cơ bản để hiểu thêm về nó. Phương thức eval yêu cầu một số tham số. Trước tiên, bạn nên truyền script Lua (dưới dạng chuỗi) cho phương thức. Thứ hai, bạn nên truyền số lượng khóa (dưới dạng integer) mà script tương tác. Thứ ba, bạn nên truyền tên của các khoá đó. Cuối cùng, bạn có thể truyền thêm bất kỳ tham số nào khác mà bạn cần truy cập trong script của bạn.

Trong ví dụ này, chúng ta sẽ tăng counter, kiểm tra giá trị mới của nó và tăng counter thứ hai nếu giá trị của counter thứ nhất lớn hơn năm. Cuối cùng, chúng ta sẽ trả về giá trị của counter đầu tiên:

$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] Vui lòng tham khảo tài liệu về Redis để biết thêm thông tin về script Redis.

Lệnh Pipeline

Thỉnh thoảng bạn có thể cần thực thi nhiều lệnh Redis. Thay vì thực hiện truy vấn tới server Redis của bạn cho từng lệnh một, bạn có thể sử dụng phương thức pipeline. Phương thức pipeline chấp nhận một tham số là: một closure nhận vào một instance Redis. Bạn có thể đưa vào tất cả các lệnh của bạn cho instance Redis này và tất cả chúng sẽ được truyền trực tiếp đến server đồng thời để giảm các lượt truy vấn đến server. Các lệnh vẫn sẽ được thực thi theo thứ tự chúng được ghi:

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 cung cấp một interface thuận tiện cho các lệnh publishsubscribe của Redis. Các lệnh Redis này cho phép bạn listen các tin nhắn trên một "channel" nhất định. Bạn có thể publish tin nhắn lên channel từ một application khác hoặc thậm chí sử dụng một ngôn ngữ lập trình khác, cho phép giao tiếp dễ dàng giữa các application và process.

Đầu tiên, hãy thiết lập một listen channel bằng phương thức subscribe. Chúng ta sẽ thực hiện gọi phương thức này trong một lệnh Artisan vì khi gọi phương thức subscribe là sẽ bắt đầu chạy một process lâu dài:

<?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;
        });
    }
}

Bây giờ chúng ta có thể publish tin nhắn lên channel bằng phương thức publish:

use Illuminate\Support\Facades\Redis;

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

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

Wildcard Subscriptions

Sử dụng phương thức psubscribe, bạn có thể theo dõi một nhóm các channel, nó có thể hữu ích để lấy tất cả các tin nhắn trên tất cả các channel. Tên channel sẽ được truyền làm tham số thứ hai cho closure:

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

Redis::psubscribe(['users.*'], function (string $message, string $channel) {
    echo $message;
});
Seeding MongoDB
© 2023 by Logo page doc-vn