這次給大家帶來php使用redis長串連有哪些步驟,php使用redis長串連的注意事項有哪些,下面就是實戰案例,一起來看一下。
php-redis在github上的項目地址:https://github.com/phpredis/phpredis
pconnect函式宣告
其中time_out表示用戶端閑置多少秒後,就中斷連線。函數串連成功返回true,失敗返回false:
pconnect(host, port, time_out, persistent_id, retry_interval) host: string. can be a host, or the path to a unix domain socket port: int, optional timeout: float, value in seconds (optional, default is 0 meaning unlimited) persistent_id: string. identity for the requested persistent connection retry_interval: int, value in milliseconds (optional)
下面的例子詳細介紹了pconnect串連的重用情況。
$redis->pconnect('127.0.0.1', 6379);$redis->pconnect('127.0.0.1'); // 預設連接埠6379,跟上面的例子使用相同的串連。$redis->pconnect('127.0.0.1', 6379, 2.5); // 設定了2.5秒的到期時間。將是不同於上面的新串連$redis->pconnect('127.0.0.1', 6379, 2.5, 'x'); //設定了持久串連的id,將是不同於上面的新串連$redis->pconnect('/tmp/redis.sock'); // unix domain socket - would be another connection than the four before.
pconnect使用介紹
對pconnect方法簡單描述
使用該方法建立串連,串連不會在調用close方法之後關閉,只有在進程結束之後該串連才會被關閉。
[待驗證]如果使用的是長串連,Redis設定檔中的timeout配置項需要設定為0,否則串連池中的串連會因為逾時而失效
針對PHP-FPM來說明一下pconnect
長串連只會在PHP-FPM進程結束之後結束,串連的生命週期就是PHP-FPM進程的生命週期。
相比較短串連而言,在每一個PHP-FPM調用過程中都會產生一個redis的串連,在伺服器上的表性形式就是過多的time_out串連狀態。
而長串連相反,PHP-FPM調用的所有CGI都只會共用一個長串連,所以也就是只會產生固定數量的time_out。
關閉長串連
可以調用close和unset方法,但兩則差異很大:
- close的作用僅僅是使當前PHP進程不能再進行redis請求,但無法真正關閉redis長串連,串連在後續請求中仍然會被重用,直FPM進程生命週期結束。所以close 並不會銷毀redis對象,只是中斷連線而已。
- unset 變數才會銷毀。也需要注意並不是使用了 pconnect 就不要 close 了,如果當前指令碼執行時間很長 那麼也會一直佔用一個串連的。
如何判斷當前Redis是否處於串連狀態
等效的問題是,在單例模式中,判斷當前執行個體是否有效。
習慣上調用echo,判斷是否正常返回字串本身,或者調用ping,查看傳回值是否為 +PONG。
但是需要特別小心的是,在redis中斷連線之後,調用echo以及ping(返回'+POMG')時,均會拋出異常。所以要通過異常捕獲機制來處理。
程式碼分析pconnect串連重用的問題
情況一:非單例模式。
說明:a執行個體和b執行個體共用了一條串連,b執行個體將a執行個體的串連修改了:
所以下面的例子導致最終$a執行個體得到的值變成了2,需要特別注意。
$a = pconnect(host, port, time_out);select(3);$a -> setex(id, 3);echo $a -> get(id);//之後執行下面的串連$b = pconnect(host, port, time_out);select(2);$b->set(id,2)echo $a->get(id); //這個id操作的db變成了2,不再是之前的3了。因為這兩個串連共用了一個串連通道。
情況二:單例模式。
將上述的代碼修改,a和b都通過getInstance來產生。產生的前提是判斷當前執行個體是否存在。單例模式的混淆點在於:
$a產生了一個執行個體,這時候產生$b, $b使用了$a的執行個體,然後修改了$a的串連,之後調用$a肯定是調用的$b修改之後的執行個體。跟情況二一致。
單例模式的代碼如下:
public static function getInstance($db = 0){ if (!isset(self::$_instance)) { self::$_instance = new Redis(); } self::_connect(); self::$_instance->select($db); return self::$_instance;}
兩種情況都說明了串連重用的問題。如何修複這個bug?兩點:
1.為每一個db產生一個單例。
2.避免串連重用問題。
所以代碼可以做調整為返回一個單例數組:
public static function getInstance($db = 0){ try{ if (isset(self::$_instance[$db]) && self::$_instance[$db]->Ping() == 'Pong') { return self::$_instance[$db]; } } catch (Exception $e) { } self::$_instance[$db] = new Redis(); self::_connect($db); return self::$_instance[$db];}
需要注意的地方
避免在Task類成員變數中使用redis對象。
在redis的單例模式中,聲明了time_out的到期時間。如果redis處理的場合是一個任務,而任務調用redis間隔時間又比較長。當間隔大於time_out時候,redis就會中斷連線,這時候所有對redis的操作都會失效。解決的辦法就是避免這種調用方式,通過在調用的地方動態聲明redis類來執行。這種問題對於長串連和短連結是沒有區分,屬於調用的方式錯誤。
相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!
推薦閱讀:
php+mysql實現廣告點選統計(附代碼)
PHP中文工具類ChineseUtil怎樣轉換漢字與拼音