Files
memind/docs/g2-load-balancing.md
T
Your Name b0f5d6a51c Extract memind_adm admin server, add local dev tooling, and remove image-generation.
Split platform admin and ops APIs into standalone admin-server.mjs with network guards; simplify billing to RMB token pricing, refactor user auth, and add rsync deploy plus local-test scripts and docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-17 16:39:39 -07:00

4.8 KiB
Raw Blame History

g2.tkmind.cn 负载均衡(Studio + 105)

2026-06-17 上线。把 g2 H5 的请求按权重分到两台机器:Studio(主)和 105(灰度副)。 goose 只在 Studio 跑一份,105 是无状态前端孪生,通过 Tailscale 把请求代理回 Studio 的 goosed。

流量拓扑

用户 → Cloudflare(橙云) → Tunnel 1d8cda42 → Studio Caddy(:8090, g2-lb)
                                                 ├─ 权重 19 → Studio 本机 portal 127.0.0.1:8081
                                                 └─ 权重  1 → [SSH正向隧道 127.0.0.1:18080] → 105 portal :8080
                                                                                                   │
                       105 / Studio 两个 portal ── 都连 ──→ Studio goosed 100.99.38.66:18006(唯一实例)
                       发布页文件 ── 都读 ──→ Studio canonical /Users/john/Project/Memind/MindSpace
                                              (105 经反向隧道 + rclone 挂载到本地同路径)
  • 为什么用 Caddy 加权而不是 Cloudflare LB:账号未开通 Cloudflare Load Balancing 付费插件(建 pool/monitor 报 Access Failed)。Caddy 加权反代免费、可精确控权重,并自带 active 健康检查实现自动摘除。
  • 为什么 105 经 SSH 隧道接入:Caddy 一个 reverse_proxy 不能混用 http(本地 :8081)和 https(105 公网 :443)上游。用 Studio→105 正向隧道把 105 暴露成本地 HTTP 端口,两个上游就都是本地 http,同协议。

调灰度比例(最常用)

编辑 Studio 上的 ~/Project/Memind/scripts/g2-lb.Caddyfile,改 lb_policy weighted_round_robin 后面两个权重(第一个=Studio :8081,第二个=105 :18080):

配置 Studio 105
weighted_round_robin 19 1 95% 5%(默认上线值)
weighted_round_robin 9 1 90% 10%
weighted_round_robin 4 1 80% 20%
weighted_round_robin 1 1 50% 50%

改完零停机生效:

ssh studio   # 或 ssh 100.99.38.66
cd ~/Project/Memind/scripts
caddy validate --config g2-lb.Caddyfile   # 可选,先校验
caddy reload  --config g2-lb.Caddyfile     # 零停机热重载

caddy 路径若不在 PATH:用 /opt/homebrew/bin/caddy。

一键回滚(把流量全部收回 Studio)

把 to 那行的 127.0.0.1:18080 删掉(只留 127.0.0.1:8081),或直接恢复备份,然后 reload:

cd ~/Project/Memind/scripts
ls g2-lb.Caddyfile.bak-*          # 找最近备份
cp g2-lb.Caddyfile.bak-XXXX g2-lb.Caddyfile
caddy reload --config g2-lb.Caddyfile

验证 / 观测

每个 g2 响应都带 X-Memind-Upstream 头,标记实际命中的上游(127.0.0.1:8081=Studio,127.0.0.1:18080=105):

# 打 N 次看分流比例
for i in $(seq 1 40); do
  curl -s -D - -o /dev/null https://g2.tkmind.cn/api/status \
    | grep -i x-memind-upstream | awk '{print $2}' | tr -d '\r'
done | sort | uniq -c

# 看 Caddy 两个上游健康状态
curl -s http://127.0.0.1:2019/reverse_proxy/upstreams   # 在 Studio 上执行

active 健康检查会每 10s 打一次各上游的 /api/status,连不上或非 200 就自动摘除该上游、流量全转到健康节点;恢复后自动加回。

涉及的组件与配置位置

组件 位置 作用
g2-lb Caddy Studio scripts/g2-lb.Caddyfile(LaunchAgent cn.tkmind.g2-lb,:8090) 加权反代 + 健康检查
正向隧道 Studio scripts/memind-fwd-tunnel.sh(LaunchAgent cn.tkmind.memind-fwd-tunnel) Studio 127.0.0.1:18080 → 105 :8080
反向隧道 Studio scripts/memind-mac-tunnel.sh(LaunchAgent cn.tkmind.memind-tunnel) 105 经此挂载 Studio 的 MindSpace 文件
105 portal 105 systemd goose-h5(:8080),/root/tkmind_go/ui/h5/.env 无状态前端,TKMIND_API_TARGET=https://100.99.38.66:18006
105 文件挂载 105 systemd .mount → /mnt/memind-shared(rclone over 反向隧道) 发布页/工作区共享只读

关键约束(改动前必读)

  • 105 永不跑 goose。goosed 单实例只在 Studio;session 存 Studio 本地 SQLite,文件操作也在 Studio 本地。105 只是代理 + serve。
  • 105 的 portal 必须设 MEMIND_WORKSPACE_MAINTENANCE=0、MINDSPACE_AGENT_JOBS_ENABLED=false——工作区维护守护(缩略图/资产同步 watcher)只该在 Studio 跑,否则 105 对 rclone 挂载树做递归 fs.watch 会占满 libuv 线程池导致 portal 启动卡死。
  • 105 必须与 Studio 跑同一份代码(用 sync-to-105.sh 从 Studio 同步)和相同的 TKMIND_SERVER__SECRET_KEY(否则连不上 goosed / 解不开共享 RDS 里的加密设置)。
  • 调权重只动 g2-lb.Caddyfile,不要动 105 的 systemd 单元或 .env。