422 lines
11 KiB
Markdown
422 lines
11 KiB
Markdown
# Binance Real-time Data Ingestion System
|
||
|
||
生产级的 Binance WebSocket 实时数据采集系统,用于加密货币日内交易辅助。
|
||
|
||
## 功能特性
|
||
|
||
### 核心功能
|
||
- **多流订阅**: 同时订阅 K线、订单簿深度、实时成交数据
|
||
- **自动重连**: 指数退避策略,网络中断自动恢复
|
||
- **消息去重**: 基于事件时间戳 (E字段) 的 LRU 缓存去重
|
||
- **内存保护**: 限流 + 有界缓冲区,防止内存泄漏
|
||
- **流式存储**: 数据写入 Redis Stream,支持多消费者
|
||
|
||
### 生产级特性
|
||
- 异步 I/O (asyncio) 高性能处理
|
||
- 批量写入 Redis,降低网络开销
|
||
- 健康检查和性能监控
|
||
- 优雅关闭和信号处理
|
||
- Docker 容器化部署
|
||
- 完整的日志和统计信息
|
||
|
||
---
|
||
|
||
## 系统架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ Binance WebSocket API │
|
||
│ wss://fstream.binance.com/stream │
|
||
└────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ Multi-stream subscription
|
||
│ (kline_5m, depth20, aggTrade)
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ WebSocket Client (Auto-reconnect) │
|
||
│ - Exponential backoff │
|
||
│ - Heartbeat monitoring │
|
||
│ - Connection pooling │
|
||
└────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ Message Deduplicator │
|
||
│ - LRU cache (10,000 entries) │
|
||
│ - Event time (E field) based │
|
||
│ - TTL: 5 minutes │
|
||
└────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ Buffered Message Processor │
|
||
│ - Max buffer: 1,000 messages │
|
||
│ - Rate limit: 1,000 msg/sec │
|
||
│ - Batch processing │
|
||
└────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ Redis Stream Writer │
|
||
│ Stream keys: │
|
||
│ - binance:raw:kline:5m (K线数据) │
|
||
│ - binance:raw:depth:20 (订单簿深度) │
|
||
│ - binance:raw:trade (实时成交) │
|
||
│ │
|
||
│ MAXLEN: ~10,000 (auto-trim) │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 快速开始
|
||
|
||
### 前置要求
|
||
- Docker & Docker Compose
|
||
- 网络连接 (访问 Binance API)
|
||
|
||
### 1. 启动系统
|
||
|
||
```bash
|
||
# 克隆仓库
|
||
cd realtime-ingestion
|
||
|
||
# 复制环境变量配置
|
||
cp .env.example .env
|
||
|
||
# 启动所有服务 (Redis + 数据采集)
|
||
docker-compose up -d
|
||
|
||
# 查看日志
|
||
docker-compose logs -f ingestion
|
||
```
|
||
|
||
### 2. 验证数据采集
|
||
|
||
```bash
|
||
# 进入 Redis 容器
|
||
docker exec -it tradus-redis redis-cli
|
||
|
||
# 查看所有 Stream keys
|
||
KEYS binance:raw:*
|
||
|
||
# 查看 K线数据数量
|
||
XLEN binance:raw:kline:5m
|
||
|
||
# 读取最新的 10 条 K线数据
|
||
XREVRANGE binance:raw:kline:5m + - COUNT 10
|
||
|
||
# 实时监控新数据 (阻塞式读取)
|
||
XREAD BLOCK 0 STREAMS binance:raw:trade $
|
||
```
|
||
|
||
### 3. 使用 Web UI (可选)
|
||
|
||
```bash
|
||
# 启动 Redis Commander (Web 界面)
|
||
docker-compose --profile debug up -d redis-commander
|
||
|
||
# 访问: http://localhost:8081
|
||
```
|
||
|
||
---
|
||
|
||
## 配置说明
|
||
|
||
### 环境变量 (.env)
|
||
|
||
```bash
|
||
# Binance 配置
|
||
SYMBOL=btcusdt # 交易对
|
||
KLINE_INTERVAL=5m # K线周期
|
||
BINANCE_WS_BASE_URL=wss://fstream.binance.com
|
||
|
||
# Redis 配置
|
||
REDIS_HOST=redis
|
||
REDIS_PORT=6379
|
||
REDIS_STREAM_MAXLEN=10000 # Stream 最大长度
|
||
|
||
# 性能调优
|
||
MAX_BUFFER_SIZE=1000 # 最大缓冲区大小
|
||
RATE_LIMIT_MESSAGES_PER_SEC=1000 # 每秒处理消息数上限
|
||
DEDUP_CACHE_SIZE=10000 # 去重缓存大小
|
||
|
||
# 重连策略
|
||
RECONNECT_INITIAL_DELAY=1.0 # 初始重连延迟 (秒)
|
||
RECONNECT_MAX_DELAY=60.0 # 最大重连延迟 (秒)
|
||
MAX_RECONNECT_ATTEMPTS=100 # 最大重连次数 (-1 = 无限)
|
||
|
||
# 监控
|
||
HEALTH_CHECK_INTERVAL=30 # 健康检查间隔 (秒)
|
||
LOG_LEVEL=INFO # 日志级别
|
||
```
|
||
|
||
---
|
||
|
||
## 数据格式
|
||
|
||
详见 [REDIS_DATA_EXAMPLES.md](./REDIS_DATA_EXAMPLES.md)
|
||
|
||
### Redis Stream Keys
|
||
|
||
| Stream Key | 数据类型 | 更新频率 | 说明 |
|
||
|------------|----------|----------|------|
|
||
| `binance:raw:kline:5m` | K线 | 每5分钟 | OHLCV 数据 |
|
||
| `binance:raw:depth:20` | 订单簿 | 100ms | 前20档买卖盘 |
|
||
| `binance:raw:trade` | 成交 | 实时 | 归集成交记录 |
|
||
|
||
### 数据示例
|
||
|
||
**K线数据:**
|
||
```json
|
||
{
|
||
"e": "kline",
|
||
"E": 1701234567890,
|
||
"s": "BTCUSDT",
|
||
"k": {
|
||
"o": "42350.50",
|
||
"h": "42400.00",
|
||
"l": "42340.10",
|
||
"c": "42385.20",
|
||
"v": "125.4563"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 监控和运维
|
||
|
||
### 查看系统状态
|
||
|
||
```bash
|
||
# 查看容器状态
|
||
docker-compose ps
|
||
|
||
# 查看实时日志
|
||
docker-compose logs -f ingestion
|
||
|
||
# 查看 Redis 内存使用
|
||
docker exec tradus-redis redis-cli INFO memory
|
||
```
|
||
|
||
### 健康检查
|
||
|
||
系统每 30 秒输出健康状态:
|
||
```
|
||
Health Check | WebSocket: ✓ | Redis: ✓ | Buffer: 15.2% | Dedup: 2.34% | Written: 12345
|
||
```
|
||
|
||
### 性能指标
|
||
|
||
日志中会定期输出:
|
||
- **WebSocket 状态**: 连接是否健康
|
||
- **Redis 状态**: 写入是否正常
|
||
- **缓冲区使用率**: 内存压力指示
|
||
- **去重率**: 重复消息比例
|
||
- **已写入消息数**: 累计处理量
|
||
|
||
---
|
||
|
||
## 故障排查
|
||
|
||
### 1. WebSocket 连接失败
|
||
|
||
**症状**: 日志显示 "WebSocket connection closed"
|
||
|
||
**解决方案**:
|
||
```bash
|
||
# 检查网络连接
|
||
ping fstream.binance.com
|
||
|
||
# 检查防火墙规则
|
||
# 确保允许出站 HTTPS (443) 和 WebSocket 连接
|
||
|
||
# 重启服务
|
||
docker-compose restart ingestion
|
||
```
|
||
|
||
### 2. Redis 连接失败
|
||
|
||
**症状**: "Failed to connect to Redis"
|
||
|
||
**解决方案**:
|
||
```bash
|
||
# 检查 Redis 是否运行
|
||
docker-compose ps redis
|
||
|
||
# 测试 Redis 连接
|
||
docker exec tradus-redis redis-cli ping
|
||
|
||
# 重启 Redis
|
||
docker-compose restart redis
|
||
```
|
||
|
||
### 3. 缓冲区溢出
|
||
|
||
**症状**: "Buffer overflow! Dropped message"
|
||
|
||
**解决方案**:
|
||
```bash
|
||
# 增加缓冲区大小
|
||
# 编辑 .env:
|
||
MAX_BUFFER_SIZE=2000
|
||
|
||
# 或降低数据流量
|
||
# 只订阅必要的流 (修改 websocket_client.py)
|
||
|
||
# 重启服务
|
||
docker-compose restart ingestion
|
||
```
|
||
|
||
### 4. 高内存占用
|
||
|
||
**症状**: Redis 或应用内存使用过高
|
||
|
||
**解决方案**:
|
||
```bash
|
||
# 减少 Stream MAXLEN
|
||
REDIS_STREAM_MAXLEN=5000
|
||
|
||
# 减少去重缓存大小
|
||
DEDUP_CACHE_SIZE=5000
|
||
|
||
# 重启并清空数据
|
||
docker-compose down
|
||
docker volume rm realtime-ingestion_redis_data
|
||
docker-compose up -d
|
||
```
|
||
|
||
---
|
||
|
||
## 开发模式
|
||
|
||
### 本地开发 (不使用 Docker)
|
||
|
||
```bash
|
||
# 安装依赖
|
||
pip install -r requirements.txt
|
||
|
||
# 启动 Redis (使用 Docker)
|
||
docker run -d -p 6379:6379 redis:7.2-alpine
|
||
|
||
# 修改 .env
|
||
cp .env.example .env
|
||
# 设置: REDIS_HOST=localhost
|
||
|
||
# 运行应用
|
||
python main.py
|
||
```
|
||
|
||
### 运行测试
|
||
|
||
```bash
|
||
# 单元测试
|
||
pytest tests/
|
||
|
||
# 集成测试
|
||
pytest tests/integration/
|
||
|
||
# 覆盖率报告
|
||
pytest --cov=core --cov-report=html
|
||
```
|
||
|
||
---
|
||
|
||
## 生产部署建议
|
||
|
||
### 1. 高可用配置
|
||
|
||
- 使用 **Redis Sentinel** 或 **Redis Cluster** 实现高可用
|
||
- 部署多个采集实例 (消息去重会自动处理)
|
||
- 配置健康检查和自动重启
|
||
|
||
### 2. 监控告警
|
||
|
||
集成 Prometheus + Grafana:
|
||
```yaml
|
||
# docker-compose.yml 添加
|
||
prometheus:
|
||
image: prom/prometheus
|
||
volumes:
|
||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||
```
|
||
|
||
### 3. 日志收集
|
||
|
||
使用 ELK Stack 或 Loki:
|
||
```yaml
|
||
logging:
|
||
driver: "loki"
|
||
options:
|
||
loki-url: "http://loki:3100/loki/api/v1/push"
|
||
```
|
||
|
||
### 4. 安全加固
|
||
|
||
- 为 Redis 设置密码 (`.env` 中的 `REDIS_PASSWORD`)
|
||
- 使用专用网络隔离服务
|
||
- 限制容器资源使用 (`deploy.resources`)
|
||
|
||
---
|
||
|
||
## API 文档
|
||
|
||
### Python 消费端示例
|
||
|
||
```python
|
||
import redis
|
||
import orjson
|
||
|
||
# 创建 Redis 客户端
|
||
r = redis.Redis(host='localhost', port=6379, decode_responses=False)
|
||
|
||
# 使用 Consumer Group (推荐)
|
||
r.xgroup_create('binance:raw:kline:5m', 'my-processor', id='0', mkstream=True)
|
||
|
||
while True:
|
||
# 读取数据
|
||
messages = r.xreadgroup(
|
||
groupname='my-processor',
|
||
consumername='worker-1',
|
||
streams={'binance:raw:kline:5m': '>'},
|
||
count=10,
|
||
block=1000
|
||
)
|
||
|
||
for stream, stream_msgs in messages:
|
||
for msg_id, fields in stream_msgs:
|
||
# 解析 JSON
|
||
data = orjson.loads(fields[b'data'])
|
||
|
||
# 提取 K线数据
|
||
kline = data['k']
|
||
print(f"Price: {kline['c']}, Volume: {kline['v']}")
|
||
|
||
# 确认消息
|
||
r.xack('binance:raw:kline:5m', 'my-processor', msg_id)
|
||
```
|
||
|
||
---
|
||
|
||
## 许可证
|
||
|
||
MIT License
|
||
|
||
---
|
||
|
||
## 联系方式
|
||
|
||
如有问题或建议,请提交 Issue 或 Pull Request.
|
||
|
||
---
|
||
|
||
## 更新日志
|
||
|
||
### v1.0.0 (2023-11-29)
|
||
- 初始版本发布
|
||
- 支持 Binance 永续合约 WebSocket 数据采集
|
||
- 实现自动重连、消息去重、内存保护
|
||
- Docker 容器化部署
|