# 多渠道负载均衡与智能切换

本文档详细说明 Coding-Tool 的多渠道负载均衡系统的设计和工作原理。

## 功能概述

多渠道负载均衡系统允许用户配置多个 API 渠道，系统会根据权重、并发限制和健康状态智能分配请求，实现：

- **负载分散**：将请求分散到多个渠道，避免单点压力
- **故障转移**：自动检测故障渠道并切换到健康渠道
- **会话连续性**：可选的会话绑定，保证对话上下文

## 模块架构

```
┌─────────────────────────────────────────────────────────────────┐
│                        proxy-server.js                          │
│                      (代理服务器入口)                            │
└─────────────────────┬───────────────────────────────────────────┘
                      │ 请求分配 / 结果记录
                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                    channel-scheduler.js                         │
│                      (渠道调度器)                                │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │ 加权随机选择 │  │ 并发控制    │  │ 会话绑定    │             │
│  └─────────────┘  └─────────────┘  └─────────────┘             │
└─────────────────────┬───────────────────────────────────────────┘
                      │ 健康检查
                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                     channel-health.js                           │
│                      (健康检查模块)                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │ 故障检测    │  │ 冻结管理    │  │ 自动恢复    │             │
│  └─────────────┘  └─────────────┘  └─────────────┘             │
└─────────────────────────────────────────────────────────────────┘
```

## 核心模块说明

### 1. channel-scheduler.js（渠道调度器）

负责请求的渠道分配和并发控制。

#### 主要功能

| 功能 | 说明 |
|------|------|
| `allocateChannel()` | 分配一个可用渠道 |
| `releaseChannel()` | 释放渠道（请求完成时调用） |
| `getSchedulerState()` | 获取调度器状态 |

#### 加权随机算法

```javascript
// 权重越高，被选中概率越大
// 例如：渠道A(权重2) + 渠道B(权重1) + 渠道C(权重1)
// A 被选中概率 = 2/4 = 50%
// B 被选中概率 = 1/4 = 25%
// C 被选中概率 = 1/4 = 25%
```

#### 并发控制

- `maxConcurrency = null`：无并发限制
- `maxConcurrency = N`：最多同时处理 N 个请求
- 超过并发限制的请求进入队列等待（最长 15 秒）

#### 会话绑定（可选）

- **开启时**：同一 sessionId 的请求始终使用同一渠道
- **关闭时**：每次请求独立进行加权随机分配
- 配置位置：设置 → 高级设置 → 多渠道负载会话绑定

### 2. channel-health.js（健康检查模块）

负责监控渠道健康状态，自动冻结故障渠道。

#### 状态流转

```
         连续成功5次
    ┌──────────────────┐
    │                  │
    ▼                  │
┌────────┐  连续失败3次  ┌──────────┐  冻结到期  ┌──────────┐
│ healthy │────────────►│  frozen  │──────────►│ checking │
│ (健康)  │             │  (冻结)  │           │ (检测中) │
└────────┘              └──────────┘           └────┬─────┘
    ▲                        ▲                      │
    │                        │    连续失败3次       │
    │                        └──────────────────────┘
    │         连续成功5次
    └──────────────────────────────────────────────┘
```

#### 冻结时间策略

| 次数 | 冻结时间 |
|------|----------|
| 第1次 | 1 分钟 |
| 第2次 | 2 分钟 |
| 第3次 | 4 分钟 |
| 第4次 | 8 分钟 |
| 第5次 | 16 分钟 |
| 第6次+ | 30 分钟（上限）|

#### 恢复检测

- 冻结到期后，渠道进入"检测中"状态
- 使用真实请求进行健康检测（被动检测，不消耗额外配额）
- 连续 5 次成功后恢复为"健康"状态
- 检测期间失败则重新冻结

### 3. proxy-server.js（代理服务器）

负责接收请求、转发到选定渠道、记录结果。

#### 请求处理流程

```
1. 接收请求
   │
2. 调用 allocateChannel() 获取渠道
   │
3. 转发请求到渠道
   │
4. 等待响应
   │
   ├── 成功 → recordSuccess() → 更新健康状态
   │
   └── 失败 → recordFailure() → 可能触发冻结
   │
5. 调用 releaseChannel() 释放并发位
```

## 配置参数

### 渠道配置

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `name` | string | - | 渠道名称 |
| `baseUrl` | string | - | API 地址 |
| `apiKey` | string | - | API 密钥 |
| `enabled` | boolean | true | 是否启用 |
| `weight` | number | 1 | 权重（越高越容易被选中）|
| `maxConcurrency` | number/null | null | 最大并发（null=不限制）|

### 全局配置

| 参数 | 位置 | 默认值 | 说明 |
|------|------|--------|------|
| `enableSessionBinding` | 高级设置 | true | 是否启用会话绑定 |

### 健康检查配置

| 参数 | 值 | 说明 |
|------|-----|------|
| `failureThreshold` | 3 | 连续失败多少次触发冻结 |
| `initialFreezeTime` | 60秒 | 初始冻结时间 |
| `maxFreezeTime` | 30分钟 | 最大冻结时间 |
| `freezeMultiplier` | 2 | 冻结时间倍增系数 |
| `healthCheckWindow` | 5 | 恢复需要连续成功次数 |

## 使用场景

### 场景1：多渠道负载均衡

```
配置：
- 渠道A：权重=2, 并发=不限制
- 渠道B：权重=1, 并发=不限制
- 渠道C：权重=1, 并发=不限制

效果：
- A 处理 50% 的请求
- B 处理 25% 的请求
- C 处理 25% 的请求
```

### 场景2：主备切换

```
配置：
- 主渠道：权重=100, 并发=不限制
- 备渠道：权重=1, 并发=不限制

效果：
- 正常情况：几乎所有请求走主渠道
- 主渠道故障：自动切换到备渠道
- 主渠道恢复：自动切回主渠道
```

### 场景3：并发控制

```
配置：
- 渠道A：权重=1, 并发=2
- 渠道B：权重=1, 并发=2

效果：
- 同时最多 4 个请求（每个渠道 2 个）
- 超过 4 个请求时排队等待
```

## 前端展示

### 渠道卡片状态

- 🟢 **绿色左边框**：健康状态
- 🟡 **黄色左边框 + 渐变背景**：检测中状态
- 🔴 **红色左边框 + 渐变背景**：冻结状态
- ⚪ **灰色左边框**：未启用

### 卡片信息

- `W:N`：权重值
- `C:N` 或 `C:∞`：并发限制
- 冻结标签显示剩余时间

## API 接口

### 获取渠道列表（含健康状态）

```
GET /api/channels
Response: {
  channels: [{
    id, name, baseUrl, apiKey, enabled, weight, maxConcurrency,
    health: { status, statusText, freezeRemaining, ... }
  }]
}
```

### 重置渠道健康状态

```
POST /api/channels/:id/reset-health
Response: { success: true, health: {...} }
```

## 注意事项

1. **会话绑定与故障转移**：渠道被冻结时，绑定到该渠道的会话会自动解绑
2. **被动健康检测**：不主动发送检测请求，使用真实请求检测
3. **冻结时间递增**：避免频繁检测故障渠道
4. **手动重置**：可在前端手动重置渠道健康状态
