JAiRouter 架构揭秘:一个面向 AI 时代的响应式网关设计

发布于:2025-08-19 ⋅ 阅读:(35) ⋅ 点赞:(0)

JAiRouter 架构揭秘:一个面向 AI 时代的响应式网关设计

关键词:Spring WebFlux、响应式、AI 网关、负载均衡、熔断、限流、可观测性


1. 为什么需要 JAiRouter?

大模型即服务(MaaS) 的时代,一个业务系统往往需要同时对接 GPUStack / Ollama / vLLM / OpenAI 等多种后端。
传统做法是在每个业务模块里各自维护一套调用逻辑,带来的痛点显而易见:

痛点 场景示例
协议差异 GPUStack 要求 HTTP+JSON,OpenAI 兼容 SSE,ollama 仅支持 chat,向量化
流量不均 某一台 GPU 机器被突发流量打满,其余机器空闲
故障放大 当 Ollama 实例异常时,上游服务无熔断,拖垮整站
配置漂移 每上线一台新机器,需要到 N 个业务系统改配置

JAiRouter 的定位就是 “AI 世界的流量中枢”

通过统一的、响应式的、可观测的网关,把后端差异、流量调度、故障自愈、动态配置全部收敛到一个平台。


2. 一张图看懂整体架构

后端服务
适配器层
网关层
客户端层
GPUStack
Ollama
VLLM
OpenAI
GPUStack适配器
Ollama适配器
VLLM适配器
OpenAI适配器
统一API网关
负载均衡器
限流器
熔断器
Web客户端
移动应用
第三方服务
  • 客户端层:任何符合 OpenAI 格式的 HTTP 调用方即可接入,零改造。
  • 网关层:负责统一入口、路由、负载、限流、熔断。
  • 适配器层:把 JAiRouter 的请求翻译成后端能听懂的“方言”。
  • 后端服务:真正的 GPU 算力节点或第三方 SaaS。

3. 核心模块全景

下面按“从北到南”的顺序,拆解 7 个核心模块。

3.1 控制器层(Controller Layer)

UniversalController
Chat API
Embedding API
Rerank API
TTS API
STT API
Image API
  • UniversalController 对外暴露 100% OpenAI 兼容 的 RESTful 接口,让前端/业务方无感切换。
  • ModelManagerController 提供 /admin/models 等运维端点,支持 热更新 实例列表。
  • AutoMergeController 监听 本地配置文件,秒级合并 配置文件并推送到所有节点,无需重启。

3.2 服务层(Service Layer)

ModelServiceRegistry
LoadBalancerFactory
RateLimiterFactory
CircuitBreakerFactory
ConfigurationService
HealthCheckService

一句话总结:“所有策略都是插件”

  • LoadBalancerFactory 随机 / 轮询 / 最少连接 / IP Hash,四种算法随时切换。
  • RateLimiterFactory 令牌桶 / 漏桶 / 滑动窗口 / 预热,支持 按 IP、按模型 双重维度隔离。
  • CircuitBreakerFactory 基于 失败率 + 半开探测 的经典熔断,30 秒无心跳自动摘除。

3.3 适配器层(Adapter Layer)

BaseAdapter
GPUStackAdapter
OllamaAdapter
VLLMAdapter
OpenAIAdapter
推理引擎 适配器
GpuStack GpuStackAdapter
Ollama OllamaAdapter
vLLM VLLMAdapter
OpenAI OpenAIAdapter

所有适配器实现 BaseAdapter 接口,开发者在 10 行代码 内即可新增一家后端。

3.4 负载均衡层(Load Balancer Layer)

LoadBalancer接口
Random
RoundRobin
LeastConnections
IPHash
  • LeastConnections 在 GPU 机器显存/Token 吞吐量不均时尤其有效。
  • IPHash 用于“长会话”场景,保证同一客户端多次请求落到同一实例,避免重复加载 LoRA。

3.5 限流层(Rate Limiting Layer)

RateLimiter接口
TokenBucket
LeakyBucket
SlidingWindow
WarmUp
  • TokenBucket 适合突发流量(如秒杀问答)。
  • WarmUp 在新节点加入集群时缓慢放量,防止冷启动打爆显存。

3.6 熔断层(Circuit Breaker Layer)

失败率>阈值
超时30s
连续成功>5
再次失败
CLOSED
OPEN
HALF_OPEN
  • 状态机完全基于 Reactor 实现,无锁、无阻塞。
  • 支持 按模型、按实例 双维度熔断,粒度更细。

3.7 存储层(Storage Layer)

ConfigStore接口
MemoryConfigStore
FileConfigStore
  • MemoryConfigStore:纳秒级读取,用于运行时策略。
  • FileConfigStore:基于 Git 的版本化管理,支持 一键回滚

4. 技术栈 & 设计原则

类别 选型 理由
语言 Java 17 LTS + 虚拟线程预览
框架 Spring Boot 3.5.x + WebFlux 原生响应式,背压友好
构建 Maven 3.8 + Wrapper CI/CD 零依赖
文档 SpringDoc OpenAPI 自动生成,可在线调试
监控 Micrometer + Actuator 对接 Prometheus + Grafana
代码质量 Checkstyle + SpotBugs + JaCoCo PR 即检测,覆盖率 80%+

设计原则 4 句话 讲完:

  1. 响应式:所有 I/O 非阻塞。
  2. 模块化:每个策略都是接口 + 自动装配,拔插无重启
  3. 可观测:指标、追踪、日志三位一体,出问题 5 分钟定位

