对 gateway (commit id = 8ef7a8f2185c41777) 压测时采集火焰图,压测前需配置 lua_code_cache=on,使用网关默认路由,不配置插件,
qps 如下:
采集得到的火焰图如下:
一、找出火焰图的平顶
火焰图就是看顶层的哪个函数占据的宽度最大。只要有平顶,就表示该函数可能存在性能问题
从火焰图中可以看出,apirouter.lua存在比较耗时的调用 lj_str_new, 这一般是由于字符串操作导致的
逐步注释字符串相关代码进行火焰图分析,发现是由红框标识代码导致,而ngx.re.match函数本身可以被jit,没有更优的替代方法,
从另一方面考虑,可能是由于ngx.re.match调用次数过多导致,通过代码统计,因为匹配的是默认路由,这段函数总计调用了270次,
修改代码直接路由到默认路由,得到了如下数据:
从图中可以看出,相关耗时调用已经消失,qps有所增加,但实际代码中显然不能如此修改。
项目使用遍历所有路由进行转发的算法,算法复杂度为O(n),比较耗时,关于路由算法,后面专门进行分析。
二、观测每个业务函数的宽度( 基于on-cpu-flame(2) )
从火焰图中可以看出,耗时比较长的调用有
1、content_by_lua 阶段
(1)网关返回的response
从中可以看出,存在字符串操作 lj_str_new,由于.. 操作符每次都会新申请临时空间来拼接字符串,利用table.concat去掉所有临时空间的申请和GC
(2) 网关转发至上游的 request 和 response
从图中可以看出转发耗时主要是在发送和接收中,这也是整个请求生命周期中最耗时的操作
其中每个请求都对请求体进行json解析比较耗时,这个后期可以考虑优化
2、log_by_lua 阶段
记录metrics最为耗时,暂没发现优化空间
记录log,由于现在是每个请求的日志都立即记录,操作过于频繁,可以累积一定日志后再进行记录
优化后qps明显提高
3、rewrite_by_lua 阶段
没有发现优化空间
4、uuid
生成uuid比较耗时,暂无优化