最近做了一个需求,对供应商报表系统导出文件进行RMS加密,同时还需要记录用户下载日志,该需求主要在openresty实现。RMS加密是核心功能,日志是附加功能,如果将2者同步处理,记录日志会影响到用户导出文件,因此需要在openresty使用异步方式调用日志api接口。
1.nginx conf配置文件
user nobody;
worker_processes auto;
worker_cpu_affinity auto;
pcre_jit on;
error_log logs/error.log error;
worker_rlimit_nofile 30000;
worker_shutdown_timeout 200s;
pid logs/nginx.pid;
events {
use epoll;
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
server_tokens off;
underscores_in_headers on;
keepalive_timeout 10;
send_timeout 60;
lua_socket_log_errors off;
resolver 10.1.1.1;
#共享内存,作为消息队列
lua_shared_dict log_list 16m;
init_by_lua_block {
#启动特权进程
assert(require("ngx.process").enable_privileged_agent())
}
init_worker_by_lua_block {
#特权进程启动定时器
if require("ngx.process").type() == "privileged agent" then
local file_download = require "resty.file_download"
file_download.work_init()
ngx.log(ngx.ERR, "start the worker_timer!!!")
end
}
include /usr/local/openresty/nginx/conf/online/*.conf;
include /usr/local/openresty/nginx/conf/servers/*.conf;
}
2.写入api接口
location / {
proxy_pass http://10.1.1.1:8080;
log_by_lua_block {
local file_download = require "resty.file_download"
local file_info = file_download.get_filename()
local origin_filename = file_info[1]
local file_type = file_info[2]
local username = file_download.get_username_sap()
if not username then
username = ""
end
local cjson = require 'cjson'
local log_url = "https://abc.cn/def/insert_log"
local log_header = {}
log_header["Download-Log"] = "0123456789abcdef"
local log_body = {}
log_body["time"] = ngx.localtime()
log_body["fileName"] = origin_filename
log_body["fileType"] = file_type
log_body["fileSize"] = ngx.var.body_bytes_sent
log_body["downloadAccount"] = username
local clientIP = ngx.var.remote_addr
if not clientIP then
clientIP = ""
end
log_body["clientIp"] = clientIP
log_body["isEncrypted"] = 0
local json_body = cjson.encode(log_body)
if json_body and #json_body > 0 then
log_header["Content-Length"] = #json_body
end
--共享内存
local log_list = ngx.shared.log_list
local param = {log_url, json_body, log_header}
local param_json = cjson.encode(param)
--放入消息队列,“1” 相当于topic
log_list:lpush("1", param_json)
ngx.log(ngx.ERR, "push message :" .. param_json)
}
}
3.消费数据调用api
local function log_handler(premature)
if premature then
return
end
ngx.log(ngx.ERR, "now in log_handler!")
while (true) do
--从消息队列取出消息
local param_json = log_list:rpop("1")
if param_json then
ngx.log(ngx.ERR, "pop message :" .. param_json)
local param = cjson.decode(param_json)
--调用接口api
local log_client = http_client.post_json(param[1], param[2], param[3])
http_client.receive_all(log_client)
end
ngx.sleep(0.2)
end
end
function _M.work_init()
local oka, erra = ngx.timer.at(0, log_handler)
if not oka then
ngx.log(ngx.ERR, "failed to run timer-at task " .. erra)
return
end
end
需要注意的是,上面的消息队列使用nginx共享内存,没有进行持久化。