翻譯進度
44.44% 已翻譯
更新時間:
2023年2月11日 上午10:28:00 [世界標準時間]
翻譯人員:
幫我們翻譯此頁

Redis

簡介

Redis is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets, and sorted sets.

Before using Redis with Laravel, we encourage you to install and use the PhpRedis PHP extension via PECL. The extension is more complex to install compared to "user-land" PHP packages but may yield better performance for applications that make heavy use of Redis. If you are using Laravel Sail, this extension is already installed in your application's Docker container.

If you are unable to install the PhpRedis extension, you may install the predis/predis package via Composer. Predis is a Redis client written entirely in PHP and does not require any additional extensions:

1composer require predis/predis
1composer require predis/predis

設定

我們可以在 config/database.php 設定檔中設定專案的 Redis 設定。在該檔案中,可以看到一個 redis 陣列,其中存放的就是專案要使用的 Redis 伺服器:

1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'default' => [
6 'host' => env('REDIS_HOST', '127.0.0.1'),
7 'password' => env('REDIS_PASSWORD'),
8 'port' => env('REDIS_PORT', 6379),
9 'database' => env('REDIS_DB', 0),
10 ],
11 
12 'cache' => [
13 'host' => env('REDIS_HOST', '127.0.0.1'),
14 'password' => env('REDIS_PASSWORD'),
15 'port' => env('REDIS_PORT', 6379),
16 'database' => env('REDIS_CACHE_DB', 1),
17 ],
18 
19],
1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'default' => [
6 'host' => env('REDIS_HOST', '127.0.0.1'),
7 'password' => env('REDIS_PASSWORD'),
8 'port' => env('REDIS_PORT', 6379),
9 'database' => env('REDIS_DB', 0),
10 ],
11 
12 'cache' => [
13 'host' => env('REDIS_HOST', '127.0.0.1'),
14 'password' => env('REDIS_PASSWORD'),
15 'port' => env('REDIS_PORT', 6379),
16 'database' => env('REDIS_CACHE_DB', 1),
17 ],
18 
19],

除非使用單一 URL 來代表 Redis 連線,否則該設定檔中所定義的每個 Redis 伺服器都必須有名稱、主機、連接埠:

1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'default' => [
6 'url' => 'tcp://127.0.0.1:6379?database=0',
7 ],
8 
9 'cache' => [
10 'url' => 'tls://user:[email protected]:6380?database=1',
11 ],
12 
13],
1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'default' => [
6 'url' => 'tcp://127.0.0.1:6379?database=0',
7 ],
8 
9 'cache' => [
10 'url' => 'tls://user:[email protected]:6380?database=1',
11 ],
12 
13],

Configuring the Connection Scheme

預設情況下,Redis 用戶端會使用 tcp Scheme(配置) 來連線到 Redis 伺服器。不過,我們也可以在 Redis 伺服器設定陣列中指定 scheme 設定選項來使用 TLS / SSL 加密:

1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'default' => [
6 'scheme' => 'tls',
7 'host' => env('REDIS_HOST', '127.0.0.1'),
8 'password' => env('REDIS_PASSWORD'),
9 'port' => env('REDIS_PORT', 6379),
10 'database' => env('REDIS_DB', 0),
11 ],
12 
13],
1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'default' => [
6 'scheme' => 'tls',
7 'host' => env('REDIS_HOST', '127.0.0.1'),
8 'password' => env('REDIS_PASSWORD'),
9 'port' => env('REDIS_PORT', 6379),
10 'database' => env('REDIS_DB', 0),
11 ],
12 
13],

叢集

若專案使用 Redis 伺服器叢集 (Cluster),則應在 Redis 設定中的 clusters 索引鍵下定義這些叢集。預設情況下沒有該設定索引鍵,因此我們需要手動在 config/database.php 設定檔中建立該索引鍵:

1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'clusters' => [
6 'default' => [
7 [
8 'host' => env('REDIS_HOST', 'localhost'),
9 'password' => env('REDIS_PASSWORD'),
10 'port' => env('REDIS_PORT', 6379),
11 'database' => 0,
12 ],
13 ],
14 ],
15 
16],
1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'clusters' => [
6 'default' => [
7 [
8 'host' => env('REDIS_HOST', 'localhost'),
9 'password' => env('REDIS_PASSWORD'),
10 'port' => env('REDIS_PORT', 6379),
11 'database' => 0,
12 ],
13 ],
14 ],
15 
16],

預設情況下,叢集會在各個節點間做用戶端分區 (Sharding),讓我們能集區化 (Pool) 節點,並儘量取得更多可用的 RAM。不過,使用用戶端分區將無法處理 Failover(容錯移轉)。因此,這種做法主要只適合用在一些存放時間短的、快取的資料。這些資料應該要能從其他主要的資料存放空間內取得。

