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

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

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

假設有100臺PHP的應用服務器,每一個機器須要啓動100個apache或fpm工做進程,那每一個進程都會產生一個長鏈接到MySQL。這一共會產生1萬個My SQL鏈接。你們都知道MySQL是每一個鏈接會佔用1個線程。那MYSQL就須要建立1萬個線程,這樣大量的系統資源被浪費在線程間上下文切換上。而你的業務代碼中並非全部地方都在作數據庫操做,因此這個就是浪費的。數據庫

鏈接池就不一樣了,100個worker進程,公用10個數據庫鏈接便可,當操做完數據庫後,當即釋放資源給其餘worker進程。這樣就算有100臺PHP的服務器,那也只會建立1000個MySQL的鏈接,徹底能夠接受的。apache

之前確實沒有好的辦法來解決此問題的,如今有了swoole擴展,利用swoole提供的task功能能夠很方便作出一個鏈接池來。服務器

代碼以下:swoole

$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。fetch

相關文章
相關標籤/搜索