日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

php cli swoole mysql_[了解实践]Swoole、PHP与MySQL:连接池,swoole扩展实现真正的PHP数据库连接池。...

發(fā)布時(shí)間:2023/12/4 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php cli swoole mysql_[了解实践]Swoole、PHP与MySQL:连接池,swoole扩展实现真正的PHP数据库连接池。... 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

背景:swoole的出現(xiàn),包括PHP出現(xiàn)前,在新浪企業(yè)郵箱就有基于Sun Solaris 系統(tǒng)上面用c++寫Mysql的長(zhǎng)連接,那時(shí)候的長(zhǎng)連接是基于RPC實(shí)現(xiàn),對(duì)mysql那一端形成一個(gè)遠(yuǎn)程過(guò)程的調(diào)用,通過(guò)XDR數(shù)據(jù)結(jié)構(gòu)進(jìn)行解析mysql傳來(lái)的數(shù)據(jù)項(xiàng)(RPC也為sun最新提出并后來(lái)在linux上默認(rèn)支持),也就是說(shuō)像用戶登錄驗(yàn)證這一塊用Mysql的長(zhǎng)連接來(lái)實(shí)現(xiàn),提高其效率運(yùn)行相當(dāng)穩(wěn)定,后面這個(gè)系統(tǒng)遷移到了FreeBSD后,出現(xiàn)了mysql長(zhǎng)連接的服務(wù)經(jīng)常出現(xiàn)假死,也就是說(shuō)進(jìn)程還在,但是已經(jīng)連接不上mysql了,重新啟動(dòng)這個(gè)RPC服務(wù)又好了,原因未知,當(dāng)時(shí)我對(duì)c++不了解(現(xiàn)在也不太了解,只聽(tīng)說(shuō)要看是否形成coredump啥的),當(dāng)年我還寫過(guò)一個(gè)判斷死了就殺死,重啟動(dòng),判斷的程序也老半天回不來(lái),于是我又改成了一個(gè)多進(jìn)程,如果超時(shí)沒(méi)有回來(lái),就干掉那個(gè)進(jìn)程,重啟Rpc服務(wù),再后來(lái),這套C++的cgi被替換成了php,再后來(lái)基于FreeBSD的系統(tǒng)遷移到了Linux,也就是現(xiàn)在一直在linux上,linux也就強(qiáng)大了起來(lái),回想起來(lái),當(dāng)年一個(gè)登錄服務(wù)如此極致,現(xiàn)在都變成了直接查詢mysql了,這個(gè)長(zhǎng)連接技術(shù)有還有用嗎?我只能說(shuō)對(duì)有上千臺(tái)上萬(wàn)臺(tái)的服務(wù)器可能有用,能節(jié)省一定的機(jī)器成本罷。但是,追求技術(shù)永無(wú)止境,需要有這樣的一些東西來(lái)繁榮我們這個(gè)PHP的市場(chǎng),長(zhǎng)連接這個(gè)話題不再是Java做成了連接池,像c++也能做成連接池,像騰訊廣平就有c++團(tuán)隊(duì)還有寫cgi實(shí)現(xiàn)長(zhǎng)連接Mysql服務(wù),據(jù)說(shuō)前二年吧更多關(guān)注了H5,像實(shí)時(shí)技術(shù),比如Tail技術(shù)在web上的實(shí)現(xiàn),有轉(zhuǎn)向nodejs的趨勢(shì),而此時(shí)的PHP拿不出這樣的技術(shù),是很危險(xiǎn)的,有了swoole起到填補(bǔ)作用,我更多的是覺(jué)得官方應(yīng)該重視這個(gè)技術(shù),而不是形成一個(gè)擴(kuò)展,像H5的來(lái)到,像websocket的進(jìn)入,這些東西對(duì)于Node來(lái)講,從前端向后端的統(tǒng)一,而PHp呢?沒(méi)有誰(shuí)來(lái)解決,那么從用戶角度來(lái)講,開(kāi)發(fā)者用戶的流失或遷移,對(duì)PHP本身也是一個(gè)損失,但我還是說(shuō)PHP是最好的語(yǔ)言沒(méi)有之一,期望其能伴隨潮流,與時(shí)俱進(jìn)。

PHP的數(shù)據(jù)庫(kù)連接池一直以來(lái)都是一個(gè)難題,很多從PHP語(yǔ)言轉(zhuǎn)向Java的項(xiàng)目,大多數(shù)原因都是因?yàn)镴ava有更好的連接池實(shí)現(xiàn)。PHP的MySQL擴(kuò)展提供了長(zhǎng)連接的API,但在PHP機(jī)器數(shù)量較多,規(guī)模較大的情況下,mysql_pconnect非但不能節(jié)約MySQL資源,反而會(huì)加劇數(shù)據(jù)庫(kù)的負(fù)荷。

