1. 程式人生 > >PHP連線池實現的一種想法

PHP連線池實現的一種想法

雖然現在名義上是PHP開發,不過做這資料分析的事,平時工作大部分用的是JAVA。C語言出身,學的語言比較多,JAVA還算熟悉,不過之前一直都沒用連線池。第一次遇到連線池是在學校的時候女朋友用連線池出現問題了,找我,我看了下覺得沒必要,直接就刪了。那時候用的是第三方擴充套件,感覺很麻煩,也沒必要。工作後,面對上百T的資料,同時併發的大量資料庫連結,才發現連線池的必要性。於是上週五自己封裝了一套連結池。寫完後,在想JAVA可以實現連線池,那麼PHP呢?我們用PHP做WEB開發,他們是不常駐記憶體的,連線池要放在哪,又以何種方式去獲取連結呢。然後看到了這一篇文章:http://blog.csdn.net/tangxy723/article/details/8607167

這篇文章是在PHP與資料庫之間又構建了一個快取系統,把大部分的資料都放入快取系統中。這樣一來大部分的訪問都只需要連結快取系統,僅有少部分還需要進入資料庫。這篇文章給我些啟發,既然PHP的速度足夠快,那麼導致資料庫訪問速度慢的原因在哪呢。我用java測試,發現直接用JDBC使用主鍵索引訪問一個有700W條記錄的表(由兩個欄位組成的聯合主鍵,用主鍵中的欄位進行分割槽,分了10個區)需要耗費的時間是380毫秒左右。而同一條SQL語句使用連線池的方式,只要70-80毫秒。這中間差了300毫秒,差在哪呢。連線池比起直接訪問,只是連線池事先打開了連結,省去connection的過程,也就是說開啟一條資料庫連結需要消耗一次資料庫訪問近四分之三的時間。那麼剩下的70-80毫秒,我們還有必要優化嗎,我寫了個demo測試了下,PHP直接從0加到700W要多久。demo如下

    public function test() {
        $st = $this->getMillisecond();
        $i = 0;
        while ($i < 7000000)
            $i ++;
        echo $this->getMillisecond() -$st;
        die;
    }

    private function getMillisecond() {
        list($t1, $t2) = explode(' ', microtime());
        return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
    }

我的幾次的測試結果是:218 207 225 203 221。顯然都是在200毫秒以上,因此我認為這塊的時間沒必要在優化了。隨便一提同樣的的程式碼,在java中只要1毫秒,PHP的計算效能還是差了很多。到此,我認為解決資料庫訪問速度慢的問題可以使用類似java連線池的方式解決,即先開啟連結,然後任務。問題在於人家java能常駐記憶體,支援多執行緒,連線池只需要開一個執行緒維護,要用的時候找這個執行緒就可以直接獲取到記憶體物件了。但PHP用於WEB,每一次請求的時候開始,請求結束的時候結束,不常駐記憶體,也沒多執行緒可言。解決這個問題,我的想法是用先在伺服器上開啟一個PHP守護程序,這個守護程序開啟並維護多個連結物件,起著連線池的作用,然後每一次資料庫的訪問都由這個守護程序發起,這是程序間通訊,具體使用管道還是網路都可以,只要把SQL語句傳給守護程序,守護程序啟動一個閒置的連線去執行這條SQL,並將放回結果以程序間通訊的方式返回。寫了個demo測試管道讀取的速度:

    public function test() {
        $st = $this->getMillisecond();
        $file = file_get_contents(__DIR__."/test");
        echo $file."</br>";
        echo $this->getMillisecond() -$st;
        die;
    }

    private function getMillisecond() {
        list($t1, $t2) = explode(' ', microtime());
        return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
    }

上圖了執行結果,test檔案大小為3k。無論幾次執行結果,消耗時間都為0。也就是說我們讀取的時間可以忽略掉。然後再寫一個demo進行寫入,

    public function test() {
        $file = file_get_contents(__DIR__."/test");
        $st = $this->getMillisecond();
        file_put_contents(__DIR__."/test",$file,FILE_APPEND);
        echo $this->getMillisecond() -$st;
        die;
    }

    private function getMillisecond() {
        list($t1, $t2) = explode(' ', microtime());
        return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
    }

測試平均值為12。也就是說,整個過程我們我們可以節省的時間是300-12=288毫秒,速度上提升了很多。

最後,這只是個思考的筆記,一時的想法,現在沒有時間具體實施。