# 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)