在 `kline_stream.py` 中增强了 Redis 写入机制,限制待处理队列大小以防止无限增长,并在 Redis 处理失败时降级到进程内存。更新了缓存管理逻辑,确保在有 Redis 时优先使用 Redis 进行数据存储,提升了系统的内存使用效率与稳定性。同时,调整了日志记录以减少高负载时的输出频率。此改动进一步优化了消息处理与系统性能。
104 lines
2.9 KiB
Markdown
104 lines
2.9 KiB
Markdown
# 内存优化:修复 K 线缓存仍占用进程内存的问题
|
||
|
||
## 问题
|
||
|
||
即使配置了 Redis,K 线数据仍然在进程内存中累积,导致内存持续增长。
|
||
|
||
## 根本原因
|
||
|
||
在 `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**(只有降级时的少量数据)
|
||
- 内存占用应该**稳定**,不再持续增长
|
||
|
||
## 其他可能的内存增长源
|
||
|
||
如果重启后内存仍在增长,检查:
|
||
|
||
1. **WebSocket 消息队列**:检查是否有消息堆积
|
||
2. **日志**:检查日志文件大小
|
||
3. **数据库连接**:检查连接池是否正常释放
|
||
4. **其他缓存**:检查 `_price_cache`、`_symbol_info_cache` 等是否正常清理
|