缺陷分析:API 限流排队拥塞恒定 30 个请求 2

BUG 分析:网络恢复后 API 限流排队深度始终卡在 30

摘要

  • 现象:WebSocket 重连成功后,日志中「API 限流排队拥塞」的「排队深度」长期停留在约 29~30 个请求,「需等待」约 74s,看似队列不消化。
  • 影响:重连后 K 线 HTTP 拉取缓慢、日志持续刷拥塞告警,易被误判为限流或配置错误。
  • 根因:「排队深度」表示的是当前请求前已预约的时间槽个数,不是队列长度上限;分析 worker 数为 30,全局限流每 2.5s 一个槽位,稳态下 30 个 worker 持续占满槽位,故排队深度恒为约 30。

完整因果链

1. 输入(Input)

类型 描述
主路径 WebSocket 假活检测触发重连 → 重连成功 → 「清空缓存,强制 HTTP 刷新」→ 大量分析任务需要 K 线数据。
触发表现 30 个分析 worker 同时调用 fetch_candles(经 KlineDataFillerfetch_candles_range_with_retry),全局限流器按 2.5s 一槽串行化,每个新请求看到的「前面已预约槽位数」≈ 30。

即:输入 = 重连后大量 candle 请求 + 30 个并发 worker 竞争同一全局限流。


2. 状态与公式(State)

  • 限流机制:单全局变量 _next_allowed_time,每次 fetch_candles 在锁内预约「下一个可用时间」wait_until = max(now, _next_allowed_time),并置 _next_allowed_time = wait_until + 2.5,再在锁外 sleep 到 wait_until 后发请求。
  • 排队深度定义queue_depth = (wait_until - now) / min_interval,其中 min_interval = KLINE_FILLER_API_INTERVAL = 2.5。即当前请求前面已预约的槽位数,非「队列中等待的请求数」。
  • 稳态:30 个 worker 持续占满槽位 → wait_until - now 恒约 30×2.5 ≈ 75s → 排队深度 ≈ 30,需等待 ≈ 74s。每完成 1 个请求又有新任务立即预约,故数值不下降直至整体任务量减少。

状态变化链:

[ 重连成功,缓存失效/强制刷新 ]
  → [ 大量分析任务入队,30 个 worker 同时拉 K 线 ]
  → [ 每次 fetch_candles 预约 2.5s 槽位,_next_allowed_time 持续前移 ]
  → [ 新请求看到的 wait_until - now ≈ 75s,queue_depth ≈ 30 ]
  → [ 日志持续输出「排队深度: 30」「需等待: 74s」]

3. 调用路径(Call Path)

WebSocket 重连成功
  └─ 清空缓存 / 缓存过期(如 base_klines TTL 60s)
  └─ 分析队列中大量任务(symbol × 周期)需 K 线
       └─ 30 × _analysis_worker 并发处理
            └─ _fetch_and_validate_price_data() → KlineDataFiller.fill_*()
                 └─ fetch_candles_range_with_retry() → fetch_candles()
                      └─ with _candles_lock:
                           wait_until = max(now, _next_allowed_time)
                           _next_allowed_time = wait_until + 2.5
                           queue_depth = (wait_until - now) / 2.5
                      └─ sleep(wait_until - now)  # 约 74s
                      └─ info.candles_snapshot(...)

4. 为何是 30 而不是「队列上限」

  • 代码中没有将排队深度或队列长度上限设为 30 的硬编码。
  • 30 = ANALYSIS_WORKERS_GENERAL(分析工作线程数)。在「每 2.5s 一槽」的全局限流下,约 30 个并发调用者会使得「下一个可用槽位」始终在约 75s 之后,因此计算得到的排队深度稳定在约 30。
  • 因此这是并发数与限流间隔共同导致的稳态现象,不是配置了「最多排队 30 个请求」的队列上限。

涉及文件与配置

项目 位置
排队深度计算与「API 限流排队拥塞」日志 src/utils/hyperliquid_candles.py 第 99–115 行
全局限流间隔 src/config.pyKLINE_FILLER_API_INTERVAL = 2.5
分析 worker 数 src/config.pyANALYSIS_WORKERS_GENERAL = 30
分析 worker 启动 src/services/realtime_kline_service_base.py_init_worker_threads()
重连「清空缓存」日志 src/trading/executor.py 重连回调

