“我们有50家酒店供应商,每家都有不同的限流策略。每次做促销活动,我们的集成服务就崩溃。” — 一位沮丧的CTO

“我们的HTTP客户端每秒创建数千个连接。供应商5分钟后就封锁我们。” — 一位首席工程师

如果这些故事听起来很熟悉,那你面临的就是HTTP Dispatcher问题。

问题:供应商太多,连接太多

天真的方法:每个供应商一个客户端

// ❌ 天真的实现
type HotelIntegrationService struct {
    hotelbedsClient  *http.Client
    didaClient       *http.Client
    expediaClient    *http.Client
    agodaClient      *http.Client
    // ... 还有46个客户端
}

func (s *HotelIntegrationService) SearchHotels(ctx context.Context, suppliers []string) {
    for _, supplier := range suppliers {
        go func(supplier string) {
            var client *http.Client
            switch supplier {
            case "hotelbeds":
                client = s.hotelbedsClient
            case "dida":
                client = s.didaClient
            // ... 更多case
            }

            resp, err := client.Get(fmt.Sprintf("/api/hotels?%s", query))
            // 处理响应
        }(supplier)
    }
}

当你搜索50家供应商时会发生什么?

并发请求:50
打开的连接:50(每个供应商一个)
┌─────────────────────────────────────────────────┐
│  供应商A: 10 请求/秒 (限制: 10) ✅               │
│  供应商B: 10 请求/秒 (限制: 5) ❌ 429           │
│  供应商C: 10 请求/秒 (限制: 20) ✅               │
│  供应商D: 10 请求/秒 (限制: 2) ❌ 429           │
│  ...                                          │
└─────────────────────────────────────────────────┘

结果:40%的请求因429 Too Many Requests失败

根本原因

  1. 没有限流意识:每个供应商有不同的限制(5 req/s、10 req/s、100 req/s、仅突发、等等)
  2. 没有连接池:每次请求都创建新连接
  3. 没有智能重试:收到429就立即放弃
  4. 没有优先级:所有请求一视同仁

登场:HTTP Dispatcher

什么是HTTP Dispatcher?

HTTP Dispatcher是一个中间件层,位于你的应用程序和供应商API之间。它管理所有HTTP通信,具有智能限流、连接池和请求优先级。

┌─────────────────────────────────────────────────────────┐
│                   你的应用程序                           │
└─────────────────────────────────────────────────────────┘
                          │
                          │ SearchHotels(request)
                          ▼
┌─────────────────────────────────────────────────────────┐
│              HTTP Dispatcher (大脑)                     │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │
│  │  限流器       │  │  连接池      │  │  优先级调度  │   │
│  └──────────────┘  └──────────────┘  └──────────────┘   │
│         │                  │                  │           │
└─────────┼──────────────────┼──────────────────┼───────────┘
          │                  │                  │
          ▼                  ▼                  ▼
┌─────────────────────────────────────────────────────────┐
│              供应商API(50个端点)                      │
│  HotelBeds  |  Dida  |  Expedia  |  Agoda  |  ...       │
└─────────────────────────────────────────────────────────┘

核心职责

职责 为什么重要
限流 防止429错误,尊重供应商限制
连接池 减少延迟,提高吞吐量
请求优先级 确保关键请求优先处理
智能重试 自动处理临时故障
指标和可观测性 实时了解发生的情况
熔断器 停止对故障供应商的请求

为什么HTTP Dispatcher对酒店API集成至关重要

挑战1:限流混乱

供应商限流无处不在

供应商 限流 类型
HotelBeds 10 req/s 每个IP
Dida 50 req/min 每个API Key
Expedia 100 req/s 允许突发
Agoda 无限制 但会阻止滥用
DerbySoft 5 req/s 严格
TravelGDS 20 req/s + 突发 令牌桶

没有HTTP Dispatcher

// ❌ 你同时发送100个请求
for i := 0; i < 100; i++ {
    go func() {
        resp, err := http.Get("https://api.hotelbeds.com/v1/hotels")
        // 结果:大多数请求因429失败
    }()
}

有HTTP Dispatcher

// ✅ Dispatcher自动排队和节流
dispatcher := NewHTTPDispatcher()

for i := 0; i < 100; i++ {
    dispatcher.Submit(&Request{
        Supplier: "hotelbeds",
        URL:      "https://api.hotelbeds.com/v1/hotels",
        Priority: PriorityNormal,
    })
}
// Dispatcher自动遵守10 req/s的限制

挑战2:连接开销

创建新的HTTP连接需要时间

DNS查询: 20-50ms
TCP握手: 30-100ms
TLS握手: 50-150ms
─────────────────────────────
总计: 每个新连接100-300ms