5. 扩展点实战:10 分钟接入「Xinference」

本节以 Xorbits Inference(Xinference) 为例,完整演示“零侵入”接入一个新的推理后端。
只要 3 步,不重启、不发布、不改动业务代码


5.1 需求背景

业务方已有 3 条 GPU 机器,希望把 Xinference 作为第 4 条算力池,并满足:

  1. 复用现有 /v1/chat/completions 接口,前端无感;
  2. 支持 流式/非流式 双模式;
  3. 沿用 JAiRouter 的负载、限流、熔断策略。

5.2 步骤 1:实现 Adapter(3 分钟)

新建 XinferenceAdapter.java核心代码 60 行

package org.unreal.modelrouter.adapter.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Component;
import org.unreal.modelrouter.adapter.AdapterCapabilities;
import org.unreal.modelrouter.adapter.BaseAdapter;
import org.unreal.modelrouter.dto.ChatDTO;
import org.unreal.modelrouter.model.ModelServiceRegistry;
import org.unreal.modelrouter.monitoring.collector.MetricsCollector;

/**
 * Xinference Adapter
 * Xinference 与 OpenAI v1 协议 100% 兼容,仅需补充缺失字段
 */
@Component
public class XinferenceAdapter extends BaseAdapter {

    private final ObjectMapper om = new ObjectMapper();

    public XinferenceAdapter(ModelServiceRegistry registry, MetricsCollector collector) {
        super(registry, collector);
    }

    @Override
    public AdapterCapabilities supportCapability() {
        return AdapterCapabilities.all();   // 支持 chat / embedding / tts / stt ...
    }

    @Override
    protected String getAdapterType() {
        return "xinference";
    }

    /* ---------- 请求转换 ---------- */
    @Override
    protected Object transformRequest(Object req, String adapterType) {
        if (req instanceof ChatDTO.Request r) {
            ObjectNode node = om.createObjectNode();
            node.put("model", r.model());
            node.set("messages", om.valueToTree(r.messages()));
            if (r.temperature() != null) node.put("temperature", r.temperature());
            if (r.maxTokens() != null) node.put("max_tokens", r.maxTokens());
            if (r.stream() != null) node.put("stream", r.stream());
            return node;
        }
        return req; // embedding / tts / stt 同理
    }

    /* ---------- 响应增强 ---------- */
    @Override
    protected String transformStreamChunk(String chunk) {
        // 若 chunk 中无 system_fingerprint,补充
        if (chunk.startsWith("data: ")) {
            try {
                String json = chunk.substring(6);
                if ("[DONE]".equals(json.trim())) return chunk;
                ObjectNode node = (ObjectNode) om.readTree(json);
                if (!node.has("system_fingerprint")) {
                    node.put("system_fingerprint", "xinference-adapter");
                }
                return "data: " + node;
            } catch (Exception ignored) {}
        }
        return chunk;
    }
}

要点

  • 继承 BaseAdapter 即可拿到 负载、限流、熔断、重试 等全部能力;
  • 只实现差异处:Xinference 与 OpenAI 协议一致,只需 补全缺失字段(如 system_fingerprint)。

5.3 步骤 2:声明式配置(1 分钟)

在 Git 仓库的 application-xinference.yml 中新增:

jairouter:
  adapters:
    xinference:
      enabled: true
      hosts:
        - http://10.0.0.21:9997   # GPU-4
        - http://10.0.0.22:9997   # GPU-5
      load-balancer: round-robin   # 可选 random / least-connections / ip-hash
      rate-limit:
        permits-per-second: 100
        burst-capacity: 200
      circuit-breaker:
        failure-rate-threshold: 0.5
        wait-duration: 30s

5.4 步骤 3:Git Push → 30 秒生效(无需重启)

git add application-xinference.yml
git commit -m "feat: add xinference backend"
git push origin main
  • JAiRouter 监听配置仓库的 Webhook,30 秒内把新配置热加载到全部节点;
  • 业务方立即可以通过 /v1/chat/completions 访问 Xinference 算力,前端 0 改动

5.5 验证

curl -X POST https://gateway.example.com/v1/chat/completions \
  -H "Authorization: Bearer sk-xxx" \
  -d '{
        "model": "xinference-llama3-8b",
        "messages": [{"role":"user","content":"你好"}],
        "stream": true
      }'

返回:

data: {"id":"xinference-123","object":"chat.completion.chunk",...,"system_fingerprint":"xinference-adapter"}
...
data: [DONE]

5.6 效果

指标 结果
新增代码行数 60 行
上线耗时 1 次 Git Push ≈ 30 秒
业务改动 0
是否重启

只要遵循 Adapter + 配置即代码 范式,任何推理引擎 都可以在 10 分钟内接入 JAiRouter。

6. 结语:面向未来的 AI 网关

JAiRouter 把 “协议差异、流量调度、故障自愈、配置管理” 四大痛点抽象成四大模块,通过响应式编程 + 配置即代码,让 AI 算力像自来水一样随开随用

  • 开源仓库:https://github.com/Lincoln-cn/jairouter
  • 商业支持:发送邮件至 sodlinken@gmail.com

如果这篇文章对你有帮助,别忘了 点赞 + 收藏 + 关注三连
评论区欢迎交流落地经验,下一个版本的功能可能由你决定!


网站公告

今日签到

点亮在社区的每一天
去签到