redis連接

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配置爲

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">pm<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.max</span>_children = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>
pm<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.start</span>_servers = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>
pm<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.max</span>_spare_servers = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

這樣,我們的頁面請求會由一個確定的fpm進程執行,方便strace跟蹤。

對應頁面請求的php代碼:

<code class="language-php hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ip</span> = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"10.136.30.144"</span>; 
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$port</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7777</span>; 
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Redis();

<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span>->pconnect(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ip</span>, <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$port</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$key</span> = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"test"</span>;
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$value</span> = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"this is test"</span>;

<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span>->set(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$key</span>, <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$value</span>);
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$d</span> = <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span>->get(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$key</span>);
var_dump(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$d</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

代碼的功能很簡單,連接redis,先設置一個值,再取出。

測試問題1

思路: 
使用strace觀察fpm的系統調用,如果連接的生命週期是一次php執行,那麼每次頁面調用,都會有connect系統調用,用以連接redis;如果連接的生命週期是fpm的終結,那麼只有第一次頁面調用會有connect系統調用 ,之後由於連接被重用,無需connect,直接發命令請求即可。

啓動一個新的fpm(進程號28082)。 
執行

<code class="language-shell hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">strace <span class="hljs-attribute" style="box-sizing: border-box;">-p</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">28082</span> <span class="hljs-attribute" style="box-sizing: border-box;">-s</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span> <span class="hljs-attribute" style="box-sizing: border-box;">-o</span> redis_1</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

記錄一次頁面請求的系統調用。如下圖所示: 
這裏寫圖片描述
可以看到進程先建立了socket連接(文件描述符爲9)。然後給reids發一系列命令,最終取到“this is test”的結果串。且沒有關閉連接相關的redis命令或系統調用。

頁面請求結束後,我們執行

<code class="language-shell hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">lsof <span class="hljs-attribute" style="box-sizing: border-box;">-n</span> <span class="hljs-attribute" style="box-sizing: border-box;">-p</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">28082</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

這裏寫圖片描述
可以看到,fpm進程仍然保有一個到10.136.30.144的reids連接,其文件描述符爲9(這與strace的結果一致)。

執行

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">strace <span class="hljs-attribute" style="box-sizing: border-box;">-p</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">28082</span> <span class="hljs-attribute" style="box-sizing: border-box;">-s</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span> <span class="hljs-attribute" style="box-sizing: border-box;">-o</span> redis_2</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

記錄 第二次頁面請求的系統調用,得到下面結果。 
這裏寫圖片描述
與第一次請求的區別是:省去了建立連接的過程,直接發送reids命令,得到結果! 
再使用lsof -n -p 28082查看fpm打開的文件描述符,結果與上文件相同。 
說明,連接的確是被重用的,沒有新建。

執行第6次頁面請求(因爲我們在準備工作中的配置,此時fpm已經是一個新的進程了),用lsof查看進程打開的文件描述符。 
這裏寫圖片描述
我們發現,雖然仍然有描述符爲9的reids連接,但兩個tcp連接的臨時端口不同了,也就是連接改變了!

至此,我們得出問題1的結論: 
當使用pconnect時,連接會被重用,連接的生命週期是fpm進程的生命週期,而非一次php的執行。

測試問題2

爲了對比,我們先看一下,使用connect連接redis,並調用redis->close()的系統調用。(將上述代碼中的pconnect改爲connect, 同時在最後加入redis->close()) 
這裏寫圖片描述
我們看到,除了建立連接外,在程序結尾,還向reids發送了quit命令,並關閉了連接的文件描述符。

接下來,我們看在使用pconnect後,redis->close()有何表現 
代碼調整爲:

<code class="language-php hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ip</span> = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"10.136.30.144"</span>;
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$port</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7777</span>;
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Redis();
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span>->pconnect(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ip</span>, <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$port</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$key</span> = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"test"</span>;
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$value</span> = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"this is test"</span>;
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span>->set(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$key</span>, <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$value</span>);
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$d</span> = <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span>->get(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$key</span>);
var_dump(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$d</span>);
<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span>->close();

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>{
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$redis</span>->get(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$key</span>);
} 
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Exception</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$e</span>){
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">echo</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$e</span>->getMessage();
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>

我們直接看第2次執行頁面請求的系統調用這裏寫圖片描述
並沒有建立連接,同樣是直接發送命令得到結果。說明連接被重用。同時,沒有向reids server發送quit命令,也無關閉連接的系統調用。 
但注意,頁面請求的返回結果: 
這裏寫圖片描述 
至此,我們得出問題2的結論: 
如果代碼中使用pconnect, close的作用僅是使當前php不能再進行redis請求,但無法真正關閉redis長連接,連接在後續請求中仍然會被重用,直至fpm進程生命週期結束。

結論

1. 當使用pconnect時,連接會被重用,連接的生命週期是fpm進程的生命週期,而非一次php的執行。 
2.如果代碼中使用pconnect, close的作用僅是使當前php不能再進行redis請求,但無法真正關閉redis長連接,連接在後續請求中仍然會被重用,直至fpm進程生命週期結束。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章