如何在后台开启轻量级线程完成定时任务?

Question:

现在有一个场景:需要定时(30s)从redis里面拉取数据灌入 lua cache 共享内存。我现在是用 ngx.timer 这个 API 来实现的,请问这会不会有问题?因为对 ngx.timer 这个 API 不是很了解看了文档说是:在后台开启了一个轻量级线程来执行,与原来的请求脱钩。场景需求是拉取灌入的操作不能阻塞 worker 。

  1. 请问这样能够满足需求吗?会不会有阻塞问题?
  2. ngx.timer 我现在是放在 content_by_lua_file 中的,需要访问接口才能启动,有没有可以开启 worker 的时候就启动 timer 的办法(我试了放在 init_by_lua_file 里面好像不生效。。。)
  3. 这个 timer 是每个 worker 里面都会有还是只有一个 worker 里面会有呢?(看文档貌似是只有一个 worker 里面会有,这也是我的需求)

Answer:

  1. 请问这样能够满足需求吗?会不会有阻塞问题?

    只要使用的都是 OpenResty 的 API 和库,是不存在阻塞问题的。只要大体确认一下当前 nginx 进程负载压力不要太高,能够确定获取到工作时间片即可。

  2. 有没有可以开启 worker 的时候就启动 timer 的办法 。。。

    其实这里你已经点出关键字了,借助 init_worker_by_lua 即可。

  3. 这个 timer 是每个 worker 里面都会有还是只有一个 worker 。。。

    通过 init_worker_by_lua 启动的 ngx.timer 是对每个 worker 的。如果这里需要控制 timer 的存在数量,可以借助 ngx.worker.id 完成 ngx.timer 数量控制,比如只启动一个或多个,并让他们确定绑定在哪个 worker 上。

如何使用 os.getenv 获取系统环境变量

Question: 如题

Answer:

如果你想在 Lua 中通过标准 Lua API os.getenv 来访问系统环境变量,例如 foo , 那么你需要在你的 nginx.conf 中,通过 env 指令,把这个环境变量列出来。 例如:

env foo;

lua-resty-mongol3 用户名、密码验证部分占用时间过长

Question

这个库的使用流程大致如下:

1. 创建一个 mongo 对象(local conn =mongo:new())
2. 创建一个连接 mongodb(conn:connect("192.168.1.254",27017))
3. 选择数据库(local db = conn:new_db_handle("openresty"))
4. 然后 auth 验证(db:auth_scram_sha1("username","password"))
5. 接收数据执行 insert 操作
6. 放入连接池(conn:set_keepalive(10000, 100))

主要问题是用户登录部分占用将近 1/3 的时间,这个合理么?如何优化?

Answer

为了回答上面的问题,我们先粗略整理一下数据库连接池的通常做法,看下面流程图:

主要区别:如何减少不必要的用户验证过程,合理高效的复用已有连接。其实对于已经验证过的连接,直接使用即可。

比较推荐的改进方法,参考 lua-resty-mysql 的实现,对不同 ip、port、db、user、password 绑定不同的连接池名字,让不同连接目的连接归类存放,并在数据库层直接完成用户验证动作。

OpenResty 中不能被 jit 编译的地方有日志提示吗?

Question:如题

Answer:

是可以借用 jit.v 或者 jit.dump 这两个 lua 模块可以输出 NYI 等日志。它们都是 luajit 自带的标准模块,在针对 jit 编译器做 lua 代码优化时,这两个模块之一是必须的。具体用法可以参考 lua-resty-core 项目的测试集。

jit.dump 输出的信息最详尽,从 trace 的 bc 到 ir 再到 mcode,jit.v 则比较简略。书鑫老师正在做一个更好的 luajit IR dumper,jit.dump 目前输出的 IR 列表不够直观,不够友好。书鑫老师的 IR 输出看着像高级语言伪码。

引用一下 lua-resty-core/t/md5.t 的第一个测试用例,为了突出重点,这里做了一下节选:

our $HttpConfig = <<_EOC_;
    lua_package_path "$pwd/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;";
    init_by_lua '
        local v = require "jit.v"
        v.on("$Test::Nginx::Util::ErrLogFile")
        require "resty.core"
    ';
_EOC_

__DATA__

=== TEST 1: set md5 hello
--- http_config eval: $::HttpConfig
--- config
    location = /md5 {
        content_by_lua '
            local s
            for i = 1, 100 do
                s = ngx.md5("hello")
            end
            ngx.say(s)
        ';
    }
--- request
GET /md5
--- response_body
5d41402abc4b2a76b9719d911017c592
--- error_log eval
qr/\[TRACE   1 content_by_lua\(nginx\.conf:\d+\):3 loop\]/
--- no_error_log
[error]

解释一下,对是否执行了 LuaJIT 优化编译,最后是通过 error_log eval 这个小节匹配确定的。这是预期的一条被 JIT 优化编译的日志输出结果。

而对于没有被 JIT 编译优化,是有下面类似日志输出的,会出现 NYI(Not Yet Implemented) 关键字,比如下面:

[TRACE --- db_base.lua:247 -- NYI: bytecode 51 at db_base.lua:252]

有兴趣的同学,可以自己玩下 jit.dump ,对汇编比较了解的同学,有惊喜哦。

results matching ""

    No results matching ""