若想使用 Redis 原生的叢集功能,而不使用用戶端分區,則我們可以在 config/database.php 設定檔中將 options.cluster 設定值設為 redis

1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'options' => [
6 'cluster' => env('REDIS_CLUSTER', 'redis'),
7 ],
8 
9 'clusters' => [
10 // ...
11 ],
12 
13],
1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'options' => [
6 'cluster' => env('REDIS_CLUSTER', 'redis'),
7 ],
8 
9 'clusters' => [
10 // ...
11 ],
12 
13],

Predis

若專案通過 Predis 套件來使用 Redis,則請確定 REDIS_CLIENT 環境變數是否有設為 predis

1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'predis'),
4 
5 // ...
6],
1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'predis'),
4 
5 // ...
6],

除了預設的 hostportdatabasepassword 等伺服器設定選項外,Predis 還支援其他的連線參數,這些連線參數可以在每個 Redis 伺服器上定義。若要使用這些其他的設定選項,請將這些選項駕到 config/database.php 設定檔中的 Redis 伺服器設定內:

1'default' => [
2 'host' => env('REDIS_HOST', 'localhost'),
3 'password' => env('REDIS_PASSWORD'),
4 'port' => env('REDIS_PORT', 6379),
5 'database' => 0,
6 'read_write_timeout' => 60,
7],
1'default' => [
2 'host' => env('REDIS_HOST', 'localhost'),
3 'password' => env('REDIS_PASSWORD'),
4 'port' => env('REDIS_PORT', 6379),
5 'database' => 0,
6 'read_write_timeout' => 60,
7],

Redis Facade 的別名

Laravel's config/app.php configuration file contains an aliases array which defines all of the class aliases that will be registered by the framework. By default, no Redis alias is included because it would conflict with the Redis class name provided by the PhpRedis extension. If you are using the Predis client and would like to add a Redis alias, you may add it to the aliases array in your application's config/app.php configuration file:

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

PhpRedis

By default, Laravel will use the PhpRedis extension to communicate with Redis. The client that Laravel will use to communicate with Redis is dictated by the value of the redis.client configuration option, which typically reflects the value of the REDIS_CLIENT environment variable:

1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 // Rest of Redis configuration...
6],
1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 // Rest of Redis configuration...
6],

In addition to the default scheme, host, port, database, and password server configuration options, PhpRedis supports the following additional connection parameters: name, persistent, persistent_id, prefix, read_timeout, retry_interval, timeout, and context. You may add any of these options to your Redis server configuration in the config/database.php configuration file:

1'default' => [
2 'host' => env('REDIS_HOST', 'localhost'),
3 'password' => env('REDIS_PASSWORD'),
4 'port' => env('REDIS_PORT', 6379),
5 'database' => 0,
6 'read_timeout' => 60,
7 'context' => [
8 // 'auth' => ['username', 'secret'],
9 // 'stream' => ['verify_peer' => false],
10 ],
11],
1'default' => [
2 'host' => env('REDIS_HOST', 'localhost'),
3 'password' => env('REDIS_PASSWORD'),
4 'port' => env('REDIS_PORT', 6379),
5 'database' => 0,
6 'read_timeout' => 60,
7 'context' => [
8 // 'auth' => ['username', 'secret'],
9 // 'stream' => ['verify_peer' => false],
10 ],
11],

PhpRedis Serialization and Compression

The PhpRedis extension may also be configured to use a variety of serializers and compression algorithms. These algorithms can be configured via the options array of your Redis configuration:

1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'options' => [
6 'serializer' => Redis::SERIALIZER_MSGPACK,
7 'compression' => Redis::COMPRESSION_LZ4,
8 ],
9 
10 // Rest of Redis configuration...
11],
1'redis' => [
2 
3 'client' => env('REDIS_CLIENT', 'phpredis'),
4 
5 'options' => [
6 'serializer' => Redis::SERIALIZER_MSGPACK,
7 'compression' => Redis::COMPRESSION_LZ4,
8 ],
9 
10 // Rest of Redis configuration...
11],

Currently supported serializers include: Redis::SERIALIZER_NONE (default), Redis::SERIALIZER_PHP, Redis::SERIALIZER_JSON, Redis::SERIALIZER_IGBINARY, and Redis::SERIALIZER_MSGPACK.

支援的壓縮演算法包含:Redis::COMPRESSION_NONE (預設)、Redis::COMPRESSION_LZFRedis::COMPRESSION_ZSTDRedis::COMPRESSION_LZ4

