-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
Gateway Config: OpenResty + Redis + Lua 导流
Parent Issue: #204
Status: ⏸️ Phase 1 Complete, Lua 导流待实现
架构设计
多 Region 数据隔离
- 不同 region 的 DB 不互通
- 用户通过 GitHub ID 绑定到特定 region
- Gateway + Redis 负责导流
导流逻辑
┌─────────────────────────────────────────────────────────────────┐
│ Gateway (OpenResty + Lua) │
│ │
│ Request 进入 → │
│ 1. 检查 Header: X-M3W-Region │
│ ├── 有 → 直接导流到对应 region backend │
│ └── 无 → 继续 │
│ 2. 检查是否登录 (有 JWT/Cookie) │
│ ├── 有 → 解析 GitHub ID → 查 Redis │
│ │ ├── 找到 → 导流到对应 region │
│ │ └── 没找到 → 就近分配 (新用户) │
│ └── 无 → 就近分配 (未登录) │
│ │
└─────────────────────────────────────────────────────────────────┘
场景处理
| 场景 | Gateway 行为 | Backend 行为 |
|---|---|---|
| 已登录 + Header | 直接导流 | 正常处理 |
| 已登录 + 无 Header | 查 Redis 导流 | 正常处理 |
| 新用户 | 就近分配 + 写 Redis | 注册成功返回 X-M3W-Region |
| 未登录老用户 | 随便走 | 走错了返回 X-M3W-Region: <correct> |
| 走错 region | - | 检测 GitHub ID 不存在 → 返回正确 Header |
Redis 数据结构
# GitHub ID → Region 映射
SET user:region:12345 "jp"
SET user:region:67890 "sea"
# 可选: TTL 刷新
SETEX user:region:12345 86400 "jp"
当前状态 (2025-12-21)
✅ 已完成
- OpenResty 容器运行
- SSL 配置 (Let's Encrypt)
client_max_body_size 100M- Proxy 到 K3s via WireGuard
- Redis 容器运行
⏳ 待实现 (多 region 时)
- Lua 脚本解析 JWT/Cookie
- Lua 查询 Redis 获取 region
- 新用户写入 Redis
- Backend 返回
X-M3W-RegionHeader - Frontend 存储并发送 Header
Lua 导流脚本 (设计)
-- /usr/local/openresty/nginx/lua/route.lua
local redis = require "resty.redis"
local jwt = require "resty.jwt"
local function get_user_region()
-- 1. 检查 Header
local region = ngx.req.get_headers()["X-M3W-Region"]
if region then
return region
end
-- 2. 解析 JWT 获取 GitHub ID
local auth = ngx.req.get_headers()["Authorization"]
if not auth then
return nil -- 未登录,就近分配
end
local jwt_obj = jwt:load_jwt(auth:sub(8)) -- 去掉 "Bearer "
if not jwt_obj.valid then
return nil
end
local github_id = jwt_obj.payload.sub
-- 3. 查 Redis
local red = redis:new()
red:connect("127.0.0.1", 6379)
local region = red:get("user:region:" .. github_id)
red:close()
if region and region ~= ngx.null then
return region
end
return nil -- 新用户
end
local function route_to_backend()
local region = get_user_region()
local backends = {
jp = "10.10.0.2:30080",
sea = "10.10.0.3:30080", -- 未来
}
-- 默认就近 (根据 Gateway 位置)
local default_region = os.getenv("GATEWAY_REGION") or "jp"
local target = backends[region] or backends[default_region]
ngx.var.backend = target
end
route_to_backend()nginx 配置 (设计)
http {
lua_package_path "/usr/local/openresty/nginx/lua/?.lua;;";
upstream backend {
server 0.0.0.1; # placeholder
balancer_by_lua_block {
local balancer = require "ngx.balancer"
balancer.set_current_peer(ngx.var.backend)
}
}
server {
set $backend "";
location /api/ {
access_by_lua_file /usr/local/openresty/nginx/lua/route.lua;
proxy_pass http://backend;
}
}
}当前简化配置
单 region 时不需要 Lua 导流,直接 proxy:
server {
listen 443 ssl http2;
client_max_body_size 100M;
location / {
proxy_pass http://10.10.0.2:30080; # 唯一 backend
}
}相关 Issue
- K8s Gateway with intelligent user routing for multi-region architecture #204 Gateway Architecture (parent)
- Independent Gateway K3s + Wireguard VPN #212 Gateway VM Setup
- 区域后端 VPN 接入 + 关闭公网 #232 K3s VPN Connection
Reactions are currently unavailable