pconnect, phpredis中用於client連接server的api。
The connection will not be closed on close or end of request until the php process ends.
這是api說明中的一句原文
那麼問題來了:
1. php process ends是指一次php執行完結,還是fpm的終結?如果是後者,那意味著即使一次php執行完畢,redis連接也不會被釋放,下一次執行時redis連接會被重用。
2. The connection will not be closed on close是 說如果使用了pconnect, 即使在代碼中顯示的調用close(), 也不會關閉連接?
帶著這兩個問題,我們做下實驗,深入看一下pconnect究竟做了些什麼。
環境:
nginx + fpm
php5.3
我們將fpm配置為
pm.max_children = 1
pm.start_servers = 1
pm.max_spare_servers = 1
這樣,我們的頁面請求會由一個確定的fpm進程執行,方便strace跟蹤。
對應頁面請求的php代碼:
$ip = 10.136.30.144;
$port = 7777;
$redis = new Redis();
$redis->pconnect($ip, $port, 1);
$key = test;
$value = this is test;
$redis->set($key, $value);
$d = $redis->get($key);
var_dump($d);
代碼的功能很簡單,連接redis,先設置一個值,再取出。
思路:
使用strace觀察fpm的系統調用,如果連接的生命周期是一次php執行,那麼每次頁面調用,都會有connect系統調用,用以連接redis;如果連接的生命周期是fpm的終結,那麼只有第一次頁面調用會有connect系統調用 ,之後由於連接被重用,無需connect,直接發命令請求即可。
啟動一個新的fpm(進程號28082)。
執行
strace -p 28082 -s 1024 -o redis_1
記錄一次頁面請求的系統調用。如下圖所示:
可以看到進程先建立了socket連接(文件描述符為9)。然後給reids發一系列命令,最終取到“this is test”的結果串。且沒有關閉連接相關的redis命令或系統調用。<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPtKzw+bH68fzveHK+Lrzo6zO0sPH1rTQ0DwvcD4NCjxwcmUgY2xhc3M9"brush:java;">
lsof -n -p 28082
可以看到,fpm進程仍然保有一個到10.136.30.144的reids連接,其文件描述符為9(這與strace的結果一致)。
執行
strace -p 28082 -s 1024 -o redis_2
記錄 第二次頁面請求的系統調用,得到下面結果。
與第一次請求的區別是:省去了建立連接的過程,直接發送reids命令,得到結果!
再使用lsof -n -p 28082查看fpm打開的文件描述符,結果與上文件相同。
說明,連接的確是被重用的,沒有新建。
執行第6次頁面請求(因為我們在准備工作中的配置,此時fpm已經是一個新的進程了),用lsof查看進程打開的文件描述符。
我們發現,雖然仍然有描述符為9的reids連接,但兩個tcp連接的臨時端口不同了,也就是連接改變了!
至此,我們得出問題1的結論:
當使用pconnect時,連接會被重用,連接的生命周期是fpm進程的生命周期,而非一次php的執行。。
為了對比,我們先看一下,使用connect連接redis,並調用redis->close()的系統調用。(將上述代碼中的pconnect改為connect, 同時在最後加入redis->close())
我們看到,除了建立連接外,在程序結尾,還向reids發送了quit命令,並關閉了連接的文件描述符。
接下來,我們看在使用pconnect後,redis->close()有何表餡喎?http://www.Bkjia.com/kf/yidong/wp/" target="_blank" class="keylink">WPGJyIC8+DQq0+sLrtffV+86qo7o8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;">
$ip = 10.136.30.144;
$port = 7777;
$redis = new Redis();
$redis->pconnect($ip, $port, 1);
$key = test;
$value = this is test;
$redis->set($key, $value);
$d = $redis->get($key);
var_dump($d);
$redis->close();
try{
$redis->get($key);
}
catch (Exception $e){
echo $e->getMessage();
}
我們直接看第2次執行頁面請求的系統調用
並沒有建立連接,同樣是直接發送命令得到結果。說明連接被重用。同時,沒有向reids server發送quit命令,也無關閉連接的系統調用。
但注意,頁面請求的返回結果:
至此,我們得出問題2的結論:
如果代碼中使用pconnect, close的作用僅是使當前php不能再進行redis請求,但無法真正關閉redis長連接,連接在後續請求中仍然會被重用,直至fpm進程生命周期結束。
1. 當使用pconnect時,連接會被重用,連接的生命周期是fpm進程的生命周期,而非一次php的執行。
2.如果代碼中使用pconnect, close的作用僅是使當前php不能再進行redis請求,但無法真正關閉redis長連接,連接在後續請求中仍然會被重用,直至fpm進程生命周期結束。