一、为什么需要性能调优

刚接触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:

  1. 调整连接池大小:
upstream user_service {
    keepalive 128;
    server 10.0.0.1:8000;
    server 10.0.0.2:8000;
}
  1. 增加缓存层:
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小时
  1. 优化日志记录:
# 关闭不必要的访问日志
access_log off;

# 只记录错误日志
error_log /var/log/nginx/error.log warn;

五、常见问题排查

当遇到性能问题时,可以按这个顺序排查:

  1. 使用ngx.status检查响应状态码
  2. 通过ngx.now()ngx.update_time()计算处理时间
  3. 检查共享内存使用情况:
local shdict = ngx.shared.my_dict
ngx.say("Free space: ", shdict:free_space())
  1. 监控系统负载:
# 查看系统负载
top -H -p `cat /usr/local/openresty/nginx/logs/nginx.pid`

六、调优后的效果评估

经过上述优化后,我们的测试结果如下:

  • 平均响应时间从120ms降到45ms
  • 99分位响应时间从800ms降到200ms
  • 服务器负载从80%降到35%
  • 单机QPS从2000提升到6000

七、注意事项

  1. 调优要循序渐进,每次只改一个参数并测试效果
  2. 生产环境要先在测试环境验证
  3. 监控系统指标至少包括:CPU、内存、网络IO、磁盘IO
  4. 不同业务场景的最佳配置可能不同
  5. 高并发下要特别注意TIME_WAIT状态的连接

八、总结

OpenResty的性能调优就像给汽车做改装,不是所有零件都需要换,关键是要找到瓶颈点。记住几个原则:

  1. 先测量再优化,用数据说话
  2. 从系统参数到业务代码层层深入
  3. 保持配置简单可维护
  4. 定期review性能指标

通过合理的配置和Lua代码优化,完全可以让OpenResty发挥出惊人的性能。希望这些实战经验能帮你少走弯路!