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

如何在OpenResty中获取ngx.var.bytes_sent并存入Redis?

问题解决方案

原因分析

  • access_by_lua_file阶段在请求刚进入时执行,此时响应还未生成和发送,ngx.var.bytes_sent自然为0,无法获取实际发送的字节数。
  • log_by_lua_file阶段在响应完全发送后执行,能拿到正确的bytes_sent,但该阶段默认禁止阻塞IO操作(如Redis的同步连接),直接使用resty.redis的同步方法会失败。

具体解决步骤

1. 修改Lua脚本,用定时器异步执行Redis操作

把Redis的连接和存储逻辑放到ngx.timer.at的回调函数里,定时器会在独立协程中执行,不受log阶段的阻塞限制:

local function save_bytes_sent(premature, bytes_sent, uri)
    if premature then
        return
    end

    local redis = require "resty.redis"
    local red = redis:new()
    red:set_timeout(1000)

    local ok, err = red:connect("172.20.0.2", 6379)
    if not ok then
        ngx.log(ngx.CRIT, "Failed to connect to redis: ", err)
        return
    end

    local res, err = red:set("bytes_sent_" .. uri, bytes_sent)
    if not res then
        ngx.log(ngx.CRIT, "Failed to save bytes_sent in redis: ", err)
        red:close()
        return
    end

    -- 可选:用连接池替换直接关闭,提升性能
    local ok, err = red:set_keepalive(10000, 100)
    if not ok then
        ngx.log(ngx.CRIT, "Failed to set keepalive: ", err)
        red:close()
        return
    end

    ngx.log(ngx.CRIT, "Saved bytes_sent in redis successfully")
end

-- 在log阶段触发定时器,传入所需参数
local bytes_sent = ngx.var.bytes_sent
local uri = ngx.var.uri
local ok, err = ngx.timer.at(0, save_bytes_sent, bytes_sent, uri)
if not ok then
    ngx.log(ngx.CRIT, "Failed to create timer: ", err)
    return
end

2. 修改nginx.conf配置,切换到log阶段执行脚本

把原来的access_by_lua_file替换为log_by_lua_file,让脚本在响应发送完成后执行:

location / {
    log_by_lua_file /test.lua;
}

内容的提问来源于stack exchange,提问作者Esmail Ebrahimi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 15:36:15