工作上因為需求,必須使用 AWS Redis Key-Value Store,原本是透過 stunnel 連接 redis,因此必須修改設定。
重點:
支援叢集
使用
tls
連線
踩到的雷
laravel 若沒有額外設定,使用的是 redis client 是 phpredis
,參考 laravel 7 redis 的說明文件。
phpredis 是 php 的擴充,而 laravel 7 另外支援的 predis
是用 php 開發的套件,兩者相比主要是效能上的差異,一般情況下會優先使用 phpredis,但也要注意 phpredis 也會有版本與 php 版本之間的差別。
laravel 官方文件上寫的很陽春,所以設定上只是一再的嚐試,我們可以先透過 redis-cli 來連接 redis 服務試試看是否運作正常。
redis-cli -c -h <redis_host> -p <redis_port> --tls
# 連接成功後
AUTH <redis_password>
# 驗證成功之後
SET my_key 'Hello,Redis Cluster!'
# 寫入成功之後
GET my_key
# return Hello,Redis Cluster!
若是透過 redis-cli 運作都沒有問題,服務端就是運作正常,下一步再來設定。
撞 phpredis 的牆
依 laravel 官方說明文件使用 redis 叢集的設定
'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' => [
[
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
],
],
只要包在 clusters
的 connection 就視為 redis 叢集服務,在連線上處理就會比一般不同。
叢集的 redis 連線必需指定「叢集」模式
叢集不能額外指定 db index 統一帶 `0`
另外還要看連線的協定為何,預設為「tcp」,依情況設定為「tls」。
'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' => [
[
'scheme' => env('REDIS_PROTOCOL', 'tcp'),
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
],
],
透過設定「scheme」即可,同樣,一般的連線設定也可以透過如此設定。
但是透過如此設定仍然無法正常使用,出現 MOVE 或是連線 timeout 的異常,直接檢查「vendor/laravel/framework/src/Illuminate/Redis/Connectors/PhpRedisConnector.php」中「connectToCluster」方法帶入的設定等,還是無法解決連線上的問題。
另闢溪踁
與其一直撞南牆,換的個方式使用 larave 底層也支援的套件「Predis」。
'redis' => [
'client' => env('REDIS_CLIENT', 'predis'),
'clusters' => [
'production' => [
[
'scheme' => env('REDIS_PROTOCOL', 'tcp'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => 0,
],
],
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
'parameters' => [
'read_write_timeout' => 60,
'scheme' => env('REDIS_PROTOCOL', 'tcp'),
'password' => env('REDIS_PASSWORD', null),
],
'ssl' => [
'verify_peer' => false,
],
],
],
],
使用 Predis 後就正常使用啦!!
Phpredis 與 Predis 最大的區別還是在效能上,Phpredis 還是較優於 Predis 的,但畢竟在專案上主要也只需用於 session,主要的服務又是後台服務,api 請求也有快取,基本上也還可以,後續再來撞 Phpredis 這個南牆。
參考資料: