- 基于 axum + sqlx + tokio 的 Rust 后端服务 - 实现多数据源管理(东方财富/新浪/腾讯)含 failover 容错 - 数据源健康检查、请求日志记录与重放诊断 - 股票公司列表、历史K线、实时行情数据获取 - 配置 .gitignore:忽略 target 构建产物、.env 密钥、data 数据库
210 lines
5.5 KiB
Markdown
210 lines
5.5 KiB
Markdown
# 📡 多数据源管理系统
|
||
|
||
支持多个金融数据源,自动降级、负载均衡、健康监控。
|
||
|
||
## 🏗️ 架构设计
|
||
|
||
```
|
||
┌─────────────────────┐
|
||
│ DataSourceManager │ ← 统一调度入口
|
||
│ (调度/降级/聚合) │
|
||
└──────────┬──────────┘
|
||
│
|
||
┌──────────┬───────────┼───────────┬──────────┐
|
||
▼ ▼ ▼ ▼ ▼
|
||
┌──────────┐┌─────────┐┌──────────┐┌─────────┐┌────────┐
|
||
│EastMoney ││ Sina ││ Tencent ││ Tushare ││ Mock │
|
||
│东方财富 ││新浪财经 ││腾讯财经 ││(需Token)││(测试用)│
|
||
│priority:1││ pri:2 ││ pri:3 ││ pri:1 ││ pri:99 │
|
||
└──────────┘└─────────┘└──────────┘└─────────┘└────────┘
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
免费无需Token(东方财富/新浪/腾讯)
|
||
```
|
||
|
||
## 🎯 运行模式
|
||
|
||
| 模式 | 说明 | 配置值 |
|
||
|------|------|--------|
|
||
| **Failover** (默认) | 按优先级依次尝试,失败自动降级到下一个源 | `failover` |
|
||
| **Aggregate** | 同时请求多个源,取最快返回结果 | `aggregate` |
|
||
| **PrimaryOnly** | 仅使用主源,失败不降级 | `primary_only` |
|
||
|
||
## 📊 数据源能力对比
|
||
|
||
| 数据源 | 公司列表 | 历史K线 | 实时行情 | 是否免费 | 限流 |
|
||
|--------|:------:|:------:|:------:|:------:|:----:|
|
||
| **东方财富** | ✅ | ✅ | ✅ | ✅ 免费 | 宽松 |
|
||
| **新浪财经** | ❌ | ✅ | ✅ | ✅ 免费 | 中等 |
|
||
| **腾讯财经** | ❌ | ✅ | ✅ | ✅ 免费 | 宽松 |
|
||
| **Tushare** | ✅ | ✅ | ✅ | 🔑 需Token | 严格 |
|
||
| **Mock** | ✅ | ✅ | ✅ | - | 无 |
|
||
|
||
## ⚙️ 配置说明
|
||
|
||
编辑 `backend/.env`:
|
||
|
||
```env
|
||
# 运行模式
|
||
DATA_SOURCE_MODE=failover # failover | aggregate | primary_only
|
||
DATA_SOURCE_PRIMARY=eastmoney # 主数据源
|
||
DATA_SOURCE_TIMEOUT=15 # 超时秒数
|
||
|
||
# Tushare(可选)
|
||
TUSHARE_TOKEN=your_token_here
|
||
```
|
||
|
||
## 📡 管理 API
|
||
|
||
### 查看数据源状态
|
||
```bash
|
||
GET /api/datasources
|
||
```
|
||
|
||
响应示例:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"data": {
|
||
"mode": "failover",
|
||
"primary": "eastmoney",
|
||
"sources": [
|
||
{
|
||
"name": "eastmoney",
|
||
"type": "eastmoney",
|
||
"status": "healthy",
|
||
"priority": 1,
|
||
"success_rate": "100.0%",
|
||
"avg_latency_ms": 133
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 触发健康检查
|
||
```bash
|
||
POST /api/datasources/health
|
||
```
|
||
|
||
### 切换运行模式
|
||
```bash
|
||
PUT /api/datasources/mode
|
||
Content-Type: application/json
|
||
|
||
{ "mode": "aggregate" }
|
||
```
|
||
|
||
### 测试单个数据源
|
||
```bash
|
||
GET /api/datasources/eastmoney/test
|
||
```
|
||
|
||
## 🔄 降级机制详解
|
||
|
||
以 Failover 模式获取 K线为例:
|
||
|
||
```
|
||
请求: GET /api/stocks/daily?code=600519&start=2026-01-01&end=2026-06-15
|
||
|
||
① 尝试 eastmoney (优先级1)
|
||
→ 失败(网络/解析错误)
|
||
→ 重试 2 次,仍失败
|
||
|
||
② 自动降级到 sina (优先级2)
|
||
→ 请求成功 ✅
|
||
→ 返回数据
|
||
|
||
如果 sina 也失败:
|
||
|
||
③ 自动降级到 tencent (优先级3)
|
||
→ 请求成功 ✅
|
||
|
||
如果全部失败:
|
||
|
||
④ 最终降级到 mock (优先级99)
|
||
→ 返回模拟数据
|
||
→ 保证系统不报错
|
||
```
|
||
|
||
## 📈 健康状态
|
||
|
||
每个数据源维护以下指标:
|
||
|
||
| 指标 | 说明 |
|
||
|------|------|
|
||
| `status` | healthy / degraded / down / unknown |
|
||
| `request_count` | 总请求数 |
|
||
| `success_count` | 成功次数 |
|
||
| `success_rate` | 成功率 |
|
||
| `avg_latency_ms` | 平均延迟 |
|
||
| `last_success` | 最后成功时间 |
|
||
| `last_error` | 最后错误信息 |
|
||
|
||
**自动状态判定规则**:
|
||
- `healthy`: 成功率 > 90%
|
||
- `degraded`: 成功率 50%-90%
|
||
- `down`: 成功率 < 50% 且请求 > 5 次
|
||
|
||
## 🛠️ 扩展新数据源
|
||
|
||
### 1. 实现 DataSource trait
|
||
|
||
```rust
|
||
// src/services/sources/my_source.rs
|
||
use crate::services::traits::DataSource;
|
||
|
||
pub struct MySource { /* ... */ }
|
||
|
||
#[async_trait]
|
||
impl DataSource for MySource {
|
||
fn name(&self) -> &str { "mysource" }
|
||
fn source_type(&self) -> &'static str { "mysource" }
|
||
async fn health_check(&self) -> anyhow::Result<bool> { /* ... */ }
|
||
|
||
fn supports_daily(&self) -> bool { true }
|
||
|
||
async fn fetch_daily_quotes(&self, code: &str, start: NaiveDate, end: NaiveDate)
|
||
-> anyhow::Result<Vec<StockDaily>> { /* ... */ }
|
||
}
|
||
```
|
||
|
||
### 2. 注册到管理器
|
||
|
||
```rust
|
||
// src/services/sources/mod.rs
|
||
pub mod my_source;
|
||
|
||
// src/services/manager.rs DataSourceManager::new()
|
||
match src_cfg.source_type {
|
||
SourceType::MySource => Arc::new(MySource::new(timeout)),
|
||
}
|
||
```
|
||
|
||
### 3. 添加配置
|
||
|
||
```rust
|
||
// src/services/config.rs
|
||
pub enum SourceType {
|
||
MySource,
|
||
}
|
||
```
|
||
|
||
## 🚀 快速测试
|
||
|
||
```bash
|
||
# 启动后端
|
||
cd backend && ./start.sh
|
||
|
||
# 测试公司列表
|
||
curl "http://localhost:8080/api/companies?page=1&page_size=5"
|
||
|
||
# 测试K线(真实数据)
|
||
curl "http://localhost:8080/api/stocks/daily?code=600519&start=2026-01-01&end=2026-06-15"
|
||
|
||
# 测试实时行情
|
||
curl "http://localhost:8080/api/stocks/latest?codes=000100,600519"
|
||
|
||
# 查看数据源状态
|
||
curl "http://localhost:8080/api/datasources"
|
||
``` |