一、本质区别
1.1 基本定义
- Nginx: 高性能HTTP和反向代理服务器
- OpenResty: 基于Nginx + LuaJIT的全功能Web平台
1.2 架构差异
Nginx核心架构:
┌─────────────────────────────────┐
│ Nginx (C语言编写) │
│ ┌─────────┐ ┌─────────┐ │
│ │ 模块系统 │ │配置语言 │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────┘
OpenResty架构:
┌─────────────────────────────────┐
│ OpenResty平台 │
│ ┌─────────────────────────┐ │
│ │ Nginx核心 │ │
│ ├─────────────────────────┤ │
│ │ LuaJIT引擎 │ │
│ ├─────────────────────────┤ │
│ │ lua-nginx-module │ │
│ ├─────────────────────────┤ │
│ │ 大量Lua模块库 │ │
│ └─────────────────────────┘ │
└─────────────────────────────────┘
二、OpenResty独有能力
2.1 完整的Lua编程能力
原生Nginx的限制
# Nginx配置是声明式的
location /api {
proxy_pass http://backend;
limit_req zone=api burst=5;
add_header X-Cache $upstream_cache_status;
}
OpenResty的编程能力
-- 完整的Lua脚本控制
location /api {
access_by_lua_block {
-- 复杂的业务逻辑
local user_id = get_user_from_token()
local rate_limit_key = "rate:" .. user_id
-- 动态决策
if is_blacklisted(user_id) then
ngx.exit(403)
end
-- 自定义限流
local limiter = limit.conn("my_limit", 10, 100, 0.5)
local delay, err = limiter:incoming(user_id, true)
-- 请求改写
ngx.req.set_header("X-User-ID", user_id)
}
proxy_pass http://backend;
}
2.2 请求处理阶段的完全控制
OpenResty的11个处理阶段
-- 完整的请求生命周期控制
init_by_lua_block -- Nginx启动时执行
init_worker_by_lua_block -- Worker进程启动时
set_by_lua_block -- 变量赋值阶段
# 请求处理流程
rewrite_by_lua_block -- 重写阶段
access_by_lua_block -- 访问控制阶段 ✔
content_by_lua_block -- 内容生成阶段
header_filter_by_lua_block -- 响应头过滤
body_filter_by_lua_block -- 响应体过滤
balancer_by_lua_block -- 负载均衡决策
timer -- 定时任务
log_by_lua_block -- 日志记录阶段
实际应用场景
-- 1. 启动时初始化
init_by_lua_block {
require "resty.core"
config = require "config"
redis_pool = require "redis_pool"
}
-- 2. 动态重写
rewrite_by_lua_block {
-- 基于业务逻辑重写URL
if ngx.var.args.version == "v2" then
ngx.var.uri = "/api/v2" .. ngx.var.uri
end
}
-- 3. 访问控制(之前的配置就在此阶段)
access_by_lua_block {
-- Token验证、限流、安全检查
}
-- 4. 内容生成
content_by_lua_block {
ngx.say('{"status": "ok", "data": ', get_data(), '}')
}
-- 5. 响应过滤
header_filter_by_lua_block {
-- 添加安全头
ngx.header["X-Content-Type-Options"] = "nosniff"
ngx.header["X-Frame-Options"] = "DENY"
}
-- 6. 响应体修改
body_filter_by_lua_block {
-- 压缩、加密、格式化响应
local chunk = ngx.arg[1]
if chunk then
ngx.arg[1] = minify_json(chunk)
end
}
2.3 非阻塞I/O操作
Nginx的限制
# Nginx本身不能做复杂的I/O操作
# 所有阻塞操作都会导致worker阻塞
OpenResty的优势
-- 非阻塞的并发操作
location /user {
content_by_lua_block {
-- 并行查询多个后端
local user_future = query_user_async(ngx.var.arg.user_id)
local orders_future = query_orders_async(ngx.var.arg.user_id)
-- 等待所有结果
local user = user_future:wait()
local orders = orders_future:wait()
-- 返回合并结果
ngx.say(json.encode({
user = user,
orders = orders
}))
}
}
2.4 动态配置和热更新
传统Nginx的问题
# 修改配置需要重启
nginx -t
nginx -s reload # 可能中断连接
OpenResty的动态配置
-- 动态配置管理
location /admin/config {
content_by_lua_block {
local config = require "config_manager"
if ngx.var.request_method == "POST" then
-- 动态更新路由规则
local new_routes = ngx.req.get_body_data()
config.update_routes(new_routes)
ngx.say('{"status": "updated"}')
else
-- 获取当前配置
ngx.say(json.encode(config.get_all()))
end
}
}
-- 使用共享字典实现配置热更新
local shared_dict = ngx.shared.config_cache
local function get_dynamic_config(key)
local config = shared_dict:get(key)
if not config then
config = fetch_from_redis(key)
shared_dict:set(key, config, 60) -- 缓存60秒
end
return config
end
三、核心功能对比
3.1 数据存储和缓存
| 功能 |
Nginx |
OpenResty |
| 内存缓存 |
简单key-value |
丰富数据结构(Lua table) |
| 共享字典 |
❌ 不支持 |
✅ 支持跨worker共享 |
| Redis操作 |
❌ 不支持 |
✅ 非阻塞客户端 |
| MySQL操作 |
❌ 不支持 |
✅ 非阻塞客户端 |
| Kafka生产消费 |
❌ 不支持 |
✅ 完整客户端 |
OpenResty示例:
-- 1. 共享内存
local shared_data = ngx.shared.my_cache
shared_data:set("key", "value", 60) -- 60秒过期
local value = shared_data:get("key")
-- 2. Redis操作
local redis = require "resty.redis"
local red = redis:new()
red:connect("127.0.0.1", 6379)
local res, err = red:get("user:123")
-- 3. MySQL操作
local mysql = require "resty.mysql"
local db = mysql:new()
db:connect({
host = "127.0.0.1",
port = 3306,
database = "test",
user = "root",
password = "123456"
})
local res, err = db:query("SELECT * FROM users")
-- 4. Kafka操作
local producer = require "resty.kafka.producer"
local bp = producer:new(broker_list, { producer_type = "async" })
local ok, err = bp:send("test-topic", nil, "message")
3.2 协议支持
| 协议 |
Nginx |
OpenResty |
| HTTP/1.x |
✅ 完整支持 |
✅ 完整支持 |
| HTTP/2 |
✅ 支持 |
✅ 支持 |
| WebSocket |
✅ 支持 |
✅ 增强支持 |
| gRPC |
✅ 基础支持 |
✅ 增强支持 |
| MQTT |
❌ 不支持 |
✅ 支持 |
| Redis协议 |
❌ 不支持 |
✅ 支持(可作Redis服务器) |
| 自定义协议 |
❌ 有限支持 |
✅ 完整支持 |
示例:创建Redis服务器
-- OpenResty可以充当Redis服务器
server {
listen 6380;
content_by_lua_block {
local redis = require "resty.redis"
-- 解析Redis协议
local line = ngx.var.request_body
local command = parse_redis_command(line)
if command == "GET" then
local key = get_key_from_request(line)
local value = get_from_cache(key)
ngx.print(format_redis_response(value))
elseif command == "SET" then
-- 处理SET命令
end
}
}
3.3 模板渲染和Web框架
-- 1. 模板渲染
local template = require "resty.template"
template.render("user.html", {
name = "John",
age = 30,
skills = {"Lua", "Nginx", "OpenResty"}
})
-- 2. Web框架(Lapis)
local lapis = require "lapis"
local app = lapis.Application()
app:get("/users", function(self)
return { json = { users = get_all_users() } }
end)
app:post("/users", function(self)
local user = create_user(self.params)
return { json = { user = user } }
end)
-- 3. RESTful API框架
local resty_mvc = require "resty.mvc"
local app = resty_mvc:new()
app:controller("user", {
get = function(ctx)
return { id = 123, name = "test" }
end,
post = function(ctx)
-- 创建用户
end
})
3.4 高级负载均衡和服务发现
-- 动态负载均衡
balancer_by_lua_block {
local balancer = require "ngx.balancer"
-- 基于业务逻辑选择后端
local backend
if ngx.var.cookie_version == "v2" then
backend = get_backend_v2()
else
backend = get_healthy_backend()
end
-- 设置后端
balancer.set_current_peer(backend.host, backend.port)
-- 重试逻辑
if ngx.ctx.balancer_tries then
ngx.ctx.balancer_tries = ngx.ctx.balancer_tries + 1
else
ngx.ctx.balancer_tries = 1
end
if ngx.ctx.balancer_tries > 3 then
ngx.exit(503)
end
}
-- 服务发现集成
local consul = require "resty.consul"
local consul_client = consul:new({
host = "127.0.0.1",
port = 8500
})
local services, err = consul_client:get_services()
local healthy_instances = {}
for _, service in ipairs(services) do
local instances = consul_client:get_service_instances(service)
for _, instance in ipairs(instances) do
if instance.Checks[1].Status == "passing" then
table.insert(healthy_instances, instance)
end
end
end
四、性能优化能力
4.1 LuaJIT性能优势
-- 1. JIT编译加速
local function process_request(req)
-- LuaJIT会将热点代码编译为机器码
for i = 1, 1000000 do
process_item(req.items[i])
end
end
-- 2. FFI调用C库
local ffi = require "ffi"
ffi.cdef[[
int memcmp(const void *s1, const void *s2, size_t n);
void *malloc(size_t size);
void free(void *ptr);
]]
-- 直接调用C函数,无开销
local ptr = ffi.C.malloc(100)
ffi.C.free(ptr)
4.2 内存管理优化
-- 避免Lua GC压力
local buffer = require "resty.core.base".get_string_buf(1024)
-- 使用table池
local table_pool = require "tablepool"
local tab = table_pool.fetch("my_pool", 10, 0)
-- 使用table...
table_pool.release("my_pool", tab)
五、企业级应用场景
5.1 API网关
-- 完整的API网关功能
location /api {
access_by_lua_block {
-- 1. 认证鉴权
local auth = require "auth"
auth.validate()
-- 2. 限流
local limit = require "limit"
limit.check()
-- 3. 参数校验
local validator = require "validator"
validator.validate_params()
-- 4. 协议转换
if ngx.var.http_content_type == "application/grpc" then
convert_grpc_to_http()
end
}
proxy_pass http://backend;
header_filter_by_lua_block {
-- 响应处理
add_security_headers()
inject_trace_id()
}
body_filter_by_lua_block {
-- 数据脱敏
desensitize_response()
}
log_by_lua_block {
-- 访问日志
log_access()
report_metrics()
}
}
5.2 实时数据处理
-- WebSocket实时数据处理
location /ws {
lua_socket_log_errors off;
content_by_lua_block {
local server = require "resty.websocket.server"
local wb, err = server:new{
timeout = 5000,
max_payload_len = 65535
}
while true do
local data, typ, err = wb:recv_frame()
if err then
break
end
if typ == "text" then
-- 处理消息
local result = process_message(data)
wb:send_text(result)
-- 广播给其他连接
broadcast_to_others(result)
end
end
}
}
5.3 边缘计算
-- CDN边缘计算
location /video {
access_by_lua_block {
-- 验证token
local valid = validate_token(ngx.var.arg.token)
if not valid then
ngx.exit(403)
end
}
header_filter_by_lua_block {
-- 添加防盗链
ngx.header["X-Allow-Origin"] = get_allowed_origin()
}
body_filter_by_lua_block {
-- 视频水印
if ngx.var.content_type == "video/mp4" then
add_watermark(ngx.arg[1])
end
}
}
六、生态系统对比
6.1 模块生态系统
| 领域 |
Nginx模块 |
OpenResty模块 |
| 缓存 |
proxy_cache, fastcgi_cache |
lua-resty-lrucache, lua-resty-memcached |
| 数据库 |
❌ 无 |
lua-resty-mysql, lua-resty-postgres |
| NoSQL |
❌ 无 |
lua-resty-redis, lua-resty-mongo |
| 消息队列 |
❌ 无 |
lua-resty-kafka, lua-resty-rabbitmq |
| 模板 |
❌ 无 |
lua-resty-template, lemplate |
| Web框架 |
❌ 无 |
Lapis, Lor, Vanilla |
| 测试框架 |
❌ 无 |
test-nginx, busted |
6.2 开发调试工具
-- OpenResty专属调试工具
-- 1. 代码热重载
if package.loaded["my_module"] then
package.loaded["my_module"] = nil
end
local my_module = require "my_module"
-- 2. 性能分析
local profile = require "resty.profiler"
profile.start()
-- 执行代码...
profile.stop()
profile.report()
-- 3. 单元测试
describe("auth module", function()
it("should validate token", function()
local auth = require "auth"
local ok = auth.validate_token("test")
assert.is_false(ok)
end)
end)
七、总结对比表
| 特性 |
Nginx |
OpenResty |
优势说明 |
| 编程模型 |
声明式配置 |
完整Lua编程 |
OpenResty可实现复杂业务逻辑 |
| 处理阶段 |
固定阶段 |
11个可编程阶段 |
更细粒度控制 |
| I/O模型 |
异步非阻塞 |
异步+协程 |
编写同步风格异步代码 |
| 数据存储 |
简单缓存 |
Redis/MySQL/Kafka等 |
完整的数据处理能力 |
| 协议支持 |
常见协议 |
任意自定义协议 |
可扩展性极强 |
| 动态配置 |
有限 |
完整热更新 |
不停机配置更新 |
| 性能 |
极高 |
极高+JIT优化 |
LuaJIT接近C性能 |
| 开发生态 |
C模块开发 |
Lua模块开发 |
开发效率提升10倍 |
| 调试能力 |
日志调试 |
完整调试器 |
更好的开发体验 |
| 适用场景 |
静态代理 |
全功能应用 |
OpenResty可替代应用服务器 |
八、选择建议
选择Nginx当:
- 只需要反向代理/负载均衡
- 静态文件服务
- 简单的缓存代理
- 团队没有Lua开发经验
- 对性能要求极致,不需要业务逻辑
选择OpenResty当:
- 需要API网关功能
- 需要动态配置和热更新
- 需要复杂业务逻辑处理
- 需要集成多种数据源
- 需要自定义协议处理
- 希望用单一技术栈覆盖更多场景
- 需要边缘计算能力
性能数据参考
简单代理场景:
- Nginx: 约50,000 QPS
- OpenResty: 约45,000 QPS (90% of Nginx)
复杂业务场景:
- Nginx + 后端: 约20,000 QPS
- OpenResty(内聚): 约40,000 QPS (2x提升)
内存占用:
- Nginx: 约50MB
- OpenResty: 约80MB (包含LuaJIT)
结论: OpenResty不是Nginx的替代品,而是在Nginx基础上的超集。如果你需要在网关层面处理业务逻辑、需要动态能力、或者希望减少技术栈复杂度,OpenResty是更好的选择。如果只是简单的代理和缓存,纯Nginx可能更合适。