假設(shè)有100臺(tái)PHP的應(yīng)用服務(wù)器,每個(gè)機(jī)器需要啟動(dòng)100個(gè)apache或fpm工作進(jìn)程,那每個(gè)進(jìn)程都會(huì)產(chǎn)生一個(gè)長(zhǎng)連接到MySQL。這一共會(huì)產(chǎn)生1萬(wàn)個(gè)My SQL連接。大家都知道MySQL是每個(gè)連接會(huì)占用1個(gè)線程。那MYSQL就需要?jiǎng)?chuàng)建1萬(wàn)個(gè)線程,這樣大量的系統(tǒng)資源被浪費(fèi)在線程間上下文切換上。而你的業(yè)務(wù)代碼中并不是所有地方都在做數(shù)據(jù)庫(kù)操作,所以這個(gè)就是浪費(fèi)的。

連接池就不同了,100個(gè)worker進(jìn)程,公用10個(gè)數(shù)據(jù)庫(kù)連接即可,當(dāng)操作完數(shù)據(jù)庫(kù)后,立即釋放資源給其他worker進(jìn)程。這樣就算有100臺(tái)PHP的服務(wù)器,那也只會(huì)創(chuàng)建1000個(gè)MySQL的連接,完全可以接受的。

以前確實(shí)沒(méi)有好的辦法來(lái)解決此問(wèn)題的,現(xiàn)在有了swoole擴(kuò)展,利用swoole提供的task功能可以很方便做出一個(gè)連接池來(lái)。

代碼如下:

$serv = new swoole_server("127.0.0.1", 9508);

$serv->set(array(

'worker_num' => 100,

'task_worker_num' => 10, //MySQL連接的數(shù)量

));

function my_onReceive($serv, $fd, $from_id, $data)

{

//taskwait就是投遞一條任務(wù),這里直接傳遞SQL語(yǔ)句了

//然后阻塞等待SQL完成

$result = $serv->taskwait("show tables");

if ($result !== false) {

list($status, $db_res) = explode(':', $result, 2);

if ($status == 'OK') {

//數(shù)據(jù)庫(kù)操作成功了,執(zhí)行業(yè)務(wù)邏輯代碼,這里就自動(dòng)釋放掉MySQL連接的占用

$serv->send($fd, var_export(unserialize($db_res), true) . "\n");

} else {

$serv->send($fd, $db_res);

}

return;

} else {

$serv->send($fd, "Error. Task timeout\n");

}

}

function my_onTask($serv, $task_id, $from_id, $sql)

{

static $link = null;

if ($link == null) {

$link = mysqli_connect("127.0.0.1", "root", "root", "test");

if (!$link) {

$link = null;

$serv->finish("ER:" . mysqli_error($link));

return;

}

}

$result = $link->query($sql);

if (!$result) {

$serv->finish("ER:" . mysqli_error($link));

return;

}

$data = $result->fetch_all(MYSQLI_ASSOC);

$serv->finish("OK:" . serialize($data));

}

function my_onFinish($serv, $data)

{

echo "AsyncTask Finish:Connect.PID=" . posix_getpid() . PHP_EOL;

}

$serv->on('Receive', 'my_onReceive');

$serv->on('Task', 'my_onTask');

$serv->on('Finish', 'my_onFinish');

$serv->start();

看完上面的,看完了,覺(jué)得真的很厲害。畢竟,現(xiàn)在來(lái)說(shuō)可能是還沒(méi)有真正在PHP使用數(shù)據(jù)庫(kù)連接池的大應(yīng)用。今天終于準(zhǔn)備實(shí)驗(yàn)實(shí)驗(yàn)。

在開(kāi)始之前,還是說(shuō)一下測(cè)試環(huán)境吧:OS CentOS 6.4 x86;php 5.3.17;MySQL 5.5.28;Swoole 1.6.8。

首先,我們當(dāng)然要把代碼寫好。下面是服務(wù)端代碼,很多是參考了上面文章里面的,當(dāng)然也有自己的內(nèi)容。

$serv = swoole_server_create('127.0.0.1', 3305, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);//端口3305

swoole_server_set($serv, array(

'worker_num' => 2,??????//worker線程的數(shù)量

'task_worker_num' => 1, //MySQL連接的數(shù)量

));//作為小型測(cè)試,參數(shù)調(diào)得比較小

//這里有一個(gè)守護(hù)進(jìn)程化的參數(shù),由于是實(shí)驗(yàn),沒(méi)有加入

function my_onReceive($serv, $fd, $from_id, $data){

//執(zhí)行查詢

$result = $serv->taskwait($data);

if ($result !== false) {

swoole_server_send($serv, $fd, $result);

return;

} else {

swoole_server_send($serv, $fd, "Error. Task timeout\n");

}

}