使用 Redis

我們可以呼叫 Redis Facade 上的各種方法來使用 Redis。Redis Facade 支援動態方法,著表示,我們可以在該 Facade 上呼叫任何的 Redis 指令,而該指令會被直接傳到 Redis 上。在這個範例中,我們會在 Redis Facade 上呼叫 get 方法,以呼叫 Redis 的 GET 指令:

1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Http\Controllers\Controller;
6use Illuminate\Support\Facades\Redis;
7use Illuminate\View\View;
8 
9class UserController extends Controller
10{
11 /**
12 * Show the profile for the given user.
13 */
14 public function show(string $id): View
15 {
16 return view('user.profile', [
17 'user' => Redis::get('user:profile:'.$id)
18 ]);
19 }
20}
1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Http\Controllers\Controller;
6use Illuminate\Support\Facades\Redis;
7use Illuminate\View\View;
8 
9class UserController extends Controller
10{
11 /**
12 * Show the profile for the given user.
13 */
14 public function show(string $id): View
15 {
16 return view('user.profile', [
17 'user' => Redis::get('user:profile:'.$id)
18 ]);
19 }
20}

剛才也提到過,我們可以在 Redis Facade 上呼叫任何的 Redis 指令。Laravel 會使用 Magic Method 來將這些指令傳給 Redis 伺服器。若是有要求引數的 Redis 指令,則我們可以將引數傳給 Facade 上對應的方法:

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

或者,我們也可以使用 Redis Facade 的 command 方法來將指令傳給 Redis 伺服器。command 方法的第一個引數是指令名稱,而第二個引數則是一個陣列:

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

使用多個 Redis 連線

在專案的 config/database.php 設定檔中,我們可以定義多個 Redis 連線/伺服器。我們可以使用 Redis Facade 上的 connection 方法來取得一個特定的 Redis 連線:

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

若要取得預設的 Redis 連線,可直接呼叫 connection 方法而不帶任何引數:

1$redis = Redis::connection();
1$redis = Redis::connection();

Transaction

Redis Facade 的 transaction 方法提供了一個 Redis 原生 MULTIEXEC 指令的方便包裝。transaction 方法只有一個引數,該引數為一個閉包。傳入的閉包會收到一個 Redis 連線實體,並可在該實體上下任何指令。在該閉包中所下的所有指令,都會被放在單一、不可部分完成 (Atomic) 的 Transaction 內執行:

1use Redis;
2use Illuminate\Support\Facades;
3 
4Facades\Redis::transaction(function (Redis $redis) {
5 $redis->incr('user_visits', 1);
6 $redis->incr('total_visits', 1);
7});
1use Redis;
2use Illuminate\Support\Facades;
3 
4Facades\Redis::transaction(function (Redis $redis) {
5 $redis->incr('user_visits', 1);
6 $redis->incr('total_visits', 1);
7});
lightbulb

定義 Redis Transaction 時,無法從 Redis 連線中取值。請記得,Transaction 是以單一、不可部分完成的動作來執行的,因此這些動作會在整個閉包內的指令都執行完畢後才被執行。

Lua Script

eval 方法提供了另一種以單一、不可部分完成動作執行多個 Redis 指令的方法。不過,使用 eval 方法還有個好處,就是能在動作的期間處理與偵測 Redis 的索引鍵值。Redis Script 使用 Lua 程式語言撰寫。

雖然,一開始,eval 方法可能有點可怕。不過我們會先來看看一個簡單的例子。eval 方法接受多個引數。首先,我們需要先 (以字串形式) 傳入 Lua Script 給該方法。然後。我們需要將該 Script 要處理的索引鍵數量 (以整數形式) 傳入。再來,我們需要傳入這些索引鍵的名稱。最後,我們可以傳入在該 Script 中需要存取的其他引數。

在這個範例中,我們會遞增一個計數器,並取得該計數器的值,判斷該值是否大於 5。如果大於 5,就再遞增另一個計數器。最後,回傳第一個計數器的值:

1$value = Redis::eval(<<<'LUA'
2 local counter = redis.call("incr", KEYS[1])
3 
4 if counter > 5 then
5 redis.call("incr", KEYS[2])
6 end
7 
8 return counter
9LUA, 2, 'first-counter', 'second-counter');
1$value = Redis::eval(<<<'LUA'
2 local counter = redis.call("incr", KEYS[1])
3 
4 if counter > 5 then
5 redis.call("incr", KEYS[2])
6 end
7 
8 return counter
9LUA, 2, 'first-counter', 'second-counter');
lightbulb

