You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenResty在init_worker_by_lua中初始化MySQL报错如何解决

问题根因

你遇到的报错是因为init_worker_by_lua*上下文默认禁用了cosocket(即ngx.socket.tcp相关API),而lua-resty-mysql、lua-resty-redis的底层都依赖cosocket实现网络通信,所以直接在这个阶段调用new/connect方法就会触发API禁用的错误。


可行解决方案

方案1:基于ngx.timer的延迟初始化(预初始化场景推荐)

ngx.timer的回调上下文支持cosocket调用,你可以在init_worker阶段启动一个0延迟的定时器,把数据库连接初始化逻辑放到定时器回调中执行。

改后的db.lua示例代码:

local mysql = require("resty.mysql")
local redis = require("resty.redis")

-- 数据库初始化函数
local function init_db()
    local db, err = mysql:new() 
    if not db then
        ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
        return
    end
    db:set_timeout(3000) -- 设置连接超时时间
    local ok, err, errcode, sqlstate = db:connect{
        host = "127.0.0.1",
        port = 3306,
        database = "employee",
        user = "root",
        password = "password",
        charset = "utf8",
        max_packet_size = 1024 * 1024,
    }
    if not ok then
        ngx.log(ngx.ERR, "failed to connect mysql: ", err, " errcode: ", errcode)
        return
    end
    -- 连接成功后放入连接池复用
    local ok, err = db:set_keepalive(10000, 100)
    if not ok then
        ngx.log(ngx.ERR, "failed to set keepalive: ", err)
        return
    end

    -- Redis初始化逻辑和MySQL一致,此处省略
end

-- 启动0延迟定时器,worker进程启动后立刻执行初始化
local ok, err = ngx.timer.at(0, init_db)
if not ok then
    ngx.log(ngx.ERR, "failed to create init timer: ", err)
end

注意:init_worker阶段不能调用ngx.say这类请求输出API,所有日志输出必须用ngx.log写入错误日志。

方案2:请求侧懒加载(大多数场景推荐,稳定性更高)

不在服务启动阶段做数据库初始化,而是在第一次请求触发的时候初始化连接,之后将连接状态缓存起来,后续请求直接复用。

你可以把连接逻辑封装为独立工具模块db_utils.lua:

local mysql = require("resty.mysql")
local _M = {}

function _M.get_db_conn()
    -- 用模块级变量缓存连接,也可以用ngx.shared.DICT做跨请求缓存
    if _M.db_conn then
        return _M.db_conn
    end
    local db, err = mysql:new()
    -- 连接逻辑和方案1一致,连接成功后赋值给_M.db_conn即可
    -- 省略重复代码
    return db
end

return _M

之后在access_by_lua或者content_by_lua阶段调用require("db_utils").get_db_conn()获取连接即可。


注意事项

  • 多worker进程下,每个worker都会独立执行init_worker的逻辑,每个worker的连接都是独立的,符合OpenResty的进程模型
  • 数据库连接用完后要记得调用set_keepalive放到连接池复用,避免每次请求都新建连接造成性能损耗

内容的提问来源于stack exchange,提问作者rahul garg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 05:15:11