一次openresty http.lua 性能调优之旅
2023-09-11 14:17:37 时间
最近要用Nginx lua进行http 数据交互,因此想到了resty/http.lua,因此开启一段性能调优之旅。
2 发送HTTP GET请求代码local ok, status, headers, code, body = hc:request { url = uri, method = "GET", }
很简单的一段代码,利用http.lua request 函数发送http get 请求并返回body及相关信息。
3 性能表现及现象在get 小文件的时候性能表现正常,符合预期,但是get 大文件的时候非常慢,在内网环境下GET 1个 1M左右的Object 竟然需要1s+,这性能实在不能忍,而且随着文件增大性能急剧下降。开始怀疑是不是http server 的原因,用wget 试了一下,发现很快,排除server的原因。百思不得其解后开始分析http.lua 代码
4 http.lua 分析这是Lua 读取http body 代码,可以看出这里有个fetch_size参数,从代码上看直观含义是一次从底层网络读上来数据块的大小
161 local function read_body_data(sock, size, fetch_size, callback) 162 local p_size = fetch_size 163 while size and size 0 do 164 if size p_size then 165 p_size = size 166 end 167 local data, err, partial = sock:receive(p_size) 168 if not err then 169 if data then 170 callback(data) --这里有个callback,下面看看是啥 171 end 172 elseif err == "closed" then 173 if partial then 174 callback(partial) 175 end 176 return 1 -- closed 177 else 178 return nil, err 179 end 180 size = size - p_size 181 end 182 return 1 183 end
看下fetch size 设置值是多少
nreqt.fetch_size = reqt.fetch_size or 16*1024
默认为16K
再看一下function read_body_data 在哪里调用的,参数callback 传又是什么
185 local function receivebody(sock, headers, nreqt) 186 local t = headers["transfer-encoding"] -- shortcut 187 local body = 188 local callback = nreqt.body_callback 189 if not callback then 190 local function bc(data, chunked_header, ...) 191 if chunked_header then return end 192 body = body .. data 193 end 194 callback = bc 195 end 196 if t and t ~= "identity" then 197 -- chunked 198 while true do 199 local chunk_header = sock:receiveuntil("\r\n") 200 local data, err, partial = chunk_header() 201 if not data then 202 return nil,err 203 else 204 if data == "0" then 205 return body -- end of chunk 206 else 207 local length = tonumber(data, 16) 209 -- TODO check nreqt.max_body_size !! 211 local ok, err = read_body_data(sock,length, nreqt.fetch_size, callback) 212 if err then 213 return nil,err 214 end 215 end 216 end 217 end 218 elseif headers["content-length"] ~= nil and tonumber(headers["content-length"]) = 0 then 219 -- content length 220 local length = tonumber(headers["content-length"]) 221 if length nreqt.max_body_size then 222 ngx.log(ngx.INFO, content-length nreqt.max_body_size !! Tail it !) 223 length = nreqt.max_body_size 224 end 226 local ok, err = read_body_data(sock,length, nreqt.fetch_size, callback) 227 if not ok then 228 return nil,err 229 end 230 else 231 -- connection close 232 local ok, err = read_body_data(sock,nreqt.max_body_size, nreqt.fetch_size, callback) 233 if not ok then 234 return nil,err 235 end 236 end 237 return body 238 end
这里可以看到我们的程序中没有传callback 进去,callback 默认是
190 local function bc(data, chunked_header, ...) 191 if chunked_header then return end 192 body = body .. data -- 注意这里会对每次接收到的body 进行拼接 193 end 194 callback = bc
分析到这里问题已经很明显了
fetch_size 是一次sock:receive 调用读上来的body 的size,每次读出来fetch_size 的body 后会回调默认callback 对body 进行拼接,如果文件size 很大而fetch size 很小就会造成因字符串拼接造成的CPU资源消耗及内存消耗。而我们的场景是需要缓存所有body后处理,所以一次读出越多body越好。
默认Callback是
if chunked_header then return end body = body .. data end``` 假设按照fetch size默认值16k 来算,get 1MB 文件光string 拼接就要进行64次,所以一次性接收所有body性能最佳,fetch_size 设置为1GB。(大家都知道字符串拼接需要额外内存分配会消耗大量CPU) ### 5 结论 fetch_size 设置太小导致大文件body 拼接次数过多导致,从我的场景来看要缓存所有body后才能进行下一步因此fetch_size 设置越大越好 修正后代码为:
url = uri, fetch_size = 1024*1024*1024, method = "GET", }```
注意:如果你的业务场景是需要流式处理或者转发这个值只需要将fetch_size 调整为一个合适的值即可。
用Go语言写HTTP中间件 在web开发过程中,中间件一般是指应用程序中封装原始信息,添加额外功能的组件。不知道为什么,中间件通常是一种不太受欢迎的概念。但我认为它棒极了。
01.Nginx基础Http原理 1.Http协议概述HTTP全称HyperText Transfer Protocol中文名为超文本传输协议1.什么是超文本?包含有超链接(Link)和各种多媒体元素标记的文本。这些超文本文件彼此链接,形成网状(Web),因此又被称为网页(Web Page)。这些链接使用URL表示。最常见的超文本格式是超文本标记语言HTML。html文件- 包含各种各样的元素(URL链接)- 形成web page简称web页面。2.那什么是URL,URL简称统一资源定位符。那URL的组成部分是由协议, 域名:端口, 路径和文件名3.那超文本传输http协议是什么?是一种按照URL指示,将超文本文档从一台主机(
1.HTTP的核心模块. 这些HTTP模块会在编译Nginx时自动编译进来,除非使用configure命令禁止编译这些模块. (1)alias指令. 该指令用于在URL和文件系统路径之间实现映射.
相关文章
- http和https的区别,HTTPS工作原理,状态码,cookie和session对于HTTP有什么用
- UE4/UE5 动画的原理和性能优化
- 基于MATLAB的无线信道性能仿真
- 性能测试必备技能:Prometheus监控平台搭建
- 使用 HTTP/2 提升性能的7个建议
- 《LoadRunner性能测试巧匠训练营》——3.3 场景监控实战
- SQL Server 2012使用OFFSET/FETCH NEXT分页及性能测试
- Web服务器性能/压力测试工具http_load、webbench、ab、Siege、loadrunner
- Http_4个新的http状态码:428、429、431、511
- Linux 性能监测:工具
- HTTP(http+抓包Fiddler+协议格式+请求+响应)
- Tomcat 8(十)HTTP/AJP Connector、Bio/Nio/Apr性能对照
- 计算机网络的特点及性能