• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

Nginx Lua 原理

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

协程机制

  • 基于用户态模拟出来的独立的运行空间;
  • 协程依附于线程的内存模型,切换开销小;
  • 协程遇到阻塞就归还执行权限,协程的代码以完全同步的方式模拟异步的调用,编程很容易;
  • 协程本质上是在线程中串行执行的,对任何共享变量的访问无需加锁;

Nginx 协程

  • Nginx 的每一个 Worker 进程都是在 epoll 或 kqueue 这种事件模型之上,封装成协程;当一个 Socket 句柄接收到一个 HTTP Request 操作的时候,这个 epoll 对应的 Socket 就会被唤醒,此时 Nginx 会 new 出一个协程,这个协程会处理 HTTP Request 的完整生命周期,如果处理过程中没有发生阻塞,协程会返回 HTTP Response 给 Nginx 的 epoll 模型做 Socket 的write;一旦处理过程中有 Block 的操作,比如协程要将请求反向代理给后端服务器,等待后端服务器的返回,此时协程放弃自己的执行权限,并把和后端服务器的连接注册到 epoll 事件里,等待这个事件被后端服务器的 Response 唤醒,一旦该事件被唤醒之后,Nginx 的 Worker 进程又会重新 new 一个协程出来,做之后的事情;因此每个操作都不会 Block Worker 进程自身的操作,都是依赖 epoll 操作完成的;在整个的串行链路上,看上去就是几个协程串行在一起,完成一个请求的处理过程;
  • 每一个请求都有一个协程进行处理;
  • 即使 nginx_lua 需要执行 Lua,相对于 C 来说是有一定的开销,但依旧能保证高并发能力;

Nginx 的协程机制

  • Nginx 的每个 Worker 进程内部都创建了一个 Lua 虚拟机,用来跑 Lua 的脚本文件;
  • Worker 进程内的所有协程共享同一个 Lua 虚拟机;
  • 每一个请求由一个 Lua 协程处理,每个请求的之间的数据是隔离的;
  • Lua 代码调用 IO 等异步接口时,协程被挂起,上下文的数据保持不变;一个 HTTP 请求被一个协程处理,遇到 IO 阻塞的时候,在 epoll 模型上注册完,把自己挂起,等到 epoll 模型收到数据返回后,唤醒自己,执行下面的操作,因此,不同 HTTP 请求之间的数据是隔离的;Java 的 Servlet 是用一个线程处理一个 HTTP 请求;Nginx 的 Worker 进程是单线程模型的,其对 HTTP 请求的处理都是用协程完成的;Nginx 的协程遇到阻塞,依靠 epoll 模型解决;Java 中遇到阻塞就等待,因为本身就是多线程的模型;Nginx 的协程机制是比 Java Servlet 的多线程模型更加高效;
  • 协程遇到 IO 调用,自动保存,不阻塞 Worker 进程;
  • IO 异步操作完成后,还原协程上下文,代码继续执行;
  • Nginx 协程的好处是,在编写代码的时候,无需考虑异步的方式,完全可以以同步的方式编写;当协程运行的时候发生了阻塞,比如发起 IO 调用,会在 Nginx 的 epoll 的模型上注册一个回调的句柄,放弃自己的执行权限,当 epoll 模型接收到了阻塞调用的返回之后,会再将对应的协程唤醒,对应的协程代码就像同步调用一样,返回的时候已经获得了 CPU 的执行权限;

Lua 的协程机制

  • Lua 的协程机制和 Nginx 的是一样的,因此 Nginx 可以使用 Lua 作为插件模块,使用协程做对应的插件开发;

Nginx Lua 插载点

  • Nginx 提供了很多 Nginx Lua 的插载点,能够在 Nginx 的不同的生命阶段,完成 Lua 脚本插件式的加载,并执行对应的 Lua 程序,顺序如图:


    Nginx 的 Lua 挂载点.png
几个重要的插载点
  • init_by_lua:指定系统启动时调用的 Lua 脚本;
  • init_worker_by_lua:指定 Worker 进程启动时调用的 Lua 脚本;
  • set_by_lua:Nginx 变量使用复杂的 lua return;
  • rewrite_by_lua:指定重写 URL 规则的 Lua 脚本;
  • access_by_lua:指定权限验证阶段的 Lua 脚本;
  • content_by_lua:指定内容输出节点的 Lua 脚本;

Nginx 的处理阶段

  1. NGX_HTTP_POST_READ_PHASE = 0, // 读取请求头部
  2. NGX_HTTP_SERVER_REWRITE_PHASE // 执行 uri 的 rewrite,比如访问 /resources/ 的目录 rewrite 到 static 目录;
  3. NGX_HTTP_FIND_CONFIG_PHASE // 根据 uri 替换掉 location
  4. NGX_HTTP_REWRITE_PHASE // 根据替换结果继续执行 rewrite
  5. NGX_HTTP_POST_REWRITE_PHASE // 执行 rewrite 的后处理过程
  6. NGX_HTTP_PREACCESS_PHASE // 认证预处理,比如请求限制,连接限制
  7. NGX_HTTP_ACCESS_PHASE // 认证阶段,比如 token 操作可以从 Java 中移到 Nginx 的这个阶段
  8. NGX_HTTP_POST_ACCESS_PHASE // 认证后处理,如果认证不通过,就把包丢弃掉
  9. NGX_HTTP_TRY_FILES_PHASE // 尝试 try catch 的标签
  10. NGX_HTTP_CONTENT_PHASE // 内容处理,可以是返回静态内容,可以是做反向代理,也可以自己写 Lua 脚本返回固定的内容;
  11. NGX_HTTP_LOG_PHASE // 日志处理

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Step By Step(Lua数据结构)发布时间:2022-07-22
下一篇:
Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap