本文介紹了phpredis中與redis創建鏈接的兩種方式:connect(短鏈接)和pconnect(長鏈接)的區別。
問題背景:
項目採用LNMP架構,考慮到數據訪問性能問題,所以使用redis來作數據存儲,以前一直都是經過直連IP的方式來訪問redis,可是運維說redis用sentinel作的高可用,若是直連IP去訪問,高可用就沒法生效了,所以決定切換成域名的訪問方式。
切換域名以後,問題就來了,不少接口出現調用超時的狀況,在php-fpm的慢日誌中能夠看到超時接口的函數調用棧,接口的邏輯很簡單,只是從redis取一些數據出來,並無作其餘事情,甚至連日誌都沒打,爲什麼會超時呢?
問題追蹤:
既然當天作了切換訪問方式的變動,就必定跟這個有關。切換先後惟一的區別就是切換成域名的訪問方式以後,每次鏈接redis須要先到域名服務器將域名解析成IP,而後再去鏈接,若是直連IP就能夠省去域名解析的過程,難道是域名解析速度太慢致使超時?
問題定位:
寫了一個簡單的腳本,看了一下域名訪問和IP訪問的耗時差異到底多大,代碼以下,
//test.php
<?php
function microtime_float()
{
list($usec, $sec) = explode(」 「, microtime());
return ((float)$usec + (float)$sec);
}
$begin = microtime_float();
$redis=new Redis();
$redis->connect(「10.100.24.198″,6380);
$end = microtime_float();
$ip_cost = intval(($end – $begin)*1000000);
$begin = microtime_float();
$redis->connect(「videogh-6380-redis1.m6.tudou.com」,6380);
$end = microtime_float();
$domain_cost = intval(($end – $begin)*1000000);
echo 「ip costip_cost us,domain_costdomain_cost us\n」;
//結果
ip cost:514 us,domain_cost:26972 us
IP直連和域名鏈接的耗時居然差了40倍之多!!難怪會有如此多的請求超時。
問題解決:
既然切換成域名後,與redis頻繁創建鏈接致使超時,所以考慮redis的長鏈接方式,即pconnect方式。注意,這裏說的長鏈接和短鏈接,並非指TCP和UDP,其實redis自己也只支持域套接字和TCP鏈接,這裏說的長鏈接是指屢次請求之間能夠對redis鏈接進行復用,即只在第一次執行請求是創建鏈接,之後每次請求只是從鏈接池中將鏈接取出,再也不從新創建鏈接;而短鏈接表示鏈接在屢次請求之間不可複用,每次請求都須要從新創建鏈接。
理論上雖然可行,但還須要對pconnect的實際執行效果進行驗證,驗證過程以下。
驗證過程:
考慮用抓包和lsof兩種方式進行驗證,
準備工做
環境:
Linux+nginx+fpm+PHP5.5
將fpm的參數配置爲
pm.max_children = 1;
pm.start_servers = 1;
pm.max_spare_servers = 1;
經過修改php-fpm的參數,將php-fpm的進程設置爲一個,這樣就能夠準確找到執行請求的php-fpm進程id,
頁面對應的php代碼
public function test_redis()
{
$redis = new Redis();
//redis->connect(「127.0.0.1」, 6379); //connect鏈接
redis->pconnect(「127.0.0.1」, 6379); //pconnect鏈接
exit();
}
一、lsof方式
先用pconnect的方式鏈接方式請求頁面的test_redis函數,並執行命令lsof –n –p (fpm-pid),查看php-fpm的句柄使用狀況,以下圖所示
說明請求結束後,php-fpm中仍然保持與redis的鏈接,下次請求仍然能夠對該鏈接進行復用;若是使用connect,則獲取不到鏈接信息。
二、抓包方式
抓包命令:tcpdump –i any –X –v –vv tcp and dst port 6379
一樣用connec方式和pconnect方式執行屢次,經過抓包發現,使用connect方式鏈接每次都能抓到包,說明connect每次都會創建鏈接;使用pconnect方式鏈接只有第一次訪問的時候能抓到包,之後每次執行都抓不到包,說明鏈接只創建一次。
並且,當使用pconnect方式鏈接時,經過redis-cli鏈接到redis,並執行info clients,能夠看到connected_clients=2,排除終端的命令行鏈接之外,還有一個是與php-fpm保持的長鏈接,說明即便請求結束,php-fpm仍然會保留與redis的鏈接;若是採用connect方式進行鏈接,則connected_clients=1,即請求結束後php-fpm就釋放了與redis的鏈接。
|
原文連接:http://bbs.redis.cn/forum.php?mod=viewthread&tid=721php