對(duì) gateway (commit id = 8ef7a8f2185c41777) 壓測(cè)時(shí)采集火焰圖,壓測(cè)前需配置 lua_code_cache=on,使用網(wǎng)關(guān)默認(rèn)路由,不配置插件,
qps 如下:

采集得到的火焰圖如下:

一、找出火焰圖的平頂
火焰圖就是看頂層的哪個(gè)函數(shù)占據(jù)的寬度最大。只要有平頂,就表示該函數(shù)可能存在性能問題
從火焰圖中可以看出,apirouter.lua存在比較耗時(shí)的調(diào)用 lj_str_new, 這一般是由于字符串操作導(dǎo)致的

逐步注釋字符串相關(guān)代碼進(jìn)行火焰圖分析,發(fā)現(xiàn)是由紅框標(biāo)識(shí)代碼導(dǎo)致,而ngx.re.match函數(shù)本身可以被jit,沒有更優(yōu)的替代方法,

從另一方面考慮,可能是由于ngx.re.match調(diào)用次數(shù)過多導(dǎo)致,通過代碼統(tǒng)計(jì),因?yàn)槠ヅ涞氖悄J(rèn)路由,這段函數(shù)總計(jì)調(diào)用了270次,
修改代碼直接路由到默認(rèn)路由,得到了如下數(shù)據(jù):


從圖中可以看出,相關(guān)耗時(shí)調(diào)用已經(jīng)消失,qps有所增加,但實(shí)際代碼中顯然不能如此修改。
項(xiàng)目使用遍歷所有路由進(jìn)行轉(zhuǎn)發(fā)的算法,算法復(fù)雜度為O(n),比較耗時(shí),關(guān)于路由算法,后面專門進(jìn)行分析。
二、觀測(cè)每個(gè)業(yè)務(wù)函數(shù)的寬度( 基于on-cpu-flame(2) )
從火焰圖中可以看出,耗時(shí)比較長(zhǎng)的調(diào)用有
1、content_by_lua 階段
(1)網(wǎng)關(guān)返回的response

從中可以看出,存在字符串操作 lj_str_new,由于.. 操作符每次都會(huì)新申請(qǐng)臨時(shí)空間來拼接字符串,利用table.concat去掉所有臨時(shí)空間的申請(qǐng)和GC


(2) 網(wǎng)關(guān)轉(zhuǎn)發(fā)至上游的 request 和 response
從圖中可以看出轉(zhuǎn)發(fā)耗時(shí)主要是在發(fā)送和接收中,這也是整個(gè)請(qǐng)求生命周期中最耗時(shí)的操作

其中每個(gè)請(qǐng)求都對(duì)請(qǐng)求體進(jìn)行json解析比較耗時(shí),這個(gè)后期可以考慮優(yōu)化

2、log_by_lua 階段
記錄metrics最為耗時(shí),暫沒發(fā)現(xiàn)優(yōu)化空間
記錄log,由于現(xiàn)在是每個(gè)請(qǐng)求的日志都立即記錄,操作過于頻繁,可以累積一定日志后再進(jìn)行記錄

優(yōu)化后qps明顯提高

3、rewrite_by_lua 階段
沒有發(fā)現(xiàn)優(yōu)化空間

4、uuid
生成uuid比較耗時(shí),暫無(wú)優(yōu)化
