天天看點

PHP沒有資料庫連接配接池怎麼破?PHP環境下使用Nginx ngx_http_limit_req_module子產品的高負載解決方案

線上運作了一套輔助系統是利用了開源的PHP改的,之前也沒怎麼玩過PHP,沒想到這玩意兒還是有不少坑的。突然某一天一個使用者做線上活動推廣,然後短時間内湧進來了上萬的請求,然後資料庫連接配接耗盡,短時間内幾乎拖垮了整個系統。導緻系統奔潰的有多方面原因,今天主要針對PHP沒有資料庫連接配接池的原因來分析。

在PHP裡,資料庫連接配接在請求到達時建立,請求結束時釋放。如果同時幾千個請求到達,那就同時會建立幾千個資料庫連接配接,非常恐怖。而且PHP木有比較好的資料庫連接配接池驅動方案,是以我們得另想辦法。

解決這種問題有三種辦法:

1.使用Mysql Proxy中間件。Mysql Proxy提供了連接配接池管理的功能。但是我們沒有采用此方法,因為情況緊急,沒有人熟悉這玩意兒。

2.使用PHP-FPM。PHP-FPM是PHP的一個FastCGI程序管理器。通過配置可以控制同時處理PHP請求的程序數。

具體可以參考:http://www.linuxde.net/2013/06/14638.html

但是我們也沒用使用此方案,因為安裝配置過程比較麻煩。

3.使用Nginx的ngx_http_limit_req_module來控制請求。

此子產品可以通過自定義的鍵值來限制請求頻率。限制的方法就像漏鬥,每秒固定處理請求數,然後推遲超出的請求,最後超出最大值的直接503傳回拒絕。

我們使用了此方案,是因為隻需簡單配置,而且可以靈活控制限制請求的場景。例如,對于靜态資源的請求我們不做限制,而對于PHP的請求做限制。還可以從URL位址裡提取出變量資訊作為鍵,來達到更細的請求限制。

下面貼部分我們的配置給大家講解下。

http {
    ......
    limit_req_zone $limit_key zone=limit_one:m rate=r/s;
    #定義limit_key為Key的變量名,用于後面指派,每個Key都有自己的計數器。limit_one為zone的名稱。rate表示每秒最多接受30個同時請求。
    server {
        ......
        if ( $request_uri ~* .*php.* ) {
              set $limit_one $binary_remote_addr;
              #對于全部PHP首先有個預設的Key,使用用戶端的IP作為Key。相當于每個用戶端IP都會在zone的限制内。
         }
        if ( $query_string ~* .*id/(\d+)\.php.* ) {
              set $limit_one $1;
              #提取id後面的值作為Key。
        }
        if ( $query_string ~* .*appid/wx(.*)\.html.* ) {
              set $limit_one $1;
              #提取appid作為Key。
        }
        limit_req zone=limit_one burst=;
        #限制limit_one在此server内的漏鬥容量為200。假設一個Key對應的請求數為200,那麼第一秒内在處理的為30個請求,其餘的170個請求在等待排隊。假設一個Key對應的請求數為300,那麼超出200的部分将直接傳回503。
        .......
    }
}
           

參考:http://www.ttlsa.com/nginx/nginx-limiting-the-number-of-requests-ngx_http_limit_req_module-module/

官方文檔:http://nginx.org/en/docs/http/ngx_http_limit_req_module.html