352 lines
29 KiB
Markdown
352 lines
29 KiB
Markdown
# 第六部分:智能调度系统
|
||
|
||
## 6.1 实时链路探测
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 实时链路探测系统 │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 探测架构: │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 探测集群 │ │
|
||
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
||
│ │ │ 探测节点 │ │ 探测节点 │ │ 探测节点 │ ... │ │
|
||
│ │ │ (北京) │ │ (上海) │ │ (广州) │ │ │
|
||
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
|
||
│ │ │ │ │ │ │
|
||
│ │ └──────────────┴──────────────┘ │ │
|
||
│ │ │ │ │
|
||
│ │ ┌──────┴──────┐ │ │
|
||
│ │ │ 数据汇聚 │ │ │
|
||
│ │ │ (ClickHouse)│ │ │
|
||
│ │ └──────┬──────┘ │ │
|
||
│ │ │ │ │
|
||
│ │ ┌──────┴──────┐ │ │
|
||
│ │ │ 分析引擎 │ │ │
|
||
│ │ │ (实时计算) │ │ │
|
||
│ │ └──────┬──────┘ │ │
|
||
│ │ │ │ │
|
||
│ │ ┌──────┴──────┐ │ │
|
||
│ │ │ 调度决策 │ │ │
|
||
│ │ │ (路由更新) │ │ │
|
||
│ │ └─────────────┘ │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 探测指标: │
|
||
│ ┌──────────────┬──────────────┬──────────────┬──────────────┐ │
|
||
│ │ 指标 │ 方法 │ 频率 │ 精度 │ │
|
||
│ ├──────────────┼──────────────┼──────────────┼──────────────┤ │
|
||
│ │ Ping │ ICMP/UDP │ 每5秒 │ ±1ms │ │
|
||
│ │ Jitter │ RTT标准差 │ 每5秒 │ ±2ms │ │
|
||
│ │ Loss │ 统计法 │ 每10秒 │ ±0.1% │ │
|
||
│ │ RTT │ TCP/UDP │ 每5秒 │ ±1ms │ │
|
||
│ │ Bandwidth │ 递增探测 │ 每分钟 │ ±10% │ │
|
||
│ │ Node Load │ 心跳上报 │ 每10秒 │ ±5% │ │
|
||
│ └──────────────┴──────────────┴──────────────┴──────────────┘ │
|
||
│ │
|
||
│ 探测数据存储: │
|
||
│ - 实时数据:Redis(最新值,TTL 5分钟) │
|
||
│ - 历史数据:ClickHouse(聚合后,保留30天) │
|
||
│ - 告警数据:MySQL(持久化) │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 6.2 调度算法设计
|
||
|
||
### 6.2.1 基础版本(规则引擎)
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 基础调度算法(规则引擎) │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 输入: │
|
||
│ - 用户位置(城市、ISP) │
|
||
│ - 游戏服务器位置 │
|
||
│ - 节点列表及其状态 │
|
||
│ │
|
||
│ 输出: │
|
||
│ - 最优节点 │
|
||
│ - 路由路径 │
|
||
│ │
|
||
│ 规则优先级: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 规则1:同城市同ISP → 直连 │ │
|
||
│ │ 条件:user.city == node.city && user.isp == node.isp │ │
|
||
│ │ 动作:直接选择该节点 │ │
|
||
│ │ 优先级:1(最高) │ │
|
||
│ │ │ │
|
||
│ │ 规则2:同城市跨ISP → BGP节点 │ │
|
||
│ │ 条件:user.city == node.city && user.isp != node.isp │ │
|
||
│ │ 动作:选择BGP节点 │ │
|
||
│ │ 优先级:2 │ │
|
||
│ │ │ │
|
||
│ │ 规则3:同区域跨城市 → 区域核心节点 │ │
|
||
│ │ 条件:user.region == node.region && user.city != node.city│ │
|
||
│ │ 动作:选择区域核心节点 │ │
|
||
│ │ 优先级:3 │ │
|
||
│ │ │ │
|
||
│ │ 规则4:跨区域 → 中转节点 │ │
|
||
│ │ 条件:user.region != node.region │ │
|
||
│ │ 动作:选择最优中转节点 │ │
|
||
│ │ 优先级:4 │ │
|
||
│ │ │ │
|
||
│ │ 规则5:跨境 → 国际专线节点 │ │
|
||
│ │ 条件:user.country != node.country │ │
|
||
│ │ 动作:选择国际专线节点 │ │
|
||
│ │ 优先级:5(最低) │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 伪代码实现: │
|
||
│ │
|
||
│ func basicSchedule(user *User, game *Game) *Node { │
|
||
│ candidates := getCandidateNodes(game) │
|
||
│ │
|
||
│ // 规则1:同城市同ISP │
|
||
│ for _, node := range candidates { │
|
||
│ if node.City == user.City && node.ISP == user.ISP { │
|
||
│ return node │
|
||
│ } │
|
||
│ } │
|
||
│ │
|
||
│ // 规则2:同城市BGP │
|
||
│ for _, node := range candidates { │
|
||
│ if node.City == user.City && node.IsBGP { │
|
||
│ return node │
|
||
│ } │
|
||
│ } │
|
||
│ │
|
||
│ // 规则3:同区域核心节点 │
|
||
│ for _, node := range candidates { │
|
||
│ if node.Region == user.Region && node.IsCore { │
|
||
│ return node │
|
||
│ } │
|
||
│ } │
|
||
│ │
|
||
│ // 规则4:中转节点 │
|
||
│ bestScore := 0.0 │
|
||
│ var bestNode *Node │
|
||
│ for _, node := range candidates { │
|
||
│ score := calculateScore(node, user) │
|
||
│ if score > bestScore { │
|
||
│ bestScore = score │
|
||
│ bestNode = node │
|
||
│ } │
|
||
│ } │
|
||
│ return bestNode │
|
||
│ } │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 6.2.2 高级版本(多因子加权)
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 高级调度算法(多因子加权) │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 输入因子: │
|
||
│ ┌──────────────┬──────────┬──────────┬──────────────────────┐ │
|
||
│ │ 因子 │ 权重 │ 范围 │ 说明 │ │
|
||
│ ├──────────────┼──────────┼──────────┼──────────────────────┤ │
|
||
│ │ RTT │ 0.35 │ 0-500ms │ 往返延迟 │ │
|
||
│ │ Loss Rate │ 0.25 │ 0-100% │ 丢包率 │ │
|
||
│ │ Jitter │ 0.15 │ 0-100ms │ 抖动 │ │
|
||
│ │ Node Load │ 0.10 │ 0-100% │ 节点负载 │ │
|
||
│ │ ISP Match │ 0.05 │ 0/1 │ ISP匹配 │ │
|
||
│ │ Geo Distance │ 0.05 │ 0-10000km│ 地理距离 │ │
|
||
│ │ Line Quality │ 0.05 │ 0-1 │ 线路质量 │ │
|
||
│ └──────────────┴──────────┴──────────┴──────────────────────┘ │
|
||
│ │
|
||
│ 评分公式: │
|
||
│ │
|
||
│ Score(i) = Σ(Wj × normalize(Fij)) │
|
||
│ │
|
||
│ 其中: │
|
||
│ - Wj = 第j个因子的权重 │
|
||
│ - Fij = 节点i在第j个因子上的值 │
|
||
│ - normalize() = 归一化到[0,1]区间 │
|
||
│ │
|
||
│ 归一化方法: │
|
||
│ - RTT: norm = 1 - (RTT / max_RTT) │
|
||
│ - Loss: norm = 1 - Loss │
|
||
│ - Jitter: norm = 1 - (Jitter / max_Jitter) │
|
||
│ - Load: norm = 1 - Load │
|
||
│ - ISP Match: norm = 1 if match else 0 │
|
||
│ - Geo Distance: norm = 1 - (dist / max_dist) │
|
||
│ - Line Quality: norm = Quality_Score │
|
||
│ │
|
||
│ 伪代码实现: │
|
||
│ │
|
||
│ type ScheduleFactor struct { │
|
||
│ Name string │
|
||
│ Weight float64 │
|
||
│ MaxVal float64 │
|
||
│ } │
|
||
│ │
|
||
│ var factors = []ScheduleFactor{ │
|
||
│ {"rtt", 0.35, 500}, │
|
||
│ {"loss", 0.25, 1.0}, │
|
||
│ {"jitter", 0.15, 100}, │
|
||
│ {"load", 0.10, 1.0}, │
|
||
│ {"isp_match", 0.05, 1.0}, │
|
||
│ {"geo_dist", 0.05, 10000}, │
|
||
│ {"line_quality", 0.05, 1.0}, │
|
||
│ } │
|
||
│ │
|
||
│ func advancedSchedule(user *User, game *Game) *Node { │
|
||
│ candidates := getCandidateNodes(game) │
|
||
│ │
|
||
│ var bestNode *Node │
|
||
│ bestScore := -1.0 │
|
||
│ │
|
||
│ for _, node := range candidates { │
|
||
│ score := 0.0 │
|
||
│ │
|
||
│ // RTT因子 │
|
||
│ rttNorm := 1.0 - (node.RTT / 500.0) │
|
||
│ score += 0.35 * rttNorm │
|
||
│ │
|
||
│ // 丢包因子 │
|
||
│ lossNorm := 1.0 - node.LossRate │
|
||
│ score += 0.25 * lossNorm │
|
||
│ │
|
||
│ // 抖动因子 │
|
||
│ jitterNorm := 1.0 - (node.Jitter / 100.0) │
|
||
│ score += 0.15 * jitterNorm │
|
||
│ │
|
||
│ // 负载因子 │
|
||
│ loadNorm := 1.0 - node.LoadRate │
|
||
│ score += 0.10 * loadNorm │
|
||
│ │
|
||
│ // ISP匹配 │
|
||
│ ispNorm := 0.0 │
|
||
│ if node.ISP == user.ISP { │
|
||
│ ispNorm = 1.0 │
|
||
│ } │
|
||
│ score += 0.05 * ispNorm │
|
||
│ │
|
||
│ // 地理距离 │
|
||
│ dist := haversine(user.Lat, user.Lng, node.Lat, node.Lng)│
|
||
│ distNorm := 1.0 - (dist / 10000.0) │
|
||
│ score += 0.05 * distNorm │
|
||
│ │
|
||
│ // 线路质量 │
|
||
│ score += 0.05 * node.LineQuality │
|
||
│ │
|
||
│ if score > bestScore { │
|
||
│ bestScore = score │
|
||
│ bestNode = node │
|
||
│ } │
|
||
│ } │
|
||
│ │
|
||
│ return bestNode │
|
||
│ } │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 6.2.3 AI版本(机器学习)
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ AI调度算法(机器学习) │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 模型选择:XGBoost / LightGBM │
|
||
│ 原因: │
|
||
│ - 推理速度快(<1ms) │
|
||
│ - 可解释性好 │
|
||
│ - 特征重要性可分析 │
|
||
│ - 训练数据要求相对低 │
|
||
│ │
|
||
│ 特征工程: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 用户特征: │ │
|
||
│ │ - user_city (one-hot编码) │ │
|
||
│ │ - user_isp (one-hot编码) │ │
|
||
│ │ - user_latency_avg (历史平均延迟) │ │
|
||
│ │ - user_loss_avg (历史平均丢包率) │ │
|
||
│ │ - user_bandwidth (用户带宽) │ │
|
||
│ │ - time_of_day (时段,0-23) │ │
|
||
│ │ - day_of_week (星期,0-6) │ │
|
||
│ │ - is_peak_hour (是否高峰时段) │ │
|
||
│ │ │ │
|
||
│ │ 节点特征: │ │
|
||
│ │ - node_city (one-hot编码) │ │
|
||
│ │ - node_isp (one-hot编码) │ │
|
||
│ │ - node_rtt (当前延迟) │ │
|
||
│ │ - node_loss (当前丢包率) │ │
|
||
│ │ - node_jitter (当前抖动) │ │
|
||
│ │ - node_load (当前负载) │ │
|
||
│ │ - node_bandwidth (节点带宽) │ │
|
||
│ │ - node_line_type (线路类型,0-5) │ │
|
||
│ │ │ │
|
||
│ │ 游戏特征: │ │
|
||
│ │ - game_id (游戏ID) │ │
|
||
│ │ - game_region (游戏区域) │ │
|
||
│ │ - game_protocol (游戏协议,TCP/UDP/混合) │ │
|
||
│ │ - game_server_distance (游戏服务器距离) │ │
|
||
│ │ │ │
|
||
│ │ 交叉特征: │ │
|
||
│ │ - user_node_distance (用户到节点距离) │ │
|
||
│ │ - user_node_isp_match (ISP是否匹配) │ │
|
||
│ │ - node_game_distance (节点到游戏服务器距离) │ │
|
||
│ │ - historical_score (历史评分) │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 标签: │
|
||
│ - 实际加速效果评分(0-100) │
|
||
│ - 用户满意度(点击"反馈"按钮) │
|
||
│ - 是否掉线(0/1) │
|
||
│ │
|
||
│ 训练流程: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
||
│ │ │ 数据收集 │───→│ 特征工程 │───→│ 模型训练 │ │ │
|
||
│ │ │ 30天数据 │ │ 特征提取 │ │ XGBoost │ │ │
|
||
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ ┌───────────────────┘ │ │
|
||
│ │ │ ↓ │ │
|
||
│ │ │ ┌──────────┐ ┌──────────┐ │ │
|
||
│ │ │ │ 模型评估 │───→│ 模型部署 │ │ │
|
||
│ │ │ │ A/B测试 │ │ 在线推理 │ │ │
|
||
│ │ │ └──────────┘ └──────────┘ │ │
|
||
│ │ │ │ │
|
||
│ │ └─── 每周重新训练,持续优化 │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 推理流程: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ func aiSchedule(user *User, game *Game) *Node { │ │
|
||
│ │ candidates := getCandidateNodes(game) │ │
|
||
│ │ │ │
|
||
│ │ // 提取特征 │ │
|
||
│ │ features := extractFeatures(user, candidates, game) │ │
|
||
│ │ │ │
|
||
│ │ // 模型推理 │ │
|
||
│ │ scores := model.Predict(features) │ │
|
||
│ │ │ │
|
||
│ │ // 选择最高分节点 │ │
|
||
│ │ bestIdx := argmax(scores) │ │
|
||
│ │ return candidates[bestIdx] │ │
|
||
│ │ } │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ A/B测试: │
|
||
│ - 10%用户使用AI调度 │
|
||
│ - 90%用户使用高级调度 │
|
||
│ - 对比指标:延迟、丢包率、用户满意度 │
|
||
│ - 显著提升后全量切换 │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|