Spring Boot 与 Go 双服务架构实践:从单体拆分到通信设计

当一个项目同时需要"稳定的业务层"和"高性能的 AI 编排层"时,单一语言往往不够用。本文分享"领航英语"如何用 Spring Boot + Go 构建双服务架构,以及其中的通信、部署和权衡。


为什么拆成两个服务

项目初期是 Spring Boot 单体,所有逻辑在一个进程里。当 AI 功能加入后,问题出现了:

1. 并发模型冲突

Spring Boot 的 Tomcat 线程池处理 HTTP 请求,每个请求占用一个线程。AI 调用(特别是流式 SSE)可能持续数十秒,长时间占用线程池资源。而 Go 的 goroutine 处理长连接几乎零成本。

2. 部署节奏不同

业务层(用户、会员、订单)变更频率低,要求极高稳定性。AI 层(Prompt 优化、模型切换、RAG 策略)迭代非常快,有时一天发好几版。放在同一个服务里,发版互相阻塞。

3. 语言能力匹配

Java 生态在 ORM、事务、权限框架上成熟可靠。Go 在并发、流式处理、对 LLM SDK 的支持上更灵活。用各自擅长的语言做各自擅长的事。


架构总览

复制代码
浏览器 / 移动端
      │
      ▼
   Nginx (反向代理 + SSL)
      │
      ├── /api/*  ──→  Spring Boot (8080)  ──→  PostgreSQL
      │                  用户/词库/会员/订单           Redis
      │                         │
      │                   内网 REST 调用
      │                         │
      └── (前端直连 AI 服务的 SSE 流量也经 Nginx 代理)
                              │
                              ▼
                       Go AI 服务 (8090)  ──→  LLM API
                          AI 编排/流式/            Qdrant
                          Prompt 管理

关键设计决策:前端不直连 AI 服务。所有请求先到 Spring Boot,由它决定哪些需要转发给 Go 服务。这样 AI 服务不需要关心认证鉴权,完全内网通信。


服务间通信

场景一:普通 AI 请求(非流式)

复制代码
前端 → Spring Boot Controller → AiGatewayService → RestClient → Go 服务 → 返回 JSON

Spring Boot 侧用 RestClient(Spring 6 新 API,替代 RestTemplate):

java 复制代码
@Service
public class AiGatewayService {
    private final RestClient restClient;

    public AiGatewayService(@Value("${ai-service.url}") String aiServiceUrl) {
        this.restClient = RestClient.create(aiServiceUrl);
    }

    public VocabExplainResponse explainVocab(VocabExplainRequest request) {
        return restClient.post()
            .uri("/v1/explain-vocab")
            .body(request)
            .retrieve()
            .body(VocabExplainResponse.class);
    }
}

场景二:流式 SSE 请求

SSE 不能简单转发------Spring Boot 需要把 Go 返回的流"透传"给前端:

java 复制代码
@PostMapping("/explain-vocab/stream")
public Flux<ServerSentEvent<String>> explainVocabStream(@RequestBody VocabExplainRequest req) {
    // 校验会员
    membershipService.requireActive(userId);

    // 转发到 Go 服务
    return webClient.post()
        .uri(aiServiceUrl + "/v1/explain-vocab/stream")
        .bodyValue(req)
        .retrieve()
        .bodyToFlux(String.class)
        .map(data -> ServerSentEvent.<String>builder()
            .data(data)
            .build());
}

用 Spring WebFlux 的 Flux 做响应式透传,不阻塞 Tomcat 线程。


Go 服务的多模型路由

Go 侧的核心价值之一是多 LLM 供应商路由。根据配置和可用性自动选择:

go 复制代码
type LLMClient struct {
    providers map[string]Provider
    fallback  []string  // 降级顺序
}

func (c *LLMClient) ChatCompletionStream(ctx context.Context, req Request) (<-chan Chunk, error) {
    for _, name := range c.fallback {
        provider := c.providers[name]
        if !provider.IsAvailable(ctx) {
            continue
        }
        stream, err := provider.Stream(ctx, req)
        if err == nil {
            return stream, nil
        }
        log.Warn("provider %s failed, trying next", name)
    }
    // 所有真模型都不可用时,使用 mock 降级
    return c.mockStream(req)
}

支持的供应商:DeepSeek、百炼(阿里通义千问)、Clawvard(Anthropic 兼容)。配置方式:

yaml 复制代码
# ai-service config
llm:
  providers:
    - name: deepseek
      api_key: ${DEEPSEEK_API_KEY}
      base_url: https://api.deepseek.com
      priority: 1
    - name: bailian
      api_key: ${BAILIAN_API_KEY}
      base_url: https://dashscope.aliyuncs.com
      priority: 2
  mock_fallback: true

没有配置任何 API Key 时,mock 模式模拟流式输出,方便本地开发。


部署:Docker Compose 一体化

8 个容器,一个 compose 文件:

yaml 复制代码
services:
  postgres:   image: postgres:16
  redis:      image: redis:7.2
  qdrant:     image: qdrant/qdrant:v1.12.4
  backend:    build: ./backend     # Spring Boot
  ai-service: build: ./ai-service  # Go
  pc-web:     build: ./frontend/pc    # Vue 3 PC 端
  mobile-web: build: ./frontend/mobile # Vue 3 移动端
  admin-web:  build: ./frontend/admin  # Vue 3 运营端

Nginx 在最外层做域名路由:m.dobell.top → mobile-web,pc.dobell.top → pc-web,admin.dobell.top → admin-web,/api/ 路由到 backend。


权衡与教训

好处

  • AI 服务可以独立扩缩容(需要时多起几个实例)
  • 两种语言各司其职,团队分工清晰
  • AI 服务崩溃不影响用户登录、订单等核心业务

代价

  • 增加了一次网络调用的延迟(内网约 2-5ms,可接受)
  • 两套日志、两套部署、两套监控
  • 开发环境需要同时启动两个服务(但 docker compose 一键搞定)

什么时候不该拆:如果 AI 调用只是简单的 API 包装(没有复杂的 prompt 编排和流式处理需求),放在 Spring Boot 里完全够用。为了拆而拆只会增加复杂度。


以上是领航英语(m.dobell.top)的后端架构实践。前端是 Vue 3 卡片滑动交互,后端是 Spring Boot + Go 双服务,覆盖自考、学位、高考、四六级等 10 个英语考试场景。3 天免费试用,月卡 29 元。

相关推荐
葫芦和十三25 分钟前
图解 MongoDB 23|两地三中心:跨可用区部署怎么扛机房故障
后端·mongodb·agent
灵感__idea2 小时前
《AI工程》:为什么需要RAG和智能体?
aigc·openai·ai编程
勇哥java实战分享2 小时前
PaddleOCR 太慢?我换成 RapidOCR 后,速度直接起飞
后端
kyriewen3 小时前
Anthropic 估值逼近万亿美元,Claude Sonnet 5 + Claude Science 一天两连发
前端·ai编程·claude
冬奇Lab4 小时前
Workflow 系列(04):Multi-Agent 协调——编排器边界、并发控制与上下文隔离
人工智能·工作流引擎
冬奇Lab4 小时前
每日一个开源项目(第147篇):HyperGraphRAG - 用超图表示 N 元关系,RAG 的第三代范式
人工智能·开源·graphql
甲维斯4 小时前
Github + 阿里云oss实现类似codex的自动更新!
人工智能
阿里云大数据AI技术6 小时前
光轮智能 × 阿里云:共建 Physical AI 云上数据、评测与持续学习基础设施
人工智能·机器学习