function my_onTask($serv, $task_id, $from_id, $sql){

static $link = NULL;

if ($link == NULL) {

$link = mysqli_connect('localhost', 'user', 'pw', 'db');

//localhost=>UNIX Socket , IP地址=>TCP/IP

}

$result = $link->query($sql);

if ($result === false) {

swoole_server_finish($serv, 'b:0;');//語(yǔ)句運(yùn)行失敗,這是serialize后的false,下同理

return;

}

if ($result === true){

swoole_server_finish($serv, 'b:1;');//寫入操作成功

return;

}

$data = $result->fetch_all(MYSQLI_ASSOC);

swoole_server_finish($serv, serialize($data));

}

function my_onFinish($serv, $data){

//這次實(shí)驗(yàn)就沒(méi)有寫東西了

//但是必須有這個(gè)函數(shù)定義

//其實(shí)可以寫日志什么的吧

}

swoole_server_handler($serv, 'onReceive', 'my_onReceive');

swoole_server_handler($serv, 'onTask', 'my_onTask');

swoole_server_handler($serv, 'onFinish', 'my_onFinish');

//上面是設(shè)置回調(diào)函數(shù)

swoole_server_start($serv);

swoole_event_wait();//實(shí)驗(yàn)環(huán)境是PHP5.3,所以需要這個(gè)函數(shù)進(jìn)行事件輪詢;5.4+就不需要了

如果把上面的連接池代碼和Rango的相比較,會(huì)發(fā)現(xiàn)我的對(duì)于錯(cuò)誤的部分處理很少。其實(shí)這個(gè)時(shí)候用CLI運(yùn)行這個(gè)連接池,然后使用Telnet已經(jīng)就可以直接測(cè)試效果了。但是不管怎么說(shuō)這個(gè)東西還是要應(yīng)用在PHP上面的,我簡(jiǎn)單地寫一下PHP方面的代碼。

$link=new swoole_client(SWOOLE_SOCK_TCP,SWOOLE_SOCK_SYNC);//TCP方式、同步

$link->connect('127.0.0.1',3305);//連接

$link->send('SELECT * FROM `table`');//執(zhí)行查詢

$res=unserialize($link->recv());

if(!res){

echo 'Failed!';

}

else{

print_r($res);

}

$link->close();

//上面的是最簡(jiǎn)單的測(cè)試,下面可以簡(jiǎn)單地改寫成函數(shù)

function dbcp_query($sql){

$link=new swoole_client(SWOOLE_SOCK_TCP,SWOOLE_SOCK_SYNC);//TCP方式、同步

$link->connect('127.0.0.1',3305);//連接

$link->send($sql);//執(zhí)行查詢

return unserialize($link->recv());

//swoole_client類析構(gòu)時(shí)會(huì)自動(dòng)關(guān)閉連接

}

現(xiàn)在可以運(yùn)行了,本次實(shí)驗(yàn)是成功的。但是如果使用dbcp_query()這個(gè)函數(shù),每次調(diào)用都要發(fā)起一次TCP連接,執(zhí)行的語(yǔ)句多了,肯定出問(wèn)題。這個(gè)時(shí)候我們就可以把它封裝成一個(gè)類了,單純實(shí)現(xiàn)這個(gè)會(huì)比較的簡(jiǎn)單,但是打出來(lái)要點(diǎn)時(shí)間,這里就不寫了。

最后:今天做的是數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)。從上面的代碼我們可以看見(jiàn),程序與連接池之間的數(shù)據(jù)交換是使用php序列進(jìn)行的。這里會(huì)有兩次的serialize、unserialize,絕對(duì)也是一個(gè)開(kāi)銷。Rango的文章里面有說(shuō)到“MySQL是每個(gè)連接會(huì)占用1個(gè)線程……大量的系統(tǒng)資源被浪費(fèi)在線程間上下文切換上……不是所有地方都在做數(shù)據(jù)庫(kù)操作,所以這個(gè)就是浪費(fèi)的。”再看看他那篇文章的假設(shè):“假設(shè)有100臺(tái)PHP的應(yīng)用服務(wù)器,每個(gè)機(jī)器需要啟動(dòng)100個(gè)apache或fpm工作進(jìn)程?!边@肯定不是一個(gè)小項(xiàng)目,確實(shí)就適合用連接池了。寫的東西是用來(lái)練手或者解悶兒的?常規(guī)方法已經(jīng)可以了。不要忘了一點(diǎn):程序與連接池的交互我們應(yīng)該還是用Swoole實(shí)現(xiàn)的,Swoole可是一個(gè)TCP/UDP擴(kuò)展。而Swoole只能運(yùn)行在Linux平臺(tái)上面,但是Linux平臺(tái)上的MySQL是可以用UNIX Socket通訊的。

P.S.:找個(gè)時(shí)間給epdb改寫一個(gè)支持?jǐn)?shù)據(jù)庫(kù)連接池的版本。

來(lái)自:http://rango.swoole.com/archives/265

http://bokjan.com/prog/php-db-conn-pool-with-swoole.html

總結(jié)

以上是生活随笔為你收集整理的php cli swoole mysql_[了解实践]Swoole、PHP与MySQL:连接池,swoole扩展实现真正的PHP数据库连接池。...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。