70492d9eba
Simplify asset upload temp paths, refresh deploy docs for Aliyun DNS topology, and ship MindSpace content-scan and auth improvements. Co-authored-by: Cursor <cursoragent@cursor.com>
5.4 KiB
5.4 KiB
g2.tkmind.cn 负载均衡(Studio + 105)
2026-06-17 上线。把 g2 H5 的请求按权重分到两台机器:Studio(主)和 105(灰度副)。 goose 只在 Studio 跑一份,105 是无状态前端孪生,通过 Tailscale 把请求代理回 Studio 的 goosed。
流量拓扑
用户 → 阿里云解析 → 105 服务器公网入口
├─ 转发到本地 Mac 1.6 机器 → 本机 portal 127.0.0.1:8081
└─ [SSH 正向隧道 127.0.0.1:18080] → 105 portal :8080
│
105 / 本地主机 两个 portal ── 都连 ──→ 本地 goosed 100.99.38.66:18006(唯一实例)
发布页文件 ── 都读 ──→ 本地 canonical /Users/john/Project/Memind/MindSpace
(105 经反向隧道 + rclone 挂载到本地同路径)
- 为什么不用旧的 Cloudflare 直连:当前入口已经迁到阿里云解析,外网流量先到 105,再由 105 转发回本地 Mac 1.6 机器。
- 为什么 105 经 SSH 隧道接入:入口机和 105 之间保持本地 HTTP/SSH 链路,避免把 105 公网地址直接写进上游。
调灰度比例(最常用)
105 联通约束(硬性要求)
要求:105 机器与本机通信必须走 Tailscale 隧道,不允许走外网 IP。
- 访问、同步、部署 105 一律使用
ssh105。 ssh105在~/.ssh/config中绑定为100.101.255.32并通过tailscale nc代理;- 现有脚本默认主机已改为
root@ssh105。 - 本机对 105 的联通入口是
127.0.0.1:18080,不是105.tkmind.cn。
快速自检(每次操作 105 前):
tailscale --socket /Users/john/Project/ollama/.tailscale/tailscaled.sock status
tailscale --socket /Users/john/Project/ollama/.tailscale/tailscaled.sock ping 100.101.255.32
ssh ssh105 'echo tunnel-ok-105'
curl -s http://127.0.0.1:18080/api/status # 应返回 ok
- 禁止:
HostName 120.26.184.105直接作为 105 脚本主机。 - 禁止:用
105.tkmind.cn做 API 健康检查或同步链路入口。
编辑 本地 Mac 1.6 上的入口配置,调整流量分配(第一个=本机 :8081,第二个=105 :18080):
| 配置 | 本机 | 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 本机入口机
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=本机,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
# 看入口反代两个上游健康状态
curl -s http://127.0.0.1:2019/reverse_proxy/upstreams # 在本机入口机上执行
健康检查会每 10s 打一次各上游的 /api/status,连不上或非 200 就自动摘除该上游、流量全转到健康节点;恢复后自动加回。
涉及的组件与配置位置
| 组件 | 位置 | 作用 |
|---|---|---|
| 入口反代 | 本机入口机 scripts/g2-lb.Caddyfile(LaunchAgent cn.tkmind.g2-lb,:8090) |
入口转发 + 健康检查 |
| 正向隧道 | 本机入口机 scripts/memind-fwd-tunnel.sh(LaunchAgent cn.tkmind.memind-fwd-tunnel) |
本机 127.0.0.1:18080 → 105 :8080 |
| 反向隧道 | 本机入口机 scripts/memind-mac-tunnel.sh(LaunchAgent cn.tkmind.memind-tunnel) |
105 经此挂载本地 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 单实例只在本地 Mac 1.6 机器;session 存本地 SQLite,文件操作也在本地完成。105 只是代理 + serve。
- 105 的 portal 必须设
MEMIND_WORKSPACE_MAINTENANCE=0、MINDSPACE_AGENT_JOBS_ENABLED=false——工作区维护守护(缩略图/资产同步 watcher)只该在本地跑,否则 105 对 rclone 挂载树做递归 fs.watch 会占满 libuv 线程池导致 portal 启动卡死。 - 105 必须与本地主机跑同一份代码(用
sync-to-105.sh从主机同步)和相同的TKMIND_SERVER__SECRET_KEY(否则连不上 goosed / 解不开共享 RDS 里的加密设置)。 - 调权重只动
g2-lb.Caddyfile,不要动 105 的 systemd 单元或 .env。