可选改进方向

  1. 重连恢复期降低 candle 请求并发
    在检测到「刚重连」的一段时间内,减少参与 fetch_candles 的并发数(如临时减少 worker 或集中到串行/小批量队列),使「前面已预约槽位」少于 30,排队深度与需等待时间下降。

  2. 重连后 K 线优先 DB,再按需补数
    重连后优先从 DB 读已有 K 线,仅对缺失或过期窗口用 filler 做 HTTP 补充,减少同一时刻的 HTTP 请求数。

  3. 调整 KLINE_FILLER_API_INTERVAL
    若需进一步降低 429 或减轻服务器压力,可适当增大间隔(如 3s/4s);在 worker 数不变下,排队深度计算方式不变,整体吞吐略降。

  4. 文档与观测
    在运维/开发文档中说明:重连后「排队深度: 30」是 30 个 worker 与 2.5s 间隔下的稳态现象,会缓慢消化,非 bug;可通过观察「需等待」是否随时间缓慢前移确认队列在消化。


参考

  • 全局限流设计见 src/utils/hyperliquid_candles.py 模块注释与 fetch_candles 实现。
  • 相关计划说明:.cursor/plans/ 下 API 限流排队卡在 30 分析计划。

Read more

跑步的技巧(滚动落地)

“滚动落地(rolling contact / rolling foot strike)”不是一种教条式的“脚法”,而是一种 让冲击沿着整只脚、整条后链逐级传递的落地机制。 它的核心不是“你先用哪儿着地”,而是: 你的脚落地之后,冲击是不是像轮子一样滚过去,而不是像锤子一样砸下去。 这就是滚动落地的本质。 一、什么叫“滚动落地”? 你可以把它理解成两种完全不同的落地方式: 1. 砸地(撞击式) 脚像锤子一样拍到地上: * 要么后跟先砸 * 要么前掌先戳 * 冲击集中在一个点 * 一个结构瞬间吃掉大部分载荷 结果就是: * 后跟砸 → 膝盖难受 * 前掌戳 → 前脚掌磨烂 * 都不是长跑友好模式 这叫 撞击式着地(impact strike)。 2. 滚地(滚动式) 脚像轮胎一样“滚”过地面: * 不是某一点硬砸 * 而是外侧中足先轻触 * 再向前滚到前掌 * 最后从大脚趾蹬离

By SHI XIAOLONG

AMI的优越性

世界模型(World Models)的具体例子 如下,我按类型分类,便于理解。每类都附带实际实现、演示效果和应用场景。 1. Yann LeCun / Meta 的 JEPA 系列(最直接对应“世界模型”概念) 这些是 LeCun 主张的非生成式抽象预测世界模型代表。 * I-JEPA(Image JEPA,2023) 输入一张图像,模型把不同区域(context 和 target)编码成抽象表示,然后预测 target 的表示(不在像素级别重建)。 例子:给定一张遮挡了部分物体的图片,模型能预测“被遮挡物体的大致位置和属性”,构建对物体持久性和空间关系的理解。 这是一个“原始世界模型”,能学习物理常识(如物体不会凭空消失)。 * V-JEPA / V-JEPA 2(Video JEPA,

By SHI XIAOLONG

什么是:“世界模型(World Models)”

世界模型(World Models) 是人工智能领域的一个核心概念,尤其在 Yann LeCun 等研究者推动的下一代 AI 架构中占据中心位置。它指的是 AI 系统在内部构建的对现实世界的抽象模拟或内部表示,让机器能够像人类或动物一样“理解”物理世界、预测未来、规划行动。 简单比喻 想象你闭上眼睛也能“看到”房间里的物体会如何移动、碰撞或掉落——这就是你大脑里的世界模型。AI 的世界模型就是类似的“数字孪生”(digital twin)或“内部模拟器”:它不是简单记住数据,而是学习世界的动态、因果关系和物理直觉(如重力、物体持久性、遮挡、因果等)。 为什么需要世界模型? 当前主流的大型语言模型(LLM) 擅长处理文本(统计模式预测),但存在根本局限: * 缺乏对物理世界的真正理解 → 容易“幻觉”、无法可靠规划。 * 样本效率低 → 人类/

By SHI XIAOLONG

K线周期可配置化设计方案

K线周期可配置化设计方案 1. 背景与目标 当前 Beta 套利策略的 K 线周期硬编码为 "1h",分散在多个文件中。需要: 1. 将 K 线周期从 1h 改为 2h 2. 提取为环境变量 BETA_ARB_KLINE_INTERVAL,使其可在 .env 中配置 2. 影响范围分析 2.1 需要修改的文件(共 6 个) 文件 硬编码位置 修改内容 src/trading/config.py BetaArbConfig dataclass 新增 kline_interval 字段,

By SHI XIAOLONG