利用PHP長連接提高性能
問題介紹
最近有 PHP 用戶反饋對云數(shù)據(jù)庫 Memcache 版做性能測試的結(jié)果,達不到預(yù)期的性能指標。通過了解具體情況,大多數(shù)用戶在使用 PHP 連接云數(shù)據(jù)庫 Memcache 版時,都是通過走 Apache WEB 服務(wù)再連云數(shù)據(jù)庫 Memcache 版,使用的是短連接。而每個短連接的開銷不止是 socket 重連,還有復(fù)雜的重新鑒權(quán)流程,開銷比一個普通請求大許多,因此對網(wǎng)站的效率是有很大影響的。
解決方案
于是我們建議用戶改短連接為長連接,但是云數(shù)據(jù)庫Memcache要求使用的PHP MEMCACHED擴展,不像memcache擴展那樣有個pconnect接口。如何才能在PHP中建立長連接,以下教程供大家參考。
在PHP 官網(wǎng)介紹 memcached 構(gòu)造函數(shù)時有下面一段話:
說明
Memcached::__construct ([ string $persistent_id ] )創(chuàng)建一個代表到Memcached服務(wù)端連接的Memcached實例。
參數(shù)
persistent_id默認情況下,Memcached實例在請求結(jié)束后會被銷毀。但可以在創(chuàng)建時通過persistent_id為每個實例指定唯一的ID, 在請求間共享實例。所有通過相同的persistent_id值創(chuàng)建的實例共享同一個連接。
即在調(diào)用構(gòu)造函數(shù)時傳給它一個同樣的 persistent_id 就能實現(xiàn)共享連接。代碼實現(xiàn)如下:
<?php
$memc = new Memcached(‘ocs’);//這里的ocs,就是persistent_id
if (count($memc->getServerList()) == 0) /*建立連接前,先判斷*/
{
echo "New connection"."<br>";
/*所有option都要放在判斷里面,因為有的option會導(dǎo)致重連,讓長連接變短連接!*/
$memc->setOption(Memcached::OPT_COMPRESSION, false);
$memc->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$memc->setOption(Memcached::OPT_TCP_NODELAY, true); //重要,php memcached有個bug,當get的值不存在,有固定40ms延遲,開啟這個參數(shù),可以避免這個bug
/* addServer 代碼必須在判斷里面,否則相當于重復(fù)建立’ocs’這個連接池,可能會導(dǎo)致客戶端php程序異常*/
$memc->addServer("your_ip", 11212);
$memc->setSaslAuthData("user", "password");
}
else
{
echo "Now connections is:".count($memc->getServerList())."<br>";
}
$memc->set("key", "value");
echo "Get from OCS: ".$memc->get("key");
//$memc->quit();/*代碼結(jié)束的地方一定不能加quit,否則變短連接!*/
?>
上述代碼要特別注意的三個地方都加了注釋。構(gòu)造函數(shù)里的“ocs”關(guān)鍵字,就相當于一個連接池了,需要使用的連接調(diào)用 new Memcached(‘ocs’) 就能從池里獲取連接。
執(zhí)行結(jié)果
將上述代碼放到 Apache 工作路徑/var/www/html/下面,命名為 test.php。然后再瀏覽器輸入: http://your_ip:80/test.php 。前8次瀏覽器都輸出結(jié)果為:
New connection
Get from OCS: value
即這8次都是新建連接,而8次后都是復(fù)用這8個鏈接了。抓包結(jié)果也顯示8次后都是長連接,無 socket 重連無鑒權(quán)。
那么為什么有8個鏈接?通過查看 httpd.conf 配置文件,是因為 appache 啟動了8個子進程:
#StartServers:numbers of server processes to start
StartServers 8
于是剛好在‘ocs’這個 persistent_id 的連接池里面初始化8個連接,此后的請求就用這8個鏈接了。
接下來測試頁面跳轉(zhuǎn),拷貝一個 php 文件,建立連接的構(gòu)造函數(shù)的 persistent_id 還是用 “ocs”。得到的結(jié)果是從一個連接換到了另一個連接上(因為調(diào)用的 Apache 子進程不一樣),但無鑒權(quán)無 socket 重連過程。即 PHP memcached 的長連接設(shè)置是有效的。通常我們使用的都是 PHP-FPM 模式, FPM 進程會和 memcached server 保持長連接,因此該連接的生命周期同 Apache 進程。