13 - 部署与分布式架构

从单机到分布式的平滑迁移、Docker部署与配置管理

一、部署架构

              完整部署架构
              ══════════════

  ┌─────────────────────────────────────────────────────┐
  │                    Nginx (反向代理)                   │
  │         SSE长连接支持 + 静态资源 + 负载均衡          │
  └──────────────────────┬──────────────────────────────┘
                         │
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
  │  App实例 1   │ │  App实例 2   │ │  App实例 3   │
  │  (Spring Boot)│ │  (Spring Boot)│ │  (Spring Boot)│
  └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
         │                │                │
         └────────────────┼────────────────┘
                          │
  ┌───────────┬───────────┼───────────┬───────────┐
  │           │           │           │           │
  ▼           ▼           ▼           ▼           ▼
┌─────┐  ┌────────┐  ┌────────┐  ┌───────┐  ┌───────┐
│MySQL│  │Milvus  │  │ Redis  │  │RocketMQ│  │Nacos  │
│ 8.0 │  │ 2.6.0  │  │Cluster │  │ 4.9.6 │  │ 2.3.2 │
│     │  │        │  │ (3节点) │  │       │  │       │
└─────┘  └────────┘  └────────┘  └───────┘  └───────┘

二、Docker Compose部署

项目提供了一键启动脚本 docker/cluster-runtime/setup.sh

docker-compose.cluster.yml 服务清单:

  中间件层:
  ├── mysql        MySQL 8.0        数据持久化
  ├── milvus-standalone  Milvus 2.6  向量数据库
  ├── milvus-etcd         etcd       Milvus元数据
  ├── milvus-minio        MinIO      Milvus对象存储
  ├── redis-node-1/2/3    Redis 7    3节点Cluster
  ├── rocketmq-namesrv    RocketMQ   消息队列
  ├── rocketmq-broker     RocketMQ   消息代理
  ├── nacos               Nacos 2.3  配置中心
  └── gpt4free            GPT4Free   免费AI模型

  一键启动:
  $ bash docker/cluster-runtime/setup.sh
  → 自动拉取镜像 → 启动所有服务 → 初始化数据库 → 健康检查

三、分布式运行时 — SPI架构

项目的分布式能力通过SPI(Service Provider Interface)架构实现,每个子系统可独立选择LOCAL或REDIS模式:

分布式运行时SPI:

  hub-common 定义10个SPI接口:
  ┌──────────────────────────────────────────────────────┐
  │ ActiveTaskStore        ← 活跃任务追踪               │
  │ CircuitBreakerStateStore ← 熔断器状态               │
  │ InboundDedupeStore     ← 入站消息去重               │
  │ ChannelSessionStore    ← 通道会话绑定               │
  │ CanaryTokenStore       ← 金丝雀令牌存储             │
  │ InjectionRateLimiterStore ← 注入限流计数            │
  │ UserRateLimiterRuntime ← 用户并发控制               │
  │ LoginRateLimiterRuntime ← 登录限流                  │
  │ KeyPoolRuntimeStateStore ← 密钥池状态同步           │
  │ TaskRuntimeStore       ← 任务运行时状态             │
  └──────────────────────────────────────────────────────┘

  每个SPI有LOCAL和REDIS两个实现:
  ┌──────────────────────────────────────────┐
  │ distributed-config.yml:                  │
  │                                          │
  │ hub.distributed:                         │
  │   mode: redis          # 全局默认        │
  │   active-task: local   # 按子系统覆盖    │
  │   circuit-breaker: redis                  │
  │   canary-token: redis                    │
  │   key-pool: redis                        │
  │                                          │
  │ → 可以混合使用!                          │
  │ → 不重要的用LOCAL,重要的用REDIS         │
  └──────────────────────────────────────────┘

四、Redis在分布式中的角色

