如果在log_by_lua_block 阶段放上死循环代码会咋样?

1
2
3
4
        log_by_lua_block {
            while true do
            end
        }

查阅资料话你可能会看到这么一句解释:

log Phase这个阶段,就是openresty能处理的最后阶段。到这个阶段的时候,实际上请求的响应已经发送给客户端了。另外我也测试过了,即使在这个阶段发生了错误,如 io 错误,也不会影响接口的正常响应,所以使用 log_by_lua 很是符合需求。

看到这里你是不是会觉得对上边的问题已经有答案了呢?

openresty_phases

起初我片面的以为log phase是一个请求的最后一个阶段就可以放飞了,不用太关注性能和耗时问题。

这当然是不对的,要搞清楚它的话就得理解Nginx的事件处理和Lua协程机制。

OpenResty架构

openresty arc

OpenResty的Master和Worker进程中都包含一个LuaJIT 虚拟机,

  • 有请求过来时,通过抢占锁,由一个worker进程来跟进处理;
  • worker进程内部会创建一个lua协程并与该请求绑定,也就是说一个请求对应一个lua协程;

因为worker是单线程的,在同一时间每个worker只能有一个占用CPU时间正在运行着的Lua协程,因此同一时刻每个worker只能处理一个请求。 这时你可能会有疑问了:既然同一个时刻只能处理一个请求,那nginx又是如何支持高并发的呢? 实际上Nginx是通过epoll事件驱动机制,当需要等待io时,协程主动让出cpu让其它协程占用cpu运行,继续处理其它请求,因为足够快话看起来就像并发的一样。不同于其它的多线程模式,一个请求对应一个线程,在高并发的情况占用资源也少很多。

OpenResty协程类型

在OpenResty层面,Lua协程和Nginx事件机制相互配合,当lua需要等待io时主动yield让出cpu并添加一个event到Nginx,等待io满足后再resume继续执行。

nginx event

到此我们也能看出,无论在哪个Phase lua程序都必须尽可能的快,更不能有阻塞操作,否则就会影响吞吐量。

OpenResty协程类型

  • 全局主协程
  • 请求子协程
  • 用户创建的"Light threads"

它们的调度关系可以参考下面这张图

nginx coroutine

使用 ngx.exit, ngx.exec, ngx.redirect 可以直接跳出协程,而不用等待子协程处理完成。

1
2
3
4
5
6
7
ngx.exec("/a/b/c") 			-- 内部跳转,直接从子协程结束,回到主协程
ngx.redirect("/foo", 301) 	-- 重定向,终止的当前请求的处理,即不再处理后续阶段

ngx.exit 可接受多种参数:
ngx.exit(ngx.OK) 		-- 完成当前阶段(退出子协程),继续下一个阶段
ngx.exit(ngx.ERROR)		-- 中断当前请求,报错
ngx.exit(HTTP_STATUS)	-- 结束 content 阶段,继续下个阶段

返回值说明

  • NGX_DONE 处理告一段落(子协程完成),还有协程(light thread)被挂起
  • NGX_AGIN 子协程未结束,继续等待下次唤醒重入
  • NGX_OK 当前阶段处理完成(子协程和运行在内的所有 light thread 都结束)

总结

OpenResty将Nginx的事件驱动机制与Lua结合,实现了以同步的方式写代码而有异步功能的效果,又因为是单线程,也不用担心并发时竞争问题,极大的提升了开发效率。 不过需要注意的是,协程并抢占式,因此写代码时要避免阻塞和尽快完成,否则会长期占用CPU而不能处理后续请求,影响整个吞吐量。

参考

https://time.geekbang.org/column/article/102113

https://github.com/jinhailang/blog/issues/26

https://github.com/jinhailang/blog/issues/21

https://github.com/jinhailang/blog/issues/32

https://my.oschina.net/u/2539854/blog/853012

https://groups.google.com/g/openresty/c/2UXtJHvSpXM/m/ZyLdtKwBAAAJ?pli=1

https://cloud.tencent.com/developer/article/1904796

https://forum.openresty.us/d/3375-e77210525689e3d3753440fe8db56d97/4