# gate
**Repository Path**: carlzyhuang/gate
## Basic Information
- **Project Name**: gate
- **Description**: 基于openresty的网关实现
核心功能是消息转发
基于lua 开发微服务相关特性
- **Primary Language**: Lua
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-10-20
- **Last Updated**: 2026-03-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# gate
基于 openresty 实现消息转发
## 两种连接分开处理
### 1. http 连接
方案一:
client http -> openresty (转换成 gRPC) -> backend server
由于没有成熟的库,放弃方案
方案二:
nginx 直接转发 http 消息,需要验证 session
方案三:
使用gRPC-gateway 自研网关,把http请求转发到对应的 gRPC服务器,还需要验证
```mermaid
flowchart TD
A[HTTP/JSON Client] -->|"POST /v1/hello {'name': 'World'}"| B[gRPC-Gateway :8080]
B -->|解析 JSON
转换为 Protobuf| C[gRPC Client]
C -->|编码 Protobuf 二进制| D[gRPC Server
:50051]
D -->|处理请求| E[你的业务逻辑]
E -->|返回响应| D
D -->|Protobuf 二进制响应| C
C -->|解码 Protobuf| B
B -->|编码为 JSON| A
A -->|接收| F["{'message': 'Hello World'}"]
```
### 2. TCP 的长连接
方案一:
使用 websocket, openresty 维护长连接和session, 后端服务将消息推送到网关,再到客户端
方案二:
自研 websocket 服务器,openresty 将 websocket 连接转发到服务器上
## 核心特性
- **服务发现**
使用 ```etcd``` 实现服务发现,watch服务,使用协程同步实例
- **负载均衡**
wrr 根据权重随机
ringhash 一致性哈希
instid 根据实例id选择节点
- **请求验证**
封装登录功能
验证token功能
- **高性能**
初始化流程: 预加载后端服务的实例列表
watch协程: 监听实例列表的变化,并构建缓存
http请求协程: 读取缓存,不阻塞请求的处理
## 实现步骤
首先,复习nginx的阶段处理模型,允许在请求处理的不同阶段嵌入Lua代码
```mermaid
flowchart TD
A[请求开始] --> C[rewrite阶段
rewrite_by_lua_block]
C --> D[access阶段
access_by_lua_block]
D --> E{content阶段
content_by_lua_block
或者 proxy_pass
两者互斥}
E -- 产生响应内容 --> F[header_filter阶段
header_filter_by_lua_block]
F --> G[body_filter阶段
body_filter_by_lua_block]
G --> H[log阶段
log_by_lua_block]
H --> I[请求结束]
classDef normal fill:#ffffff,stroke:#000000,stroke-width:2px
classDef important fill:#fffacd,stroke:#ffa500,stroke-width:3px
classDef critical fill:#ffcccc,stroke:#ff0000,stroke-width:4px
class A,I normal
class C,D,F,G,H important
class E critical
```
注意:Nginx 的响应体可能被分成多个"chunk"发送,每个 chunk 都会触发一次 body_filter_by_lua,这个模块一般不开发业务逻辑
```nginx
location /example {
content_by_lua_block {
ngx.say("Hello, ") -- 第一个chunk
ngx.say("World!") -- 第二个chunk
ngx.say("End") -- 第三个chunk
}
body_filter_by_lua_block {
ngx.log(ngx.INFO, "body_filter被调用") -- 每个chunk都会触发
}
}
```
### 业务执行流程
nginx的执行流程中,在不同阶段执行回调代码,根据功能的不同,以插件的方式实现。
比如:selector插件的核心工作是选择实例,设置target
```mermaid
flowchart TD
A[请求到达] --> D[Location的rewrite_by_lua]
D --> E[selector插件]
subgraph E [插件的路由匹配]
E1[get_dispatcher] --> E2[router.match]
E2 --> E3{缓存命中?}
E3 -- 是 --> E4[获得 ctx]
E3 -- 否 --> E5[etcd.query_enable_routers]
E5 --> E6[更新到router_shared_cache缓存]
E6 --> E7[更新负载均衡器loadbalancer_shared_cache缓存]
E7 --> E4
E4 --> E9{判断 ctx.lb 中的负载均衡器}
E9 -- wrr --> E10[随机权重返回地址]
E9 -- ringhash --> E11[用一致性哈希返回地址]
E9 -- filter --> E12[用instid过滤地址]
end
E --> F[设置$target变量]
F --> F1{proxy_pass 消息转发}
F1 --> G[access_by_lua阶段]
G --> K[header_filter_by_lua阶段]
K --> L[body_filter_by_lua阶段]
L --> M[log_by_lua阶段]
M --> N[请求结束]
```
### 插件的实现方法
1. 在 gateway/app/plugins 中新建插件,实现必要的接口。
详情参考 ```selector_plugin.lua``` 的内容
2. 在 app.json 中配置插件,启动时注入到系统中
```json
"plugins": [
"selector_plugin",
"tracing_plugin"
]
```
3. 在 gateway/init/init_rout.json 中配置哪些服务需要使用插件
```json
{
"service_name": "*",
"protocol": "http",
"plugins": ["selector", "tracing"]
}
```
## 待完善的内容
- 使用inst id 过滤需要对接 online 服,暂时没有实现
- etcd在实例变更后会立即通知,最好延迟变更,使用定时器,1s变更一次
- 缓存的监控需要进一步测试
- 实现压测脚本,测试性能
- 对接 Prometheus 系统
- 登录验证token,转发验证等业务逻辑
# 感谢
[代码架构参考的开源项目](https://github.com/tech-microworld/ws-cloud-gateway.git)
[监控代码移植的开源项目](https://github.com/knyar/nginx-lua-prometheus.git)