基於swoole擴展實現真正的PHP數據庫連接池


轉自:  http://rango.swoole.com/archives/265

PHP的數據庫連接池一直以來都是一個難題,很多從PHP語言轉向Java的項目,大多數原因都是因為Java有更好的連接池實現。PHP的MySQL擴展提供了長連接的API,但在PHP機器數量較多,規模較大的情況下,mysql_pconnect非但不能節約MySQL資源,反而會加劇數據庫的負荷。

假設有100台PHP的應用服務器,每個機器需要啟動100個apache或fpm工作進程,那每個進程都會產生一個長連接到MySQL。這一共會產生1萬個My SQL連接。大家都知道MySQL是每個連接會占用1個線程。那MYSQL就需要創建1萬個線程,這樣大量的系統資源被浪費在線程間上下文切換上。而你的業務代碼中並不是所有地方都在做數據庫操作,所以這個就是浪費的。

連接池就不同了,100個worker進程,公用10個數據庫連接即可,當操作完數據庫后,立即釋放資源給其他worker進程。這樣就算有100台PHP的服務器,那也只會創建1000個MySQL的連接,完全可以接受的。

以前確實沒有好的辦法來解決此問題的,現在有了swoole擴展,利用swoole提供的task功能可以很方便做出一個連接池來。

代碼如下:

$serv = new swoole_server("127.0.0.1", 9508);
$serv->set(array(
    'worker_num' => 100,
    'task_worker_num' => 10, //MySQL連接的數量
));

function my_onReceive($serv, $fd, $from_id, $data)
{
    //taskwait就是投遞一條任務,這里直接傳遞SQL語句了
    //然后阻塞等待SQL完成
    $result = $serv->taskwait("show tables");
    if ($result !== false) {
        list($status, $db_res) = explode(':', $result, 2);
        if ($status == 'OK') {
            //數據庫操作成功了,執行業務邏輯代碼,這里就自動釋放掉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();

 

這里task_worker_num就是要啟用的數據庫連接池數量,worker進程為100時,連接池數量為10就可以設置為worker_num = 100, task_worker_num = 10。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM