一 如何在nginx中嵌入lua代码
说明: 本文只是从'全局'的'科普角度'来认识,更多的是'概念',把握'框架脉络'即可
① openresty官方提供lua代码嵌入指令图
1) openresty最大的'优势'可以让'lua代码'来控制'处理请求'的流程
理解: 类比'web'容器
2) lua代码和nginx.conf的配置指令是'完全不同'的
核心: 怎样把'lua代码'嵌入到'nginx.conf的指令'中
介绍: 相应的openresty提供的'lua'关联指令
备注: 主要介绍'ngx_http_lua_module'提供的'指令'
后续: ngx_lua 模块提供的'Directive 指令'和API等
Secure Request : '黄色'的框'不是指令',表示请求来的时候进行判'是否是ssl'
+++++++++++++ "要把握两点" +++++++++++++
1) lua在nginx的'哪些阶段'可以执行代码? --> '四个阶段'
2) lua在nginx的每个阶段可以执行'哪些操作'? --> '涉及指令'
解耦: nginx的'11个'执行阶段,'每个阶段'都有自己能够'执行的指令',并可以实现'不同的功能'
② 在启动过程中嵌入lua代码
1、init_by_lua* '指令集' --> 有三种格式的指令 '引号'、{}、'文件名'
1) 在init_by_lua*阶段,openresty是在'主协程'中通过'lua_pcall'直接'执行'lua代码
2) init_by_lua 是在 'Lua VM 虚拟机 创建后'调用的
运行时机: 每当 nginx '加载配置文件'时,都会创建一个'新的 Lua VM',在该'VM'中执行
通俗: 压根就'没有到'server和location层面,是http的context,是'master进程'中跑的
3) 在'start'、'reload'、'rsetart'都会执行
备注: lua_shared_dict的内容'不会'在reload时'被清除'
补充:HUP reload 只是更新'配置和 Lua 代码',同时也'不会丢弃共享内存中'已有的数据
细节: 不管是'-s stop|reload'都会'读取'配置文件,都会创建一个'新的Lua VM',但是很快丢弃
4) init_by_lua是Nginx配置加载的阶段,很多Nginx API for Lua命令是不支持的
备注: 目前已知支持的'nginx API for Lua'的命令有ngx.log、'ngx.shared.DICT'、print
5) 场景:
[1]、'init初始化'一些'耗时模块',尤其是'对CPU消耗较多'的功能
[2]、模块的'预'加载,做一些'全局'初始化配置 -->mysql、redis'初始化等'
[3]、初始化'lua_shared_dict'共享内存的数据
nginx -s reload时,init_by_lua中的代码被执行了2次
init_worker_by_lua 中设置死循环reload后导致worker进程无法退出
lua_by_init 里面怎么判断是在nginx -t过程执行,还是真正启动的时候执行
2、init_worker_by_lua* '指令集'
[1]、特点:
1) '每个'worker进程'创建时'都会执行lua代码
[2]、应用场景:
2) ngx.timer.every '配合'init_worker_by_lua*阶段可完成'定时任务'初始化
方式1: 如果'多worker',通过'if 0 == ngx.worker.id()'判断是保证只初始化一次
常见: 定时'拉取'服务器配置
2) resty.upstream.healthcheck --> 动态进行后端'健康检查' --> 如'心跳'检查
③ 在11个阶段的6个阶段嵌入lua代码
http的11个阶段嵌入的lua代码 'VS' 对比原生nginx 11阶段对应的指令
细节1: set_by_lua_*和rewrite_by_lua_*在同一个'阶段'有'先后'顺序的
原因:
1) set_by_lua* 是放到'官方'的ngx_http_rewrite_module模块中的'脚本指令'中
2) rewrite_by_lua*作为'独立的模块'执行的
3) 二者都归属于'rewrite阶段',但是'rewrite_by_lua*'是在'靠后'的位置
4) rewrite_by_lua*'总是'在标准ngx_http_rewrite_module的 '后面'
案例1: rewrite break,进入'post_rewrite'阶段,rewrite_by_lua*就是'rewrite tail'工作
案例2: if 是rewrite_by_lua'之前' 执行的
细节2: content handler 只能'注册一个'
备注: proxy_paas 、echo'可以有多个echo'、'content_y_lua*'同时出现
特点: 服务启动'不报错',但是只有一个'生效',一般后者会'覆盖'前者
补充: 如果是'upstream'反向代理,一般是'proxy_paas',通过balance_by_lua*控制选择上游服务
content 阶段有两种:
1) 加入到静态'模块' --> root、alias、index、static、gzip_static模块'依次执行'
2) 反向代理,'独占'形式 --> content_by_lua*与其它类似'反向代理模块'都是'独占'的
细节3:对于'content生成的响应'加工,'先处理header|后处理body'的filter加工
遗留:log_by_lua*有哪些'应用场景'?
1) openresty有哪些自身'特殊'的变量 :$prefix
2) openresty如何引入'nginx'的内置变量:ngx.var --> 使用"."或"[]",建议'local'本地存储
④ 控制rewrite/access是否延迟执行lua代码
遗留:rewrite_by_lua_no_postpone只能控制'rewrite_by_lua',还是所有的'*'?
⑤ 在过滤响应和负载均衡时嵌入lua代码
1) balance_by_lua*
说明: 为了深入学习'balance_by_lua*'先回顾下HTTP的'反向代理'流程
特点: 根据'负载均衡策略'选择上游的服务器
细节: 有一个回调方法叫'init_upstream','很多模块'在这里做,openresty也是'图中红色的地方'
引入: 'balance_by_lua*'去处理请求,openresty在这里通过'hook'钩子加入lua代码
高效: 可以自定义'负载均衡算法',通过'lua+redis'自定义gray'灰度策略'实现灰度发布
细节: ngx_http_lua_module在'许多阶段'都有引入,在'filter'阶段也有引入
⑥ 在openssl处理ssl协议时嵌入lua代码
介入时机: 在openssl处理'SSL协议'时嵌入lua代码,专门用来'处理ssl握手'的
备注: openresty当前支持'3'个指令集,后续随着'版本迭代',可能提供更多'功能'
思考: 为什么openresty可以在ssl握手中定义'回调'函数,而nginx都'做不到'
原因: 'openresty'使用了'openssl'的库,跟nginx'没有'任何关系
思考: 是否支持'双向'认证?
细节: 注意'openssl'的版本
遗留: 关于该'部分',会在学习完'ssl/tls'协议后,先学习'nginx'的ssl,再扩展openresty的ssl
- ssl_client_hello_by_lua_block
- ssl_client_hello_by_lua_file
- ssl_certificate_by_lua_block
- ssl_certificate_by_lua_file
- ssl_session_fetch_by_lua_block
- ssl_session_fetch_by_lua_file
- ssl_session_store_by_lua_block
- ssl_session_store_by_lua_file
⑦ 在代码中获取当前的阶段
说明: 并'没有'实际的意义,但是会让你清晰的了解'lua相关的指令'在nginx 11个阶段的'位置'
背景: 很多'lua代码'都可以添加到处理请求过程中,而lua代码可能'互相引用'
需求: 有'一段lua代码',想知道这段代码在'哪个阶段'引用?
做法: 通过SDK的API --> 'ngx.get_phrase',调用'返回值'
目的: 在'哪些'地方开始'影响'我们请求的? 才能处理'复杂'的openresty问题
企业使用: nginx'自编译'ngx_lua_moudle,没有使用'openresty'
维护成本: openresty官方只对'直接下载编译'提供了较好的支持
⑧ 根据功能拆分
⑨ 题外话