功能Redis数据结构说明
Key池状态同步Hash + String多实例共享Key状态(ACTIVE/COOLING/DISABLED)
熔断器状态Lua脚本 + String原子状态转换,跨实例共享熔断状态
金丝雀令牌String (TTL 30天)多实例共享相同的canary token
消息去重SETNX (TTL)防止多实例重复处理同一消息
通道会话Hash用户在哪个实例上的哪个Agent对话
注入限流Sorted Set按用户ID统计注入尝试次数
轮询索引INCRKey轮询的原子计数器

五、RocketMQ消息驱动

RocketMQ Topic 分布:

  ┌──────────────────────────────────────────────────┐
  │ Topic: TASK_RETRY                                │
  │ 用途: 失败任务的异步重试                         │
  │ → TaskScheduler消费 → 重新提交到AgentExecutor    │
  ├──────────────────────────────────────────────────┤
  │ Topic: KEY_POOL_REFRESH                          │
  │ 用途: 密钥池配置变更通知                         │
  │ → 所有实例消费 → 热更新内存中的Key池             │
  ├──────────────────────────────────────────────────┤
  │ Topic: CHANNEL_INGEST                            │
  │ 用途: 通道消息入站处理(如QQ频道)              │
  │ → 异步消费 → 调用Agent编排器                    │
  └──────────────────────────────────────────────────┘

六、模块化单体 → 分布式的平滑迁移

平滑迁移策略:

  阶段1: 单实例 (LOCAL模式)
  ┌───────────────────────────────────────┐
  │ 所有SPI使用LOCAL实现                  │
  │ · 无需Redis/RocketMQ                 │
  │ · 所有状态在内存中                    │
  │ · 适合开发和低流量场景                │
  └───────────────────────────────────────┘
           │ 修改配置文件即可
           ▼
  阶段2: 分布式 (REDIS模式)
  ┌───────────────────────────────────────┐
  │ 按需切换SPI到REDIS实现               │
  │ · 可以逐个子系统迁移                  │
  │ · 先迁移最重要的(Key池、熔断器)    │
  │ · 后迁移次要的(登录限流、去重)      │
  │ · LOCAL实现作为Redis故障时的降级后备  │
  └───────────────────────────────────────┘

  关键设计:
  · Redis不可用时自动降级到LOCAL
  · 每个子系统独立选择模式
  · 不需要修改任何业务代码

七、配置管理

项目的配置文件按职责分离:

配置文件职责
application.yml主配置(数据库、Redis、RocketMQ、Nacos)
agent-config.ymlAgent ReAct/工具/并行配置
model-catalog.yml可用LLM模型列表
llm-config.ymlLLM供应商设置
security-config.ymlJWT和提示词防护
distributed-config.yml分布式运行时模式选择
orchestrator-config.yml编排器线程池/超时/熔断
search-rag-config.ymlRAG引擎/分块/缓存

八、面试高频问题

Q: 为什么选择模块化单体而不是微服务?
A: 模块化单体在保持代码模块化的同时,避免了微服务的分布式复杂度。12个Maven模块职责清晰、边界明确,但部署为单个应用。优势:1) 开发效率高:无RPC调用开销,调试方便;2) 运维简单:只需部署一个应用;3) 可按需演进:当某个模块确实需要独立扩展时,可以拆分为微服务,因为模块边界已经清晰。这在项目初期是最务实的选择。
Q: Redis不可用时系统会怎样?
A: 系统设计了优雅降级机制。每个SPI的Redis实现在捕获到Redis异常后,会自动切换到LOCAL实现。例如:Key池状态从Redis同步失败,就使用内存中的本地状态;熔断器Redis操作失败,就使用本地内存熔断。降级后功能不受影响,只是在多实例间不再共享状态。运维会通过DistributedRuntimeMetrics监控到降级事件。
Q: 如何实现灰度发布?
A: 项目文档描述了12步有序灰度切换流程:1) 部署新版本到部分实例;2) Nginx配置权重路由(如90%旧版本+10%新版本);3) 验证新版本功能正常;4) 逐步增加新版本权重;5) 全量切换。每个步骤都有门控验证,失败时按逆序回滚。Redis Cluster和MySQL共享数据层确保两个版本的数据一致。