auto_trade_sys/docs/内存优化_修复K线缓存.md
薇薇安 f4feea6b87 feat(ticker_stream, book_ticker_stream): 优化内存管理与Redis写入逻辑
在 `ticker_24h_stream.py` 和 `book_ticker_stream.py` 中引入新的内存管理机制,限制进程内缓存的最大条数为 500,避免内存无限增长。更新 Redis 写入逻辑,确保在有 Redis 时优先写入 Redis,而不在进程内存中常驻数据。通过定期从 Redis 拉取数据并合并,提升了系统的内存使用效率与稳定性,同时优化了日志记录以减少高负载时的输出频率。此改动进一步增强了系统性能与资源管理能力。
2026-02-19 00:34:35 +08:00

117 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 内存优化:修复 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` 方法
```python
# 修改前:总是先写进程内存
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 线数据不再存储在进程内存中
- **内存增长停止**:不再有数据在进程内存中累积
## 需要重启服务
**重要**:修改后需要重启交易服务才能生效。
```bash
# 重启交易服务
pkill -f "python.*trading_system.main"
# 然后重新启动
```
## 验证
重启后,检查内存使用:
```bash
# 查看进程内存
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` 等是否有上限并定期淘汰