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 元。

相关推荐
柒和远方1 小时前
后端认证、鉴权、高并发:从 Session 到 JWT 再到 Redis
前端·后端·面试
piglet121381 小时前
把搜索调到 Claude.ai 的水准
前端·人工智能
Linlingu1 小时前
openClaw不能操作我的电脑提示没有权限如何解决?
人工智能·windows·办公自动化·数字员工·小龙虾
这个DBA有点耶1 小时前
索引优化深潜(下):索引合并、ICP 与索引设计的实战法则
数据库·mysql·架构
snpgroupcn1 小时前
SNP亮相2026思爱普中国峰会,助力企业加速数据价值兑现
人工智能
IT乐手1 小时前
Anthropic 为何限制中国大陆使用 Claude?
人工智能
To_OC1 小时前
用 ESM 模块化搭建 DeepSeek LLM 调用,顺带用 Prompt 实现轻量 NLP 任务
人工智能·nlp·deepseek
jrjrgood1 小时前
现货黄金和黄金期货的区别有哪些?如何投资?
大数据·人工智能·区块链
属于自己的天空1 小时前
确认弹窗太多?一次配好 Claude Code 权限,安心让 AI 干活
人工智能