swoole http server 性能優化

上線了一個基於 swoole http server 的服務之後,發現這個服務的請求耗時監控毛刺十分嚴重,接口耗時波動比較大,通過一段時間的分析,發現這個服務 response 包十分大,有些 response 包高達1 ~ 2M,甚至更大,這樣就很清楚了,由於包太多,致使服務相應波動比較大。php

這裏稍微解釋下,爲何 response 包會致使相應時間波動,這裏主要有兩個方面的影響,第一是包大會致使 swoole 之間進程通訊更加耗時,並佔用更多資源,第二是包大會致使 swoole 的 reactor 線程發包更加耗時,關於 reactor 的解釋,摘自react

Swoole的主進程是一個多線程的程序。其中有一組很重要的線程,稱之爲Reactor線程。它就是真正處理TCP鏈接,收發數據的線程。 Swoole的主線程在Accept新的鏈接後,會將這個鏈接分配給一個固定的Reactor線程,並由這個線程負責監聽此socket。在socket可讀時讀取數據,並進行協議解析,將請求投遞到Worker進程。在socket可寫時將數據發送給TCP客戶端。nginx

那麼怎麼優化呢?swoole

其實很簡單,那就是直接在 swoole 裏開啓 gzip,這裏摘自 swoole 文檔網絡

啓用Http GZIP壓縮。壓縮能夠減少HTML內容的尺寸,有效節省網絡帶寬,提升響應時間。必須在write/end發送內容以前執行gzip,不然會拋出錯誤。swoole_http_response->gzip(int $level = 1);$level 壓縮等級,範圍是1-9,等級越高壓縮後的尺寸越小,但CPU消耗更多。默認爲1,調用gzip方法後,底層會自動添加Http編碼頭,PHP代碼中不該當再行設置相關Http頭多線程

剛開始我是採用這個方式,確實有些效果,可是效果還不是很明顯,而後我想到了一個新的方案,就是 http chunk + gzip,這個 swoole 自己是僅提供了chunk的支持,chunk+gzip須要本身實現,實現也很簡單架構

swoole_http_response->header('Content-Encoding', "gzip");

    $content = gzencode($content, 6);

    $arr = str_split($content, 1024);

    foreach ($arr as $v) {

        swoole_http_response->write($v);

    }

    swoole_http_response->end();

使用php壓縮相應內容,而後使用 swoole_http_response->write 分段發送,上線以後效果很明顯,耗時監控毛刺少了不少。socket

有些機智的同窗或許會有這個疑問,swoole http server 通常狀況下,會被 nginx 反向代理,nginx 廣泛會打開 gzip,那麼問題來了,swoole 把數據 gzip 了,nginx 會不會把數據二次壓縮。函數

固然不會了,這但是nginx,來,雖然nginx的文檔裏並無說明gzip不會被二次壓縮,可是我在源碼裏找到了相關邏輯優化

src/http/modules/ngx_http_gzip_filter_module.c,略去無關代碼,下面函數調用ngx_http_gzip_ok檢測是不是gzip

static ngx_int_t

ngx_http_gunzip_header_filter(ngx_http_request_t *r)

{

    ……

    if (!r->gzip_tested) {

        if (ngx_http_gzip_ok(r) == NGX_OK) {

            return ngx_http_next_header_filter(r);

        }

    } else if (r->gzip_ok) {

        return ngx_http_next_header_filter(r);

    }

    ……

}

src/http/ngx_http_core_module.c,略去無關代碼,ngx_http_gzip_ok根據http header檢測是不是gzip

ngx_int_t

ngx_http_gzip_ok(ngx_http_request_t *r)

{



    ……

    if (ae->value.len < sizeof("gzip") - 1) {

        return NGX_DECLINED;

    }

    ……

}

從上述兩塊代碼能夠看出,nginx 並不會對 gzip 的包二次壓縮。

因此,放心大膽的使用吧。

最後,雖然這篇文章,講的是針對swoole http server 作的一個優化,可是這個思路,對於其餘http server 也一樣適用。

更多架構、PHP、GO相關踩坑實踐技巧請關注個人公衆號:PHP架構師

相關文章
相關標籤/搜索