一、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;
}

这个配置做了几个关键优化:

  1. 自动设置worker数量与CPU核心数匹配
  2. 调高了文件描述符和连接数限制
  3. 使用更高效的epoll事件模型
  4. 启用了TCP优化选项
  5. 配置了静态文件缓存

二、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性能调优主要适用于以下场景:

  1. 高并发API服务
  2. 实时数据处理管道
  3. 边缘计算节点
  4. 微服务网关
  5. 流量分析与监控系统

技术优点:

  • 极高的性能,可以轻松处理C10K问题
  • 灵活的Lua扩展能力
  • 丰富的生态系统和模块
  • 与Nginx生态无缝集成

注意事项:

  • Lua代码质量直接影响性能
  • 需要合理配置worker数量
  • 缓存策略需要精心设计
  • 连接池参数需要根据实际负载调整

总结来说,OpenResty性能调优是一个系统工程,需要从配置、代码、缓存、连接池等多个维度综合考虑。通过合理的优化,可以充分发挥OpenResty的高性能特性,构建出高效稳定的Web服务。