一、为什么需要性能调优
刚接触OpenResty的小伙伴可能会发现,同样的配置在不同服务器上表现差异很大。有时候明明服务器配置不错,但处理请求就是慢半拍。这就像买了辆跑车却开出了拖拉机的速度,问题往往出在默认配置没有根据实际场景优化。
举个例子,我们有个电商促销页面,用OpenResty做反向代理。默认配置下,当并发请求达到500时,响应时间就从50ms飙升到800ms。通过下面这个简单的测试就能发现问题:
# OpenResty配置示例
worker_processes auto; # 默认自动设置工作进程数
events {
worker_connections 1024; # 每个worker默认连接数
}
这个配置在4核服务器上会产生4个worker进程,每个进程处理1024个连接。看起来合理,但当突发流量来临时,连接队列可能瞬间被打满。
二、关键性能参数调优
1. 工作进程与连接数
首先要调整的是worker_processes和worker_connections。建议这样设置:
worker_processes 4; # 明确设置为CPU核心数
events {
worker_connections 4096; # 根据内存调整,每个连接约占用256KB内存
multi_accept on; # 允许一次性接受所有新连接
}
这里有个计算公式:最大并发 = worker_processes × worker_connections。比如4个worker各4096连接,就能支持约1.6万并发。
2. 连接池优化
HTTP连接的keepalive设置对性能影响很大:
http {
keepalive_timeout 65s; # 保持连接的超时时间
keepalive_requests 10000; # 单个连接最大请求数
upstream backend {
keepalive 256; # 连接池大小
server 127.0.0.1:8080;
}
}
3. 缓冲区设置
不合理的缓冲区会导致频繁的内存分配:
http {
client_body_buffer_size 1M; # 请求体缓冲区
client_header_buffer_size 8k; # 请求头缓冲区
large_client_header_buffers 4 16k; # 大请求头缓冲区
# 开启内存池复用
pool_size 4096k;
pool_initial_size 1024k;
}
三、Lua代码优化技巧
OpenResty的强大之处在于Lua脚本,但写得不好反而会成为性能瓶颈。
1. 避免全局变量
-- 不好的写法
count = 0 -- 全局变量性能差
-- 推荐写法
local count = 0 -- 局部变量访问更快
2. 使用共享内存
-- 初始化共享字典
local shared_data = ngx.shared.my_dict
-- 写入数据
shared_data:set("cache_key", "value", 60) -- 60秒过期
-- 读取数据
local value = shared_data:get("cache_key")
3. 协程优化
-- 串行请求示例
local res1 = ngx.location.capture("/api1")
local res2 = ngx.location.capture("/api2")
-- 并行请求优化
local thread1 = ngx.thread.spawn(function() return ngx.location.capture("/api1") end)
local thread2 = ngx.thread.spawn(function() return ngx.location.capture("/api2") end)
local res1, res2 = ngx.thread.wait(thread1, thread2)
四、实战调优案例
我们有个用户中心服务,原先平均响应时间120ms,经过以下优化降到45ms:
- 调整连接池大小:
upstream user_service {
keepalive 128;
server 10.0.0.1:8000;
server 10.0.0.2:8000;
}
- 增加缓存层:
local redis = require "resty.redis"
local red = redis:new()
-- 先查Redis缓存
local user_data, err = red:get("user:" .. user_id)
if user_data then
return user_data
end
-- 缓存未命中才查数据库
local db_res = ngx.location.capture("/db_query?user_id="..user_id)
red:set("user:"..user_id, db_res.body, "EX", 3600) # 缓存1小时
- 优化日志记录:
# 关闭不必要的访问日志
access_log off;
# 只记录错误日志
error_log /var/log/nginx/error.log warn;
五、常见问题排查
当遇到性能问题时,可以按这个顺序排查:
- 使用
ngx.status检查响应状态码 - 通过
ngx.now()和ngx.update_time()计算处理时间 - 检查共享内存使用情况:
local shdict = ngx.shared.my_dict
ngx.say("Free space: ", shdict:free_space())
- 监控系统负载:
# 查看系统负载
top -H -p `cat /usr/local/openresty/nginx/logs/nginx.pid`
六、调优后的效果评估
经过上述优化后,我们的测试结果如下:
- 平均响应时间从120ms降到45ms
- 99分位响应时间从800ms降到200ms
- 服务器负载从80%降到35%
- 单机QPS从2000提升到6000
七、注意事项
- 调优要循序渐进,每次只改一个参数并测试效果
- 生产环境要先在测试环境验证
- 监控系统指标至少包括:CPU、内存、网络IO、磁盘IO
- 不同业务场景的最佳配置可能不同
- 高并发下要特别注意TIME_WAIT状态的连接
八、总结
OpenResty的性能调优就像给汽车做改装,不是所有零件都需要换,关键是要找到瓶颈点。记住几个原则:
- 先测量再优化,用数据说话
- 从系统参数到业务代码层层深入
- 保持配置简单可维护
- 定期review性能指标
通过合理的配置和Lua代码优化,完全可以让OpenResty发挥出惊人的性能。希望这些实战经验能帮你少走弯路!
评论