- 新增 lua-embed-analysis.md 技术分析文档 - 新增 lua-nginx-module 文档目录 - 更新 gitignore 允许跟踪 docs/lua-nginx-module/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
306 lines
7.2 KiB
Markdown
306 lines
7.2 KiB
Markdown
# lua-nginx-module 核心架构设计
|
||
|
||
本文档为 lolly 项目提供 lua-nginx-module 的核心架构参考。
|
||
|
||
---
|
||
|
||
## 一、核心数据结构
|
||
|
||
### 1.1 主配置结构 (ngx_http_lua_main_conf_t)
|
||
|
||
**文件**: `src/ngx_http_lua_common.h:233`
|
||
|
||
```c
|
||
struct ngx_http_lua_main_conf_s {
|
||
lua_State *lua; // Lua VM 实例
|
||
ngx_hash_t shm_zones; // 共享内存区域
|
||
ngx_array_t *shdict_zones; // shdict 区域
|
||
|
||
// Phase handlers
|
||
ngx_http_handler_pt init_handler;
|
||
ngx_http_handler_pt init_worker_handler;
|
||
ngx_http_handler_pt exit_worker_handler;
|
||
|
||
// 线程缓存
|
||
ngx_queue_t free_lua_threads;
|
||
ngx_queue_t cached_lua_threads;
|
||
|
||
// 功能开关
|
||
unsigned requires_rewrite:1;
|
||
unsigned requires_access:1;
|
||
unsigned requires_log:1;
|
||
// ...
|
||
};
|
||
```
|
||
|
||
### 1.2 请求上下文 (ngx_http_lua_ctx_t)
|
||
|
||
**文件**: `src/ngx_http_lua_common.h:628`
|
||
|
||
```c
|
||
struct ngx_http_lua_ctx_s {
|
||
ngx_http_request_t *request; // 请求对象
|
||
|
||
// 协程管理
|
||
ngx_http_lua_co_ctx_t *cur_co_ctx; // 当前协程
|
||
ngx_http_lua_co_ctx_t entry_co_ctx; // 入口协程
|
||
ngx_queue_t user_co_ctx; // 用户协程列表
|
||
|
||
// 输出缓冲
|
||
ngx_chain_t *out;
|
||
ngx_chain_t *free_bufs;
|
||
ngx_chain_t *busy_bufs;
|
||
|
||
// 请求体
|
||
ngx_chain_t *body;
|
||
ngx_chain_t *filter_in_bufs;
|
||
|
||
// 状态
|
||
unsigned context; // 当前 phase
|
||
unsigned exited:1;
|
||
unsigned eof:1;
|
||
// ...
|
||
};
|
||
```
|
||
|
||
### 1.3 协程上下文 (ngx_http_lua_co_ctx_t)
|
||
|
||
**文件**: `src/ngx_http_lua_common.h:550`
|
||
|
||
```c
|
||
struct ngx_http_lua_co_ctx_s {
|
||
lua_State *co; // Lua 协程
|
||
ngx_http_lua_co_status_e co_status; // 状态
|
||
|
||
// 父子关系
|
||
ngx_http_lua_co_ctx_t *parent_co_ctx;
|
||
ngx_queue_t zombie_child_threads;
|
||
|
||
// 子请求数据
|
||
ngx_int_t *sr_statuses;
|
||
ngx_http_headers_out_t **sr_headers;
|
||
ngx_str_t *sr_bodies;
|
||
|
||
// 挂起状态
|
||
unsigned sleep:1;
|
||
unsigned sem_wait:1;
|
||
// ...
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 二、Nginx 集成机制
|
||
|
||
### 2.1 Directive 注册
|
||
|
||
**文件**: `src/ngx_http_lua_module.c:114-804`
|
||
|
||
```c
|
||
static ngx_command_t ngx_http_lua_cmds[] = {
|
||
{ ngx_string("content_by_lua_block"),
|
||
NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK,
|
||
ngx_http_lua_content_by_lua_block,
|
||
NGX_HTTP_LOC_CONF_OFFSET,
|
||
offsetof(ngx_http_lua_loc_conf_t, content_handler),
|
||
NULL },
|
||
// ... 更多指令
|
||
};
|
||
```
|
||
|
||
### 2.2 Handler 注册
|
||
|
||
**文件**: `src/ngx_http_lua_module.c:839-945`
|
||
|
||
```c
|
||
static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf)
|
||
{
|
||
// 动态注册 phase handlers
|
||
if (lmcf->requires_rewrite) {
|
||
h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
|
||
*h = ngx_http_lua_rewrite_handler;
|
||
}
|
||
|
||
// Filter chain 注册
|
||
ngx_http_lua_header_filter_init();
|
||
ngx_http_lua_body_filter_init();
|
||
}
|
||
```
|
||
|
||
### 2.3 Filter Chain
|
||
|
||
```c
|
||
// Header filter
|
||
ngx_http_next_header_filter = ngx_http_top_header_filter;
|
||
ngx_http_top_header_filter = ngx_http_lua_header_filter;
|
||
|
||
// Body filter
|
||
ngx_http_next_body_filter = ngx_http_top_body_filter;
|
||
ngx_http_top_body_filter = ngx_http_lua_body_filter;
|
||
```
|
||
|
||
---
|
||
|
||
## 三、请求处理流程
|
||
|
||
```
|
||
nginx 请求
|
||
↓
|
||
ngx_http_lua_content_handler
|
||
↓
|
||
ngx_http_lua_content_run
|
||
↓
|
||
ngx_http_lua_run_thread ←───┐
|
||
↓ │
|
||
lua_pcall / lua_resume │
|
||
↓ │
|
||
用户 Lua 代码 │
|
||
│ │
|
||
├── lua_yield ───────────┘ (NGX_AGAIN)
|
||
│ ↓
|
||
│ 事件注册
|
||
│ ↓
|
||
│ resume_handler
|
||
│ ↓
|
||
│ 恢复执行
|
||
│
|
||
└── return
|
||
↓
|
||
NGX_OK / NGX_ERROR
|
||
```
|
||
|
||
---
|
||
|
||
## 四、协程驱动架构
|
||
|
||
### 4.1 Yield/Resume 机制
|
||
|
||
```c
|
||
// Yield
|
||
lua_yield(L, nresults); // 挂起 Lua 协程
|
||
ctx->resume_handler = ...; // 设置恢复函数
|
||
return NGX_AGAIN; // 让出 nginx 控制权
|
||
|
||
// Resume
|
||
resume_handler(r); // 事件触发时调用
|
||
lua_resume(L, nargs); // 恢复 Lua 协程
|
||
```
|
||
|
||
### 4.2 非阻塞 I/O 模式
|
||
|
||
```
|
||
ngx.sleep(1)
|
||
│
|
||
├── 添加 nginx 定时器
|
||
├── lua_yield
|
||
└── return NGX_AGAIN
|
||
↓
|
||
nginx 处理其他请求
|
||
↓
|
||
定时器到期
|
||
↓
|
||
ngx_http_lua_sleep_handler
|
||
↓
|
||
lua_resume
|
||
↓
|
||
用户代码继续
|
||
```
|
||
|
||
---
|
||
|
||
## 五、内存管理策略
|
||
|
||
### 5.1 双重内存管理
|
||
|
||
| 场景 | 使用 |
|
||
|------|------|
|
||
| 请求临时数据 | `ngx_palloc(r->pool)` / `ngx_pfree()` |
|
||
| 长期对象 | `lua_newuserdata()` (Lua GC) |
|
||
|
||
### 5.2 请求对象获取
|
||
|
||
```c
|
||
#ifdef OPENRESTY_LUAJIT
|
||
// 使用 exdata (更快)
|
||
r = lua_getexdata(L);
|
||
#else
|
||
// 全局变量
|
||
lua_getglobal(L, "__ngx_req");
|
||
r = lua_touserdata(L, -1);
|
||
#endif
|
||
```
|
||
|
||
---
|
||
|
||
## 六、设计模式总结
|
||
|
||
| 模式 | 说明 |
|
||
|------|------|
|
||
| **Phase-based** | Nginx 11 个 phase,每个可注册 Lua handler |
|
||
| **协程驱动** | 非阻塞 I/O 通过 yield/resume 与 nginx 事件循环协作 |
|
||
| **VM 共享** | per-worker 单 VM,协程实现请求隔离 |
|
||
| **Closure Factory** | 非 LuaJIT 环境隔离 upvalue |
|
||
| **Filter Chain** | 插入式 header/body 过滤 |
|
||
|
||
---
|
||
|
||
## 七、关键设计决策
|
||
|
||
### 7.1 为什么用协程?
|
||
|
||
- **同步代码风格**: 开发者写同步代码,框架处理异步
|
||
- **非阻塞**: yield 时 nginx 可以处理其他请求
|
||
- **简单错误处理**: 使用标准 Lua 错误机制
|
||
|
||
### 7.2 为什么单 VM?
|
||
|
||
- **内存效率**: 代码只加载一次
|
||
- **共享状态**: 全局变量和缓存自然共享
|
||
- **性能**: 无 VM 切换开销
|
||
|
||
### 7.3 为什么用 FFI?
|
||
|
||
- **性能**: 绕过 Lua C API 开销
|
||
- **简洁**: 直接调用 C 函数
|
||
- **灵活**: 可动态加载
|
||
|
||
---
|
||
|
||
## 八、lolly 实现参考
|
||
|
||
### 8.1 核心模块实现顺序
|
||
|
||
1. **VM 管理**: Lua 状态机创建、初始化、销毁
|
||
2. **Context 管理**: 请求上下文、协程上下文
|
||
3. **Phase Handlers**: 各阶段的 handler 注册和执行
|
||
4. **Yield/Resume**: 协程挂起和恢复机制
|
||
5. **API 注入**: ngx.* 命名空间构建
|
||
|
||
### 8.2 需要实现的 C API
|
||
|
||
```c
|
||
// VM 管理
|
||
lua_State *create_vm();
|
||
void destroy_vm(lua_State *L);
|
||
|
||
// 协程管理
|
||
int run_thread(lua_State *L, lua_State *co);
|
||
int yield_thread(lua_State *co, int nresults);
|
||
int resume_thread(lua_State *co, int nargs);
|
||
|
||
// 请求对象
|
||
ngx_http_request_t *get_request(lua_State *L);
|
||
void set_request(lua_State *L, ngx_http_request_t *r);
|
||
|
||
// Phase 执行
|
||
int run_phase_handler(ngx_http_request_t *r, int phase);
|
||
```
|
||
|
||
### 8.3 数据结构映射
|
||
|
||
| lua-nginx-module | lolly 参考 |
|
||
|------------------|-----------|
|
||
| `ngx_http_lua_main_conf_t` | 全局配置,VM 管理 |
|
||
| `ngx_http_lua_loc_conf_t` | Location 配置,handler 存储 |
|
||
| `ngx_http_lua_ctx_t` | 请求级上下文 |
|
||
| `ngx_http_lua_co_ctx_t` | 协程状态管理 | |