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)以下是能夠實現長鏈接的。php

$conn = new PDO($dsn, DB_USER, DB_PASSWORD,
    array(PDO::ATTR_PERSISTENT => true)
);

長鏈接的做用我以爲是在高負載的狀況下,經過複用長鏈接,減小了每一個頁面的創建數據庫鏈接的時間,而這個創建mysql connection的時間,在個人機器上mysql

  • 在數據庫connnections < 10的狀況下 , mysql pdo 創建connection time 爲0.003ms, mysqli創建connection time爲0.14mslinux

  • 在數據庫connection接近滿的時候,mysql pdo創建connection time爲0.13ms, mysqli創建connection time爲0.13msnginx

以上樣本都是在大概估測時間,時間過小很差估計。其實創建鏈接的時間並不長,那這樣爲何須要mysql長鏈接、鏈接池這樣的東西呢。那是在高負載下,好比server單機能夠接受的mysql併發在200左右,web server的單機併發在700左右,那麼當大批量500併發鏈接壓過來的時候, web server沒到滿負荷, mysql提早到了滿負荷,就會致使全部頁面沒法響應、或者已經創建好數據庫鏈接的頁面執行很慢。laravel

php中的mysql長鏈接因爲php的運行方式有多種,於是長鏈接實現也有多種。須要web服務器支持才能夠實現長鏈接,由於php是沒有進程池跟鏈接池這種概念的,絕大多數狀況下php應用自己不是一個應用服務器(後起之秀swoole, 是一個優秀的php應用服務器,不過是在c層面作的)。於是php的長鏈接實際上是搭載apache這樣的帶有mpm模塊的webserver, linux 下apache會維護一個進程池,開啓了apache mpm功能以後,apache會默認維持一個進程池,mysql長鏈接以後的鏈接,並無做爲socet鏈接關閉,而是做爲一個不釋放的東西,放進了進程池/線程池裏面去。等須要鏈接的時,apache從它維護的進程池/線程池裏面取出mysql socket connnection, 而後就能夠複用此鏈接了。git

這裏測試一下,首先本機環境是archlinux , 後文所用mysql httpd php都是本身編譯的源代碼,都在/home/dengpan/opt目錄。httpd的mpm模型這裏採用的是worker, httpd的mpm(apache用於並行方面功能的,俗稱多路處理模塊)其實有perfork、worker、event三種。mpm的好處是讓apache隨時有些備用的spare或者空閒的子進程(服務器線程池),隨時等待新過來的請求,這樣客戶端不須要在請求服務以前等待子進程的產生。github

使用什麼mpm,須要單獨指定編譯進去apache裏面去,好比編譯work mpm到apache裏面去,好比個人最簡化httpd的編譯參數是web

./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

查看httpd加載的模塊,sql

在這裏插入圖片描述

看到worker.c 已經編譯過去了,shell

mpm的配置參數爲

<IfModule mpm_worker_module>
	StartServers			 15
	MinSpareThreads		 75
	MaxSpareThreads		250
	ThreadsPerChild		 10
	MaxRequestWorkers	  400
	MaxConnectionsPerChild   0
</IfModule>

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

  • 進mysql shell, 執行SHOW STATUS WHERE variable_name = ‘Threads_connected’; 不過這個方法得mysql shell進的去纔對,當connections不少的時候,mysql shell進不去也就沒法查詢了

  • 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不斷的輸出當前鏈接數,測試可得

  1. cli下執行php,長鏈接無效,cli下腳本一退出,鏈接即釋放

  2. apche+mod_php不開啓mpm模塊的話,不管mysql mysql_pconnect、pdo_mysql長鏈接, 頁面訪問完畢, mysql鏈接即釋放。

  3. apche+mod_php開啓mpm模塊(worker模式)的話,不管mysql mysql_pconnect、pdo_mysql長鏈接, 頁面訪問完畢, mysql鏈接+1,直到達到最大的mysql鏈接數,不在增長,可是訪問頁面仍是能夠複用鏈接查詢到相應數據。

  4. nginx+php-fpm下mysql長鏈接基本無效果。

apache之因此可以複用mysql鏈接,說明apache確定爲mysql本身實現了一些功能函數、模塊,不然不可能把一個未知類型的socket指針存下來的。用ldd查看,

➜  mysql_persist  ldd /home/dengpan/opt/httpd-2.4.16/bin/httpd
        linux-vdso.so.1 (0x00007ffffcbde000)
        libpcre.so.1 => /usr/lib/libpcre.so.1 (0x00007f8e8d17c000)
        libaprutil-1.so.0 => /home/dengpan/opt/apr-util-1.5.4/lib/libaprutil-1.so.0 (0x00007f8e8cf57000)
        libexpat.so.1 => /usr/lib/libexpat.so.1 (0x00007f8e8cd2d000)
        libapr-1.so.0 => /home/dengpan/opt/apr-1.5.2/lib/libapr-1.so.0 (0x00007f8e8cafb000)
        libuuid.so.1 => /usr/lib/libuuid.so.1 (0x00007f8e8c8f6000)
        librt.so.1 => /usr/lib/librt.so.1 (0x00007f8e8c6ee000)
        libcrypt.so.1 => /usr/lib/libcrypt.so.1 (0x00007f8e8c4b6000)
        libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f8e8c299000)
        libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f8e8c095000)
        libc.so.6 => /usr/lib/libc.so.6 (0x00007f8e8bcf3000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8e8d3ec000)

能夠猜想出/home/dengpan/opt/apr-util-1.5.4/lib/libaprutil-1.so.0跟/home/dengpan/opt/apr-1.5.2/lib/libapr-1.so.0應實現了跟mysql相關的代碼段。因爲我是本地編譯的,很方便找到函數入口,/home/dengpan/github/apache-httpd/apr-util-1.5.4/dbd/apr_dbd_mysql.c這個文件,實際上是apache的mod_dbd對常見的數據庫都作了長鏈接支持。而nginx跟php-fpm的關係並不像php跟apache那樣,因此nginx+php-fpm沒法實現對應的長鏈接。大概是php-fpm並無作mysql的進程、線程池。

最後給出個人建議,通常小型php應用是沒有性能問題的,php自身鏈接mysql很快,不少都處於性能過剩, 隨着apache慢慢被nginx替代,php的mysql長鏈接也只會愈來愈雞肋。單機的話,其實要是怕mysql建立connections有壓力,最好把mysql的建立使用單例模式,這樣一個頁面只會建立一個mysql鏈接實例。諸以下面的單例例子代碼,而這個更適合寫在框架裏去實現單例。

<?php
/** * Created by PhpStorm. * User: dengpan * Date: 15-7-24 * Time: 下午2:56 */
include "./db.php";
class DB { 
	private static $_instance;
	private $db;
	private function __construct()
	{ 
		$this->db =  new mysqli(DB_HOST, DB_USER, DB_PASSWORD, 'my', 3307);
	}
	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();

點關注,不迷路

好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是人才。以前說過,PHP方面的技術點不少,也是由於太多了,實在是寫不過來,寫過來了你們也不會看的太多,因此我這裏把它整理成了PDF和文檔,若是有須要的能夠

點擊進入暗號: PHP+「平臺」

在這裏插入圖片描述

在這裏插入圖片描述


更多學習內容能夠訪問【對標大廠】精品PHP架構師教程目錄大全,只要你能看完保證薪資上升一個臺階(持續更新)

以上內容但願幫助到你們,不少PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提高,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨須要的能夠免費分享給你們,須要的能夠加入個人 PHP技術交流羣

相關文章
相關標籤/搜索