本人轉(zhuǎn)自?https://blog.csdn.net/qmhball/article/details/46988111
版權(quán)歸原作者所有
pconnect, phpredis中用于client連接server的api。
The connection will not be closed on close or end of request until the php process ends.?
這是api說(shuō)明中的一句原文
那么問(wèn)題來(lái)了:
1.?php process ends是指一次php執(zhí)行完結(jié),還是fpm的終結(jié)?如果是后者,那意味著即使一次php執(zhí)行完畢,redis連接也不會(huì)被釋放,下一次執(zhí)行時(shí)redis連接會(huì)被重用。?
2.?The connection will not be closed on close是 說(shuō)如果使用了pconnect, 即使在代碼中顯示的調(diào)用close(), 也不會(huì)關(guān)閉連接?
帶著這兩個(gè)問(wèn)題,我們做下實(shí)驗(yàn),深入看一下pconnect究竟做了些什么。
準(zhǔn)備工作
環(huán)境:
nginx + fpm?
php5.3?
我們將fpm配置為
pm.max_children = 1?pm.start_servers = 1?pm.max_spare_servers = 1
這樣,我們的頁(yè)面請(qǐng)求會(huì)由一個(gè)確定的fpm進(jìn)程執(zhí)行,方便strace跟蹤。
對(duì)應(yīng)頁(yè)面請(qǐng)求的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);
代碼的功能很簡(jiǎn)單,連接redis,先設(shè)置一個(gè)值,再取出。
測(cè)試問(wèn)題1
思路:?
使用strace觀察fpm的系統(tǒng)調(diào)用,如果連接的生命周期是一次php執(zhí)行,那么每次頁(yè)面調(diào)用,都會(huì)有connect系統(tǒng)調(diào)用,用以連接redis;如果連接的生命周期是fpm的終結(jié),那么只有第一次頁(yè)面調(diào)用會(huì)有connect系統(tǒng)調(diào)用 ,之后由于連接被重用,無(wú)需connect,直接發(fā)命令請(qǐng)求即可。
啟動(dòng)一個(gè)新的fpm(進(jìn)程號(hào)28082)。
執(zhí)行
strace -p 28082?-s 1024?-o redis_1
[if !supportLists]·?[endif]1
記錄一次頁(yè)面請(qǐng)求的系統(tǒng)調(diào)用。如下圖所示:

可以看到進(jìn)程先建立了socket連接(文件描述符為9)。然后給reids發(fā)一系列命令,最終取到“this is test”的結(jié)果串。且沒(méi)有關(guān)閉連接相關(guān)的redis命令或系統(tǒng)調(diào)用。
頁(yè)面請(qǐng)求結(jié)束后,我們執(zhí)行
lsof -n -p 28082

可以看到,fpm進(jìn)程仍然保有一個(gè)到10.136.30.144的reids連接,其文件描述符為9(這與strace的結(jié)果一致)。
執(zhí)行
strace -p 28082?-s 1024?-o redis_2
[if !supportLists]·?[endif]1
記錄第二次頁(yè)面請(qǐng)求的系統(tǒng)調(diào)用,得到下面結(jié)果。

與第一次請(qǐng)求的區(qū)別是:省去了建立連接的過(guò)程,直接發(fā)送reids命令,得到結(jié)果!
再使用lsof -n -p 28082查看fpm打開(kāi)的文件描述符,結(jié)果與上文件相同。
說(shuō)明,連接的確是被重用的,沒(méi)有新建。
執(zhí)行第6次頁(yè)面請(qǐng)求(因?yàn)槲覀冊(cè)跍?zhǔn)備工作中的配置,此時(shí)fpm已經(jīng)是一個(gè)新的進(jìn)程了),用lsof查看進(jìn)程打開(kāi)的文件描述符。

我們發(fā)現(xiàn),雖然仍然有描述符為9的reids連接,但兩個(gè)tcp連接的臨時(shí)端口不同了,也就是連接改變了!
至此,我們得出問(wèn)題1的結(jié)論:
當(dāng)使用pconnect時(shí),連接會(huì)被重用,連接的生命周期是fpm進(jìn)程的生命周期,而非一次php的執(zhí)行。。
測(cè)試問(wèn)題2
為了對(duì)比,我們先看一下,使用connect連接redis,并調(diào)用redis->close()的系統(tǒng)調(diào)用。(將上述代碼中的pconnect改為connect, 同時(shí)在最后加入redis->close())

我們看到,除了建立連接外,在程序結(jié)尾,還向reids發(fā)送了quit命令,并關(guān)閉了連接的文件描述符。
接下來(lái),我們看在使用pconnect后,redis->close()有何表現(xiàn)
代碼調(diào)整為:
$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(); }
[if !supportLists]·?[endif]
我們直接看第2次執(zhí)行頁(yè)面請(qǐng)求的系統(tǒng)調(diào)用

并沒(méi)有建立連接,同樣是直接發(fā)送命令得到結(jié)果。說(shuō)明連接被重用。同時(shí),沒(méi)有向reids server發(fā)送quit命令,也無(wú)關(guān)閉連接的系統(tǒng)調(diào)用。
但注意,頁(yè)面請(qǐng)求的返回結(jié)果:

至此,我們得出問(wèn)題2的結(jié)論:
如果代碼中使用pconnect, close的作用僅是使當(dāng)前php不能再進(jìn)行redis請(qǐng)求,但無(wú)法真正關(guān)閉redis長(zhǎng)連接,連接在后續(xù)請(qǐng)求中仍然會(huì)被重用,直至fpm進(jìn)程生命周期結(jié)束。
結(jié)論
1. 當(dāng)使用pconnect時(shí),連接會(huì)被重用,連接的生命周期是fpm進(jìn)程的生命周期,而非一次php的執(zhí)行。?
2.如果代碼中使用pconnect, close的作用僅是使當(dāng)前php不能再進(jìn)行redis請(qǐng)求,但無(wú)法真正關(guān)閉redis長(zhǎng)連接,連接在后續(xù)請(qǐng)求中仍然會(huì)被重用,直至fpm進(jìn)程生命周期結(jié)束。