天天看點

php pdo 連接配接池mysql,PHP+Mysql的長連接配接、連接配接池解析

PHP連接配接MySQL的方式,用的多的是mysql擴充、mysqli擴充、pdo_mysql擴充,是官方提供的。php的運作機制是頁面執行完會釋放所有該php程序中的所有資源的,如果有多個并發通路本地的測試頁面 http://127.0.0.1/1.php 根據php跟web伺服器的不同,會開相應的線程或者程序去處理該請求,請求完了會釋放結果的。也就是php無法從語言層面從頁面到頁面之間傳遞一些資料,但是mysql_pconnect跟pdo中的ATTR, 設定array(PDO::ATTR_PERSISTENT => true)如下是可以實作長連接配接的。$conn = new PDO($dsn, DB_USER, DB_PASSWORD,

array(PDO::ATTR_PERSISTENT => true)

);

長連接配接的作用我覺得是在高負載的情況下,通過複用長連接配接,減少了每個頁面的建立資料庫連接配接的時間,而這個建立mysql connection的時間,在本地機器上

在資料庫connnections < 10的情況下 , mysql pdo 建立connection time 為0.003ms, mysqli建立connection time為0.14ms

在資料庫connection接近滿的時候,mysql pdo建立connection time為0.13ms, mysqli建立connection time為0.13ms

以上樣本都是在大概估測時間,時間太小不好估計。其實建立連接配接的時間并不長,那這樣為什麼需要mysql長連接配接、連接配接池這樣的東西呢。那是在高負載下,比如server單機可以接受的mysql并發在200左右,web server的單機并發在700左右,那麼當大批量500并發連接配接壓過來的時候, web server沒到滿負荷, mysql提前到了滿負荷,就會導緻所有頁面無法響應、或者已經建立好資料庫連接配接的頁面執行很慢。

php中的mysql長連接配接由于php的運作方式有多種,因而長連接配接實作也有多種。需要web伺服器支援才可以實作長連接配接,因為php是沒有程序池跟連接配接池這種概念的,絕大多數情況下php應用本身不是一個應用伺服器(後起之秀swoole, 是一個優秀的php應用伺服器,不過是在c層面做的)。因而php的長連接配接其實是搭載apache這樣的帶有mpm子產品的webserver, Linux 下apache會維護一個程序池,開啟了apache mpm功能之後,apache會預設維持一個程序池,mysql長連接配接之後的連接配接,并沒有作為socet連接配接關閉,而是作為一個不釋放的東西,放進了程序池/線程池裡面去。等需要連接配接的時,apache從它維護的程序池/線程池裡面取出mysql  socket connnection, 然後就可以複用此連接配接了。

這裡測試一下,首先本機環境是linux , 後文所用mysql httpd php都是編譯安裝的,httpd的mpm模型這裡采用的是worker, httpd的mpm(apache用于并行方面功能的,俗稱多路處理子產品)其實有perfork、worker、event三種。mpm的好處是讓apache随時有些備用的spare或者空閑的子程序(伺服器線程池),随時等待新過來的請求,這樣用戶端不需要在請求服務之前等待子程序的産生。

使用什麼mpm,需要單獨指定編譯進去apache裡面去,比如編譯work mpm到apache裡面去./configure \

--with-apr=/home/dengpan/opt/apr-1.5.2 \

--with-apr-util=/home/dengpan/opt/apr-util-1.5.4 \

--prefix=/home/dengpan/opt/httpd-2.4.16 \

--with-mpm=worker

mpm的配置參數為

StartServers 15

MinSpareThreads 75

MaxSpareThreads250

ThreadsPerChild 10

MaxRequestWorkers  400

MaxConnectionsPerChild   0

啟動apache用pstree看到 |-httpd—15*[httpd—11*[{httpd}]],說明起了15個server程序,每個server起了10個子線程。整個mpm要維持的最小的閑置線程數量在75,最大的閑置線程在250。滿載的最大的工作線程在400個。下面準備一個shell腳本,每1秒輸出下目前mysql的active連接配接數量, 檢視mysql current連接配接數我用的較多的有2個方法

1.進mysql shell, 執行SHOW STATUS WHERE `variable_name` = ‘Threads_connected'; 不過這個方法得mysql shell進的去才對,當connections很多的時候,mysql shell進不去也就無法查詢了

2.shell直接查詢,  find /proc/`pidof mysqld`/fd/ -follow -type s | wc -l , 需要root權限,好處是即使mysql因為too many connections無法進入shell的時候還是可以連接配接進去。

這裡用方法2,因為後面回到機器的mysql滿載負荷的。寫一個shell如下:#!/bin/bash

while(true)

do

find /proc/`pidof mysqld`/fd/ -follow -type s | wc -l

sleep 1

done

後面執行該shell不斷的輸出目前連接配接數,測試可得:

cli下執行php,長連接配接無效,cli下腳本一退出,連接配接即釋放

apche+mod_php不開啟mpm子產品的話,無論mysql mysql_pconnect、pdo_mysql長連接配接, 頁面通路完畢, mysql連接配接即釋放。

apche+mod_php開啟mpm子產品(worker模式)的話,無論mysql mysql_pconnect、pdo_mysql長連接配接, 頁面通路完畢, mysql連接配接+1,直到達到最大的mysql連接配接數,不在增加,但是通路頁面還是可以複用連接配接查詢到相應資料。

nginx+php-fpm下mysql長連接配接基本無效果。

最後給出我的建議,一般小型php應用是沒有性能問題的,php自身連接配接mysql很快,很多都處于性能過剩, 随着apache慢慢被nginx替代,php的mysql長連接配接也隻會越來越雞肋。單機的話,其實要是怕mysql建立connections有壓力,最好把mysql的建立使用單例模式,這樣一個頁面隻會建立一個mysql連接配接執行個體。如下面的例子,而這個更适合寫在架構裡去實作單例。class DB {

private static $_instance;

private $db;

private function __construct() {

$this->db = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, 'dbname', 'dbport');

}

public static function getInstance() {

if (!(self::$_instance instanceof DB)) {

self::$_instance = new self();

}

return self::$_instance;

}

private function __clone() {

}

public function getConn() {

return $this->db;

}

}

$conn = DB::getInstance()->getConn();

至于非要有用mysql連接配接池的那種要求的,推薦使用swoole擴充實作的連接配接池.

打賞

php pdo 連接配接池mysql,PHP+Mysql的長連接配接、連接配接池解析

微信掃一掃,打賞作者吧~