首頁  >  文章  >  後端開發  >  php使用redis長連線有哪些步驟

php使用redis長連線有哪些步驟

php中世界最好的语言
php中世界最好的语言原創
2018-05-18 14:47:122567瀏覽

這次帶給大家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怎麼轉換漢字與拼音

#

以上是php使用redis長連線有哪些步驟的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn