作为一名常年和 AI Agent 框架打交道的后端工程师,我最近把团队内部的 MCP(Model Context Protocol)Server 从单机裸跑迁移到了 Docker + Nginx 的高可用架构。整套方案跑了 21 天,踩了 6 个坑,触发故障转移 14 次,本文就把可复用的工程经验一次性讲透。

顺带说一句,这次接入的模型全部走的是 HolySheep AI,原因后面会说。先上结论:

一、为什么 MCP Server 需要高可用

MCP 是 Anthropic 提出的"模型上下文协议",一个 MCP Server 通常会同时挂载 10+ 个 tool,对接 Claude Desktop、Cursor、Cline 等客户端。一旦 MCP Server 挂掉,IDE 里的 Agent 立刻"失忆",用户体验断崖式下跌。

传统的 nohup ./mcp-server & 跑法有三个致命问题:

我用 Docker Compose 起 2 个 MCP Server 实例,前面挂 Nginx 做 TCP/stream 四层负载 + 健康检查,再配一个轻量级 failover 脚本,21 天里把可用性从 97.2% 拉到了 99.87%(来源:Prometheus + Blackbox exporter 实测)。

二、整体架构图(文字版)

┌──────────────┐    HTTPS     ┌──────────────┐    stream     ┌──────────────┐
│  Cline/Cursor│ ───────────▶ │  Nginx 网关  │ ────────────▶ │ mcp-server-1 │
└──────────────┘   SSE/JSON   │  (failover)  │   :9090       └──────────────┘
                              │              │                ┌──────────────┐
                              │              │ ──────────────▶│ mcp-server-2 │
                              └──────┬───────┘                └──────────────┘
                                     │ upstream fail
                                     ▼
                              ┌──────────────┐
                              │ HolySheep AI │  ← 国内直连 <50ms
                              │  /v1/chat    │
                              └──────────────┘

三、Docker 化 MCP Server

我用的是官方 @modelcontextprotocol/server-filesystem,外面包一层 Node 22 镜像。先看 Dockerfile:

# Dockerfile.mcp
FROM node:22-alpine
RUN apk add --no-cache tini curl
WORKDIR /app
COPY package.json ./
RUN npm install --omit=dev
COPY . .
EXPOSE 9090
ENTRYPOINT ["/sbin/tini","--"]
CMD ["node","server.js","--port=9090","--transport=streamable-http"]

对应的 docker-compose.yml 起两实例:

version: "3.9"
services:
  mcp-1:
    build: ./mcp
    container_name: mcp-1
    restart: always
    environment:
      - HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1
      - HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
      - NODE_ID=mcp-1
    networks: [mcpnet]

  mcp-2:
    build: ./mcp
    container_name: mcp-2
    restart: always
    environment:
      - HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1
      - HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
      - NODE_ID=mcp-2
    networks: [mcpnet]

  nginx:
    image: nginx:1.27-alpine
    ports: ["443:443","9090:9090"]
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on: [mcp-1, mcp-2]
    networks: [mcpnet]

networks:
  mcpnet:
    driver: bridge
💡 实测小坑:HOLYSHEEP_API_KEY 一定不要写死在镜像里,建议用 Docker secret 或 .env 文件挂载,避免 key 泄露后整个账号被刷爆。

四、Nginx 四层网关 + 健康检查 + 故障转移

这里我用的是 stream 模块而不是 http,因为 MCP 走的是 streamable-HTTP/SSE 混合协议,用七层 proxy_pass 会丢 chunk。配置如下:

# nginx.conf
worker_processes auto;
events { worker_connections 4096; }

stream {
    upstream mcp_cluster {
        # 关键:max_fails + fail_timeout 决定故障转移速度
        server mcp-1:9090 max_fails=2 fail_timeout=10s;
        server mcp-2:9090 max_fails=2 fail_timeout=10s;
    }

    # 健康检查:主动探测 /healthz,3 秒一次,失败 2 次摘除
    health_check interval=3000 fails=2 passes=1 uri=/healthz match=ok;

    server {
        listen 9090 so_keepalive=on;
        proxy_pass mcp_cluster;
        proxy_connect_timeout 2s;
        proxy_timeout 300s;
        proxy_next_upstream on;
        proxy_next_upstream_tries 2;
        proxy_next_upstream_timeout 5s;
    }
}

这套配置跑下来,从 mcp-1 宕机到流量切到 mcp-2,实测 1.8 秒(来源:curl 压测 + 日志时间戳对齐)。比我之前用的 HAProxy + keepalived 方案快 3 倍。

五、价格与性能实测对比

既然是测评,我把几家主流供应商的 output 价格拉出来算了一笔账(2026 年 4 月公开报价,按 1 亿 token / 月计算):

模型OpenAI 官方 $/MTokHolySheep $/MTok月度差额 (1B tok)
GPT-4.1$8.00$8.00 (按官方价)$0
Claude Sonnet 4.5$15.00$15.00$0
Gemini 2.5 Flash$2.50$2.50$0
DeepSeek V3.2$0.42$0.42$0
付款汇率信用卡 1:7.3 + 1.5% 手续费微信 / 支付宝 ¥1=$1 无损每月 1B token 约省 ¥36,500

价格透明、模型不缩水,光这一条就值得换。再加上国内直连 < 50ms 的延迟(OpenAI 官方直连我这边 380ms,差距是 7.6 倍),整套 MCP 调用链路 P99 延迟从 1.2s 降到 280ms。

六、社区口碑

七、我的实战经验

我在 3 月初第一次部署时,Nginx 日志里疯狂报 upstream timed out,排查了 2 小时才发现是 proxy_timeout 300s 没设,SSE 长连接被 Nginx 主动掐掉了。把这个值调到 300s 后告警消失。所以建议凡是跑 SSE 的 MCP 服务,proxy_timeout 一定要 ≥ 业务最长工具调用时间

第二个坑是故障转移后客户端报错。我用的 Cline v0.18 在切换 upstream 后会发一个 initialize 重连,但 MCP 协议要求 session id 复用,导致第一次握手失败。我的解决方案是在 Nginx 里加 proxy_next_upstream on同时保留原始 session header,让 Cline 自动重试 0 次即可恢复。

常见报错排查

❌ 报错 1:502 Bad Gateway + 日志显示 no live upstreams

原因:两个 MCP 容器同时被 health_check 摘除(偶发于 CPU 抢占)。

解决:把 health_checkfails=2 调到 fails=3,并给容器加 CPU 限额:

services:
  mcp-1:
    deploy:
      resources:
        limits:
          cpus: "1.0"

❌ 报错 2:SSE 长连接 60 秒断开

原因:Nginx 默认 proxy_read_timeout 是 60s。

解决:在 stream 块里显式覆盖:

proxy_timeout 300s;
proxy_read_timeout 300s;

❌ 报错 3:upstream prematurely closed connection + HTTP 502

原因:MCP Server 内部 panic 但 Docker 没拉起(restart: always 在某些内核下不生效)。

解决:改用 restart: unless-stopped 并配合 --health-cmd

mcp-1:
  restart: unless-stopped
  healthcheck:
    test: ["CMD","curl","-f","http://localhost:9090/healthz"]
    interval: 5s
    retries: 3

八、推荐人群 & 不推荐人群

如果你也想试这套架构,可以先在 HolySheep 控制台拿一个免费 key(注册即送额度),再把上面的 docker-compose.yml 复制过去改个 key 就能跑。整套迁移我用了 4 小时,回报是 Agent 一周零事故。

👉 免费注册 HolySheep AI,获取首月赠额度

```