lolly/docs/lua-nginx-module/11-architecture.md
xfy 941c44b798 docs: 添加 Lua 嵌入分析文档
- 新增 lua-embed-analysis.md 技术分析文档
- 新增 lua-nginx-module 文档目录
- 更新 gitignore 允许跟踪 docs/lua-nginx-module/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 11:20:57 +08:00

306 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` | 协程状态管理 |