186 lines
7.8 KiB
Markdown
186 lines
7.8 KiB
Markdown
## 多用户(多账号)架构评估与落地方案(草案)
|
||
|
||
本文档基于你提出的多用户需求,给出数据隔离边界、并发模型、Redis/DB 设计、以及 2核4G 服务器负载评估与分阶段落地路线。
|
||
|
||
---
|
||
|
||
## 目标与约束
|
||
|
||
### 目标(对应你的 6 点)
|
||
|
||
1. **每个用户使用自己的 API KEY**
|
||
2. **每个用户独立自动交易、独立持仓**
|
||
3. **每个用户独立配置**
|
||
4. **交易推荐全局共用**
|
||
5. **订单/交易记录独立**
|
||
6. **错误日志全局共用**
|
||
|
||
### 关键约束
|
||
|
||
- **币安限频是关键瓶颈**:公共行情接口通常按 IP 限频,单纯“多 key”无法线性扩容;必须通过共享行情缓存降低请求。
|
||
- **隔离优先级**:下单/持仓/配置/订单记录必须强隔离;推荐/行情/错误日志可以共享。
|
||
|
||
---
|
||
|
||
## 数据归属与隔离(Data Ownership)
|
||
|
||
### A. 全局共享(所有用户共用)
|
||
|
||
- **推荐(Recommendations)**:一份全局 Redis Snapshot/List
|
||
- 建议 Key:`ats:recommendations:snapshot`
|
||
- 后端/前端只读(不在请求中触发扫描/生成)
|
||
- **行情热数据(Market Data)**:全局缓存(Redis)
|
||
- `ats:md:mark_price:all`(短 TTL,比如 2~5s)
|
||
- `ats:md:ticker_24h:all`(TTL 10~30s)
|
||
- `ats:md:klines:{symbol}:{interval}:{limit}`(TTL 30~120s)
|
||
- **错误日志(Logs)**:全局流
|
||
- 继续使用 `ats:logs:{error|warning|info}`
|
||
- 每条日志建议增加字段:`account_id`(便于筛选定位)
|
||
|
||
### B. 用户私有(必须隔离)
|
||
|
||
- **API KEY/SECRET(敏感)**:按账号独立存储(必须加密)
|
||
- **交易配置**:按账号独立
|
||
- DB:`(account_id, config_key)` 唯一
|
||
- Redis:`ats:cfg:{account_id}`(hash)
|
||
- **自动交易运行态/热数据(可选但推荐)**
|
||
- `ats:positions:{account_id}`(更快的 UI 展示/减少后端压力)
|
||
- `ats:orders:pending:{account_id}`(挂单/入场状态)
|
||
- `ats:stats:{account_id}:*`(每日下单数、成交数、撤单数等)
|
||
- **交易/订单记录**:按账号独立
|
||
- DB 表:`trades` 增加 `account_id`;统计/查询均按账号过滤
|
||
|
||
---
|
||
|
||
## 并发模型:是否需要多线程/多进程?
|
||
|
||
结论:**不推荐多线程**。更推荐以下两种模型之一:
|
||
|
||
### 方案 1(推荐先落地):每个账号一个 `trading_system` 进程(Supervisor 管理)
|
||
|
||
- **优点**
|
||
- 隔离强:某个账号异常/限频/崩溃不影响其他账号
|
||
- 上线快:对现有单账号 trading_system 改动最少
|
||
- 运维简单:Supervisor 一账号一进程
|
||
- **缺点**
|
||
- 进程数随账号增长(内存占用会上升)
|
||
- 若每进程都重复拉行情,会触发 IP 限频(必须配合“全局行情缓存”)
|
||
|
||
### 方案 2(后期优化):单进程 + asyncio 多账号 worker
|
||
|
||
- **优点**
|
||
- 资源更省,便于共享行情缓存/HTTP Session
|
||
- **缺点**
|
||
- 隔离弱:某个账号阻塞/异常可能影响整体
|
||
- 实现复杂:需要更严格的超时/限频/异常隔离与任务监控
|
||
|
||
---
|
||
|
||
## Redis 用法:减轻后端与交易系统压力的关键
|
||
|
||
建议将 Redis 分为四层:
|
||
|
||
1. **全局行情缓存层**(降低公共接口请求)
|
||
2. **全局推荐层**(只读 snapshot,避免“刷新=触发扫描”)
|
||
3. **账号配置层**(`ats:cfg:{account_id}`)
|
||
4. **账号运行态层**(positions/pending/stats)
|
||
|
||
额外建议:
|
||
- 使用短 TTL + 分布式锁(你已有 lock 设计),避免并发刷新造成浪涌。
|
||
|
||
---
|
||
|
||
## 数据库改造(最小必要变更)
|
||
|
||
1. 新增 `accounts` 表:
|
||
- `id, name, api_key_enc, api_secret_enc, status, created_at ...`
|
||
- API Key 必须加密存储(服务端用 master key 解密)
|
||
2. `trading_config` 增加 `account_id`(或新表 `trading_config_accounts`)
|
||
3. `trades` 增加 `account_id`
|
||
4. `account_snapshots` 增加 `account_id`
|
||
5. 其余按需:positions、signals(signals 可全局,positions 必须私有)
|
||
|
||
---
|
||
|
||
## 2核4G 负载评估(粗略)
|
||
|
||
负载主要来自两块:
|
||
|
||
1. **公共行情拉取/指标计算(全局)**
|
||
2. **每账号的下单/持仓同步/风控计算(私有)**
|
||
|
||
### 不做共享行情(不推荐)
|
||
|
||
- 每账号都拉 klines/mark price/ticker:会先撞到 **币安 IP 限频**,2c4g 也撑不住。
|
||
|
||
### 做共享行情 + 推荐全局(推荐)
|
||
|
||
- 公共行情只拉 1 份(Redis 分发),账号 worker 只消费缓存 + 下单/持仓同步。
|
||
- 2c4g 在“波段低频”(如 15min 扫描、每账号持仓 0~5)场景下,通常可支撑 **10~30 个账号**(视持仓监控方式与限频策略而定)。
|
||
- 若每个账号都对每个持仓开 WebSocket 监控,上限会明显降低(更建议用全局 mark price + 定时校验替代/降频)。
|
||
|
||
---
|
||
|
||
## 分阶段落地路线(推荐)
|
||
|
||
### Phase 1:最快上线(强隔离、成本最低)
|
||
|
||
- accounts + account_id 改造(DB/API/前端)
|
||
- 每账号一个 trading_system 进程(Supervisor)
|
||
- 推荐/行情继续全局缓存(Redis)
|
||
- 日志全局流(带 account_id)
|
||
|
||
### Phase 2:提升承载与稳定性
|
||
|
||
- 抽全局 MarketDataService(行情/klines 统一刷新一次)
|
||
- 每账号 worker 只做决策/下单,减少公共 API 调用
|
||
- 降低 per-position websocket 数量(用 mark price 缓存替代)
|
||
|
||
---
|
||
|
||
## 面向“更多用户”的演进战略准备(从现在就要做对的几件事)
|
||
|
||
你问“每账号一进程是不是终极方案”。我的建议是把它当作**长期默认架构**,并提前把“可演进”埋点做对,这样未来扩容不会推倒重来。
|
||
|
||
### 1)固定边界:所有“私有数据”必须天然带 account_id
|
||
|
||
- **数据库**:`trades / trading_config / account_snapshots / positions(若有)` 都必须有 `account_id`,且所有查询默认按 `account_id` 过滤。
|
||
- **Redis**:账号私有数据统一命名空间:
|
||
- `ats:cfg:{account_id}` 或 `trading_config:{account_id}`(一账号一份配置 hash)
|
||
- `ats:positions:{account_id}`、`ats:orders:pending:{account_id}` 等
|
||
- **API**:所有与交易/配置/统计相关的接口都要支持 `account_id`(Header 或 Path),哪怕当前只有一个账号。
|
||
|
||
这一步一旦做对,未来从“多进程”演进到“多 worker/分布式”几乎不改数据层。
|
||
|
||
### 2)把“共享层”单独做成服务:推荐/行情永远不绑定账号
|
||
|
||
- 推荐:一份全局 snapshot(你已拆成独立推荐进程/服务),后面可水平扩容但要有锁。
|
||
- 行情:建议尽早演进为全局 MarketDataService(单实例拉取 + Redis 分发),账号 worker 只消费缓存。
|
||
|
||
这一步是从 10~30 账号走向 100+ 账号的关键,否则会先撞 Binance IP 限频。
|
||
|
||
### 3)演进路线(从易到难,逐步替换,不做“重写”)
|
||
|
||
1. **阶段A(现在)**:每账号一个进程(Supervisor)
|
||
- 最稳、隔离最好、上线快
|
||
2. **阶段B(账号增多)**:引入“控制器 + worker”但仍可单机
|
||
- 控制器负责:调度、限频预算、健康检查、任务重启
|
||
- worker 负责:每账号决策/下单/同步(可仍按进程隔离)
|
||
3. **阶段C(规模更大)**:队列化/分布式(K8s/多机)
|
||
- 账号按 `account_id` 分片到不同节点(sharding)
|
||
- 共享服务(行情/推荐)做成单独部署,或按区域分片
|
||
|
||
### 4)安全策略提前统一:API Key/Secret 必须与“普通配置”分离
|
||
|
||
- 强烈建议:API Key/Secret 存 `accounts` 表,**加密存储**(服务端 master key 解密),前端永不回传 secret 明文。
|
||
- 交易进程只拿到自己账号的解密结果(进程隔离的优势)。
|
||
|
||
---
|
||
|
||
## 风险提示与建议
|
||
|
||
- **安全**:API Key 必须加密存储;前端永远不返回明文 secret。
|
||
- **限频**:公共接口一定要共享缓存;多账号并发拉行情会让整体不可用。
|
||
- **隔离**:交易执行建议多进程优先;后期再做单进程多 worker 的资源优化。
|
||
|