如何在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
相关产品推荐
相关产品推荐

