Openresty中的并发模型是什么?

kik*_*ito 14 concurrency lua nginx

我很难尝试围绕openresty(或nginx)的并发模型.我阅读了Lua变量范围,它解释了变量的生命周期,但它没有说明对它们的并发访问.

用文字解释很难,所以让我试着用代码来解释.想象一下,我有这个Lua模块:

local counter = {count = 0}

function counter.incr(amount)
  counter.count = counter.count + (amount or 1)
end

return counter
Run Code Online (Sandbox Code Playgroud)

然后我在openresty中使用它,如下所示:

server {
  location /incr {
    content_by_lua '
      local counter = require 'counter'
      counter.incr(1)
    '
  }
  location /decr {
    content_by_lua '
      local counter = require 'counter'
      counter.incr(-1)
    '
  }
  location /count {
    content_by_lua '
      local counter = require 'counter'
      ngx.write(counter.count)
    '
  }
}
Run Code Online (Sandbox Code Playgroud)

我想了解并发模型,所以我可以回答这些问题:

  • 如果我进行10次并发呼叫/incr,稍后我打电话/count,我可以确定结果是10(我假设不是,但为什么)?
  • 如果我同时进行10次并发呼叫,/incr同时再做10次/decr,我可以确定/count会返回0吗?
  • 工人数量如何影响结果?
  • 代码发生的阶段(即init_by_lua代替content_by_lua)会如何影响结果?

Pau*_*nko 15

nginx使用基于事件的体系结构,这意味着它使用一个带有事件循环的线程1,当它们准备好进行读取或写入时处理套接字.这意味着请求并非真正同时处理,但可以逐个快速处理多个请求,即使在存在任何套接字/ IO延迟的情况下,单个请求处理可能会有延迟.

如果我对/ incr进行10次并发调用,之后我调用/ count,我可以确定结果是10(我假设不是,但为什么)?

是.只要所有请求完成/count调用,结果将为10.假设已完成9个请求,但第10个请求由于某种原因被发送方延迟,并且如果在第10个请求由nginx处理之前处理,你应该得到9作为结果./incr/count

如果我对/ incr进行10次并发调用,同时我再做10次/ decr,我可以确定/ count会返回0吗?

是的,但不保证处理这些请求的顺序.请注意,在这种情况下,您不需要锁定您的状态或使用全局信号量或类似的东西.如果在读取状态和写入状态之间有一些I/O调用(因为在此期间可以处理不同的请求),您可能会遇到麻烦,但这不是您的示例所做的.

工人数量如何影响结果?

Lua实例在由同一工作进程处理的请求之间共享,因此多个工作者不会给您相同的结果.您的所有/incr请求都可以发送给一个工作者,但您的/count请求可以转到另一个工作者,使用另一个(仍然)count设置为0的Lua实例.如果需要在实例之间共享数据,则可能需要使用类似lua_shared_dict的内容.另请参阅其他选项的数据共享部分.

代码发生的阶段(即init_by_lua而不是content_by_lua)如何影响结果?

init_by_lua 仅在主进程加载配置文件时执行.

1我过于简单化,因为它可以分叉多个实例来处理多核系统和其他一些情况以及我记忆中的情况.

  • 谢谢@kikito; 前段时间我在 CS 课程中阅读了几篇关于 nginx 的论文。我对他们的事件驱动架构非常感兴趣,它可以用比其他线程/分叉服务器更少的资源提供更好的结果。 (2认同)