没有连接池

1000个请求 × 300ms = 300秒 = 5分钟!

有HTTP Dispatcher连接池

第一个请求:300ms(新连接)
接下来的999个请求:10-20ms(复用连接)
总计:~5-10秒

性能提升:50-100倍更快

挑战3:优先级很重要

并非所有请求都平等

请求类型 优先级 原因
实时预订 用户在等待,收入风险
价格比较 普通 重要但不紧急
缓存刷新 后台任务
分析同步 最低 可以等待

HTTP Dispatcher确保

┌─────────────────────────────────────┐
│  队列状态                            │
│  ───────────────────────────────   │
│  [高] 预订 #1234 ← 处理中           │
│  [高] 预订 #1235 ← 下一个          │
│  [普通] 价格查询 ← 等待中          │
│  [普通] 价格查询 ← 等待中          │
│  [低] 缓存刷新 ← 等待中            │
│  [最低] 分析数据 ← 等待中          │
└─────────────────────────────────────┘

实际影响

案例研究:OTA平台集成

使用HTTP Dispatcher之前

供应商数量:35
每秒请求数:500
429错误率:45%
P95响应时间:8.2秒
服务器CPU:95%
连接数:2000+

使用HTTP Dispatcher之后

供应商数量:35
每秒请求数:500
429错误率:0.5%
P95响应时间:1.2秒
服务器CPU:45%
连接数:150

影响

  • 429错误减少89%
  • P95延迟降低85%
  • CPU使用减少53%
  • 连接数减少92%

架构概览

核心组件

┌─────────────────────────────────────────────────────────────┐
│                    HTTP Dispatcher                          │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  1. 请求路由器                                         │  │
│  │     - 路由到正确的供应商                               │  │
│  │     - 应用供应商特定配置                               │  │
│  └──────────────────────────────────────────────────────┘  │
│                              │                               │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  2. 限流器(每个供应商)                               │  │
│  │     - 令牌桶算法                                       │  │
│  │     - 自适应退避                                       │  │
│  └──────────────────────────────────────────────────────┘  │
│                              │                               │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  3. 连接池管理器                                       │  │
│  │     - 保持活动连接                                     │  │
│  │     - 池大小管理                                       │  │
│  └──────────────────────────────────────────────────────┘  │
│                              │                               │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  4. 请求优先级调度器                                   │  │
│  │     - 优先级队列                                       │  │
│  │     - 公平调度                                         │  │
│  └──────────────────────────────────────────────────────┘  │
│                              │                               │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  5. 重试和熔断器                                       │  │
│  │     - 指数退避                                         │  │
│  │     - 级联故障快速失败                                 │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

数据流

1. 提交请求
   ├─ 应用  Dispatcher: SearchHotelsRequest
   └─ Dispatcher  队列: 带优先级入队

2. 限流检查
   ├─ Dispatcher  RateLimiter: 检查供应商限制
   └─ RateLimiter  队列: 需要时节流

3. 连接池查找
   ├─ Dispatcher  PoolManager: 获取连接
   └─ PoolManager  Dispatcher: 复用或创建

4. 执行请求
   ├─ Dispatcher  供应商: HTTP请求
   └─ 供应商  Dispatcher: 响应或错误

5. 处理响应
   ├─ 如果是429: 返回限流器稍后重试
   ├─ 如果是5xx: 带退避重试
   ├─ 如果成功: 返回给应用
   └─ 跟踪指标

什么时候你需要HTTP Dispatcher?

✅ 你需要HTTP Dispatcher如果:

  • 3个以上供应商,有不同限流策略
  • 100+ req/s的聚合流量
  • 实时要求(预订、可用性检查)
  • 成本约束(云提供商按连接收费)
  • 需要可观测性了解供应商性能

❌ 你可能不需要如果:

  • 1-2个供应商
  • 低流量(<10 req/s)
  • 仅离线批处理
  • 原型或MVP阶段

总结

HTTP Dispatcher不是可选项,而是酒店API集成规模化的关键组件。它:

  1. 防止限流违规 → 更少的429错误
  2. 减少连接开销 → 更快的响应时间
  3. 优先处理关键请求 → 更好的用户体验
  4. 提供可观测性 → 调试变得更容易
  5. 优雅处理故障 → 更高的可靠性

下一篇HTTP Dispatcher如何解决限流和连接池


推荐阅读


系列导航

HTTP Dispatcher系列

  1. 什么是HTTP Dispatcher及为什么需要 ← 你在这里
  2. HTTP Dispatcher如何解决限流和连接池
  3. 在Go中实现HTTP Dispatcher
  4. 真实案例研究和性能改进