建议优化 Nginx 配置项 client_body_buffer_size,提高请求 body 读取效率。建议设置 client_body_buffer_size 64k。
更多
分析 resty.http 库源码,看是否能对读写进行优化;
预计很快 Openresty 的 API 就会支持 http2.0,到时候再替换回来;
附
问题相关代码片段
access_by_lua_block {
local http = require "resty.http"
local httpc = http.new()
httpc:set_timeout(300)
httpc:set_proxy_options({http_proxy = "http://127.0.0.1:9107"})
ngx.req.read_body()
local req_method = ngx.req.get_method()
local req_body = ngx.req.get_body_data()
local req_headers = ngx.req.get_headers()
local req_url = "http://" .. ngx.var.host .. "/__to_waf__" .. ngx.var.uri
if ngx.var.is_args == "?" then
req_url = req_url .. "?" .. ngx.var.query_string
end
local res, err = httpc:request_uri(req_url, {
version = 1.1,
method = req_method,
body = req_body,
headers = req_headers,
keepalive_timeout = 60,
keepalive_pool = 16,
})
if not res then
ngx.log(ngx.ERR, "failed to request: ", err, ". url: ", req_url)
return ngx.exit(ngx.OK)
end
local status = res.status or 0
local body = res.body
if status == 200 then
if not body or body == "" then
return ngx.exit(ngx.HTTP_CLOSE)
end
elseif status == 403 or status == 400 then
ngx.req.set_method(ngx.HTTP_GET)
return ngx.exec("/__waf_page__/" .. status .. ".html")
end
}
问题描述
某产品对接最新版 waf proxy(支持 http2.0)后,上传图片超时,其他请求正常。
问题分析
从 Nginx 的 error 和 access 日志发现,请求转发到 WAF 超时(超过 60 秒),导致客户端主动断开连接(499 状态)。 为了兼容 http2(构建子请求时,将http2 改写成 http1.1),我们使用开源库 resty.http 代替了原来 Openresty 原生的 API ngx.location.capture,性能下降很大,因为
ngx.location.capture
是 Nginx 子请求,本质上不是 http 请求,直接运行在 C 语言级别,效率非常高。当 POST body 数据较大时,这个库转发 的速度会非常慢,从而引起超时。经过多次对比测试发现,跟 client_body_buffer_size 设置的大小有关,当请求 body 大于
client_body_buffer_size
设置的值时,请求就会变得很慢,甚至超时;反之则正常。client_body_buffer_size
用来指定 Nginx 读取请求 body 的 buffer 大小值,默认是 8k(32位操作系统)当请求的 body 大于这个值,则会将剩余的字节写入本地文件(磁盘)。所以,根本原因是resty.http
库转发请求读写磁盘文件效率太低。解决方案
可以从两方面进行优化解决:
resty.http
转发的超时时间(httpc:set_timeout(300)
不超过 300 毫秒),因为是转发 WAF 是旁路
逻辑,可以避免转发 WAF 过慢影响客户正常业务请求。影响就是较大 body(大于client_body_buffer_size
设置大小) 不会经过 WAF 检测,其实,考虑到性能等问题,WAF 也基本不会处理较大 body (> 1M ) 。client_body_buffer_size
,提高请求 body 读取效率。建议设置client_body_buffer_size 64k
。更多
resty.http
库源码,看是否能对读写进行优化;附
问题相关代码片段