一、OpenResty基础配置调优
OpenResty本质上就是Nginx加Lua的扩展,所以基础配置优化要从Nginx配置入手。我们先来看一个典型的优化配置示例:
# 主进程配置
worker_processes auto; # 自动根据CPU核心数设置worker数量
worker_cpu_affinity auto; # CPU亲和性设置
worker_rlimit_nofile 65535; # 每个worker能打开的最大文件数
# 事件模块配置
events {
worker_connections 20480; # 每个worker的最大连接数
use epoll; # 使用epoll事件模型
multi_accept on; # 一次性接受所有新连接
}
# HTTP模块配置
http {
sendfile on; # 启用sendfile系统调用
tcp_nopush on; # 启用TCP_NOPUSH选项
tcp_nodelay on; # 禁用Nagle算法
keepalive_timeout 65; # 保持连接超时时间
keepalive_requests 1000; # 单个连接最大请求数
# 静态资源缓存
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
这个配置做了几个关键优化:
- 自动设置worker数量与CPU核心数匹配
- 调高了文件描述符和连接数限制
- 使用更高效的epoll事件模型
- 启用了TCP优化选项
- 配置了静态文件缓存
二、Lua代码层面的性能优化
OpenResty的强大之处在于可以用Lua扩展功能,但Lua代码写不好也会成为性能瓶颈。下面看几个常见的优化点:
-- 1. 避免在热路径中创建临时表
-- 不好的写法:每次请求都创建新表
local function process_request()
local headers = {} -- 每次创建新表
-- 处理逻辑
end
-- 好的写法:复用表
local headers = {} -- 在外部创建
local function process_request()
table.clear(headers) -- 清空复用
-- 处理逻辑
end
-- 2. 字符串拼接优化
-- 不好的写法:使用..拼接大量字符串
local function build_html()
local html = ""
for i = 1, 1000 do
html = html .. "<div>" .. i .. "</div>"
end
return html
end
-- 好的写法:使用table.concat
local function build_html()
local parts = {}
for i = 1, 1000 do
parts[#parts + 1] = "<div>" .. i .. "</div>"
end
return table.concat(parts)
end
-- 3. 使用FFI调用C函数
local ffi = require "ffi"
ffi.cdef[[
int memcmp(const void *s1, const void *s2, size_t n);
]]
local function fast_compare(a, b)
return ffi.C.memcmp(a, b, #a) == 0
end
三、缓存策略的优化
缓存是性能优化的银弹,OpenResty中我们可以利用多种缓存机制:
-- 1. 共享字典缓存
local shared_cache = ngx.shared.my_cache
-- 写入缓存
local success, err = shared_cache:set("key", "value", 60) -- 60秒过期
if not success then
ngx.log(ngx.ERR, "failed to set cache: ", err)
end
-- 读取缓存
local value = shared_cache:get("key")
-- 2. LRU缓存
local lrucache = require "resty.lrucache"
local cache, err = lrucache.new(200) -- 最多缓存200个对象
if not cache then
ngx.log(ngx.ERR, "failed to create cache: ", err)
end
-- 使用缓存
cache:set("key", "value")
local value = cache:get("key")
-- 3. 多级缓存策略
local function get_data(key)
-- 1. 先查本地缓存
local value = cache:get(key)
if value then return value end
-- 2. 查共享字典
value = shared_cache:get(key)
if value then
cache:set(key, value) -- 回填本地缓存
return value
end
-- 3. 查后端服务
value = query_backend(key)
if value then
-- 同时写入两级缓存
shared_cache:set(key, value, 300)
cache:set(key, value)
end
return value
end
四、连接池与上游服务优化
与上游服务(如数据库、API)的交互是常见瓶颈,连接池可以显著提升性能:
-- 1. MySQL连接池配置
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
return
end
db:set_timeout(1000) -- 1秒超时
local ok, err, errcode, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "test",
user = "test",
password = "test123",
max_packet_size = 1024 * 1024,
pool = "my_pool", -- 连接池名称
pool_size = 100, -- 连接池大小
}
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err, ": ", errcode, " ", sqlstate)
return
end
-- 使用后放回连接池
local function close_db(db)
if db then
db:set_keepalive(10000, 100) -- 空闲10秒,最大100个连接
end
end
-- 2. Redis连接池
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000) -- 1秒超时
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.ERR, "failed to connect to redis: ", err)
return
end
-- 配置连接池参数
red:set_keepalive(10000, 100) -- 空闲10秒,最大100个连接
五、高级优化技巧
最后分享几个高级优化技巧:
-- 1. 使用Light Threads处理并发
local function fetch_multiple_urls(urls)
local threads = {}
for i, url in ipairs(urls) do
threads[i] = ngx.thread.spawn(function()
local res = ngx.location.capture("/proxy", {args = {url = url}})
return res.status, res.body
end)
end
local results = {}
for i, thread in ipairs(threads) do
local ok, status, body = ngx.thread.wait(thread)
if ok then
results[i] = {status = status, body = body}
end
end
return results
end
-- 2. 动态加载Lua代码
-- 在init_by_lua阶段预加载模块
local my_module = require "my_module"
-- 在content_by_lua阶段可以这样热更新代码
package.loaded["my_module"] = nil -- 清除缓存
my_module = require "my_module" -- 重新加载
-- 3. 使用JIT编译优化热点代码
-- 在nginx.conf中添加:
-- lua_code_cache on;
-- 在Lua代码中可以这样:
jit.on() -- 开启JIT编译
jit.off() -- 关闭JIT编译
jit.flush() -- 清空JIT缓存
-- 4. 使用FFI优化性能关键路径
local ffi = require "ffi"
ffi.cdef[[
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len);
]]
local function fast_crc32(data)
return tonumber(ffi.C.crc32(0, data, #data))
end
应用场景与总结
OpenResty性能调优主要适用于以下场景:
- 高并发API服务
- 实时数据处理管道
- 边缘计算节点
- 微服务网关
- 流量分析与监控系统
技术优点:
- 极高的性能,可以轻松处理C10K问题
- 灵活的Lua扩展能力
- 丰富的生态系统和模块
- 与Nginx生态无缝集成
注意事项:
- Lua代码质量直接影响性能
- 需要合理配置worker数量
- 缓存策略需要精心设计
- 连接池参数需要根据实际负载调整
总结来说,OpenResty性能调优是一个系统工程,需要从配置、代码、缓存、连接池等多个维度综合考虑。通过合理的优化,可以充分发挥OpenResty的高性能特性,构建出高效稳定的Web服务。
评论