# 第六部分:智能调度系统 ## 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%用户使用高级调度 │ │ - 对比指标:延迟、丢包率、用户满意度 │ │ - 显著提升后全量切换 │ │ │ └──────────────────────────────────────────────────────────────────┘ ```