auto_trade_sys/docs/common/内存优化_修复K线缓存.md
薇薇安 13a0e7d580 delete: 移除过时的文档与代码文件
删除了多个不再使用的文档和代码文件,包括交易更新推送、条件订单推送、REST API 文档、WebSocket API 文档及相关的策略分析文档。这些文件的移除有助于清理代码库,确保项目的整洁性与可维护性。
2026-02-20 17:49:00 +08:00

3.8 KiB
Raw Permalink Blame History

内存优化:修复 K 线缓存仍占用进程内存的问题

问题

即使配置了 RedisK 线数据仍然在进程内存中累积,导致内存持续增长。

根本原因

kline_stream.py_handle_message_async 中,即使有 Redis代码仍然先更新进程内存 _kline_cache,然后再批量写入 Redis。这导致

  1. 数据双重存储:进程内存和 Redis 都有数据
  2. 批量写入延迟:在批量写入之前(最多 2 秒),数据一直留在进程内存
  3. 写入失败时数据残留:如果 Redis 写入失败,数据不会从进程内存删除

修复方案

1. 修改 K 线处理逻辑

文件: trading_system/kline_stream.py

修改前

  • 先更新 _kline_cache(进程内存)
  • 然后标记需要写入 Redis
  • 批量写入 Redis 后删除进程内存中的 key

修改后

  • 有 Redis 时:直接从 Redis 读取当前数据,更新后写回 Redis完全不写进程内存
  • 无 Redis 时:才写进程内存(降级)

2. 限制 Redis 写入队列大小

_redis_write_pending 字典可能无限增长,添加了大小限制:

  • 最多保留 100 个待写入项
  • 超出时删除最旧的项

3. 删除重复定义

修复了代码中重复定义的变量(复制粘贴错误)。

修改详情

_handle_message_async 方法

# 修改前:总是先写进程内存
if key not in _kline_cache:
    _kline_cache[key] = []
cache_list = _kline_cache[key]
# ... 更新 cache_list ...
# 然后标记写入 Redis

# 修改后:有 Redis 时只写 Redis
if self._redis_cache:
    # 从 Redis 读取
    existing = await self._redis_cache.get(rkey)
    cache_list = list(existing) if existing else []
    # 更新 cache_list
    # 标记写入 Redis不写进程内存
else:
    # 无 Redis 时才写进程内存
    ...

预期效果

  • 进程内存占用大幅降低:有 Redis 时K 线数据不再存储在进程内存中
  • 内存增长停止:不再有数据在进程内存中累积

需要重启服务

重要:修改后需要重启交易服务才能生效。

# 重启交易服务
pkill -f "python.*trading_system.main"
# 然后重新启动

验证

重启后,检查内存使用:

# 查看进程内存
ps aux | grep "trading_system.main" | awk '{print "MEM:", $4"%", "RSS:", $6/1024"MB"}'

# 或使用诊断脚本
cd backend
./检查内存问题.sh

正常情况下,有 Redis 时:

  • K 线缓存进程内存应该接近 0(只有降级时的少量数据)
  • 内存占用应该稳定,不再持续增长

补充Ticker24h / BookTicker 进程内存(本次一并修复)

原因Leader 进程里 _ticker_24h_cache_book_ticker_cache 一直随 WS 消息更新,全市场 200+ 交易对常驻进程内存,且每次写 Redis 前还 dict(_ticker_24h_cache) 做完整拷贝,加重内存和分配。

修改ticker_24h_stream.py / book_ticker_stream.py

  • 有 Redis 时WS 只做「从 Redis 读出 → 合并本批/本条 → 写回 Redis」不再更新 _ticker_24h_cache / _book_ticker_cache
  • 进程内缓存只由 refresh 循环(每 2 秒从 Redis 拉一次)回填,并限制最多 500 条,避免无限增长。
  • 无 Redis 时:仍只写进程内存,并同样限制 500 条。

这样 Leader 不再在进程里常驻全量 ticker/bookTicker也不为写 Redis 做整份拷贝。


其他可能的内存增长源

若重启后内存仍涨,可再查:

  1. WebSocket 消息队列:是否有任务/消息堆积
  2. 日志:日志文件与 Redis 日志 handler 是否过大
  3. 数据库连接:连接池是否及时释放
  4. 其他缓存_price_cache_symbol_info_cache 等是否有上限并定期淘汰