有關更多在 Redis 上撰寫 Script 的資訊,請參考 Redis 的說明文件

指令管道

有時候,我們會需要執行多個 Redis 指令。除了個別以網路連線將每個指令傳給 Redis,我們還可以使用 pipeline 方法。pipeline 方法只有一個引數:一個接收 Redis 實體的閉包。我們可以使用這個 Redis 實體來下指令,下的所有指令會被一次性地傳送給 Redis 伺服器,以減少網路使用。指令會依照所下的順序執行:

1use Redis;
2use Illuminate\Support\Facades;
3 
4Facades\Redis::pipeline(function (Redis $pipe) {
5 for ($i = 0; $i < 1000; $i++) {
6 $pipe->set("key:$i", $i);
7 }
8});
1use Redis;
2use Illuminate\Support\Facades;
3 
4Facades\Redis::pipeline(function (Redis $pipe) {
5 for ($i = 0; $i < 1000; $i++) {
6 $pipe->set("key:$i", $i);
7 }
8});

Pub / Sub

Laravel 中為 Redis 的 publishsubscribe 指令提供了一個方便的介面。使用這兩個 Redis 指令,我們就能在給定的「頻道 (Channel)」上監聽訊息。接著,我們可以在另一個專案內、甚至使用另一個程式語言來 Publish(發佈) 訊息。這樣一來我們就能輕鬆地在不同專案或處理程序間進行溝通。

首先,我們先使用 subscribe 方法來建立一個頻道的 Listener(監聽程式)。我們將這個指令放在一個 Artisan 指令內呼叫。因為,呼叫 `subscribe`(訂閱) 方法就代表要開啟一個執行時間較長的處理程序:

1<?php
2 
3namespace App\Console\Commands;
4 
5use Illuminate\Console\Command;
6use Illuminate\Support\Facades\Redis;
7 
8class RedisSubscribe extends Command
9{
10 /**
11 * The name and signature of the console command.
12 *
13 * @var string
14 */
15 protected $signature = 'redis:subscribe';
16 
17 /**
18 * The console command description.
19 *
20 * @var string
21 */
22 protected $description = 'Subscribe to a Redis channel';
23 
24 /**
25 * Execute the console command.
26 */
27 public function handle(): void
28 {
29 Redis::subscribe(['test-channel'], function (string $message) {
30 echo $message;
31 });
32 }
33}
1<?php
2 
3namespace App\Console\Commands;
4 
5use Illuminate\Console\Command;
6use Illuminate\Support\Facades\Redis;
7 
8class RedisSubscribe extends Command
9{
10 /**
11 * The name and signature of the console command.
12 *
13 * @var string
14 */
15 protected $signature = 'redis:subscribe';
16 
17 /**
18 * The console command description.
19 *
20 * @var string
21 */
22 protected $description = 'Subscribe to a Redis channel';
23 
24 /**
25 * Execute the console command.
26 */
27 public function handle(): void
28 {
29 Redis::subscribe(['test-channel'], function (string $message) {
30 echo $message;
31 });
32 }
33}

接著,我們就能使用 publish 方法來將訊息發佈到頻道上:

1use Illuminate\Support\Facades\Redis;
2 
3Route::get('/publish', function () {
4 // ...
5 
6 Redis::publish('test-channel', json_encode([
7 'name' => 'Adam Wathan'
8 ]));
9});
1use Illuminate\Support\Facades\Redis;
2 
3Route::get('/publish', function () {
4 // ...
5 
6 Redis::publish('test-channel', json_encode([
7 'name' => 'Adam Wathan'
8 ]));
9});

使用萬用字元來 Subscribe

使用 psubscribe 方法,我們就能以萬用字元來 Subscribe 頻道。若要從所有頻道中取得所有的訊息,就適合使用這個方法。頻道名稱會以第二個引數傳給所提供的閉包:

1Redis::psubscribe(['*'], function (string $message, string $channel) {
2 echo $message;
3});
4 
5Redis::psubscribe(['users.*'], function (string $message, string $channel) {
6 echo $message;
7});
1Redis::psubscribe(['*'], function (string $message, string $channel) {
2 echo $message;
3});
4 
5Redis::psubscribe(['users.*'], function (string $message, string $channel) {
6 echo $message;
7});
翻譯進度
44.44% 已翻譯
更新時間:
2023年2月11日 上午10:28:00 [世界標準時間]
翻譯人員:
幫我們翻譯此頁

留言

尚無留言

“Laravel” is a Trademark of Taylor Otwell.
The source documentation is released under MIT license. See laravel/docs on GitHub for details.
The translated documentations are released under MIT license. See cornch/laravel-docs-l10n on GitHub for details.