You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

实时股价预警系统:如何在MongoDB中每分钟高效对比1000资产与百万记录?

解决实时股价预警的高效匹配问题:避免全量扫描MongoDB

这问题我之前做类似的实时行情预警系统时碰过,全量拉取100万条记录对比绝对是性能杀手,核心思路是反向匹配——只针对有预警的资产做查询/对比,而不是遍历所有预警记录。给你几个落地性强的方案:

方案一:按资产分组+MongoDB索引,精准查询

首先优化MongoDB的数据模型和索引,让每次查询只针对当前有更新的、且存在预警的资产:

  1. 数据模型设计:给预警集合的symbol字段加单键索引,每个预警文档结构如下:
{
  _id: ObjectId("..."),
  symbol: "XYZ", // 资产标识,比如股票代码
  threshold: 100.0, // 预警阈值
  operator: ">=", // 匹配规则:=、>、<、>=、<=
  user_id: "user_123",
  notify_channel: "email", // 通知渠道
  is_active: true // 是否启用预警
}
  1. 定时匹配逻辑
    • 每分钟从Redis获取1000个资产的最新价格
    • 先过滤出这1000个资产中存在有效预警的部分(可以在Redis里维护一个active_alert_symbols集合,新增/删除预警时同步更新)
    • 对每个符合条件的资产,用db.alerts.find({symbol: "XYZ", is_active: true})查询对应的预警规则——因为有symbol索引,单条查询速度是O(log n),哪怕一次查200个资产,总耗时也极低
    • 把查询到的预警规则和当前股价做对比,触发符合条件的通知

这个方案的好处是不用动太多架构,依赖MongoDB的索引性能就能解决问题,适合初期业务规模的场景。

方案二:Redis内存预加载预警规则,内存中匹配(最推荐)

如果想把性能拉满,完全规避MongoDB的实时查询IO,可以把预警规则预加载到Redis中,直接在内存里做匹配:

  1. Redis数据结构设计
    • 用Hash结构存储每个资产的预警规则:Key为alert_rules:{symbol},Field为用户ID,Value为阈值:操作符:通知渠道(比如100.0:>=:email
    • 同时维护一个Set集合active_alert_symbols,存储所有存在有效预警的资产标识
  2. 同步逻辑
    • 新增/修改/删除预警时,同时更新MongoDB和Redis(可以用MongoDB的Change Stream监听预警集合的变更,自动同步到Redis,避免手动维护的一致性问题)
    • 定期(比如每天凌晨)从MongoDB全量同步一次预警规则到Redis,做兜底容错
  3. 实时匹配逻辑
    • 每分钟从Redis获取1000个资产的最新价格
    • 遍历active_alert_symbols和当前1000个资产的交集,得到需要检查的资产列表
    • 对每个资产,从Redis Hash中取出所有预警规则,在内存中逐一对比股价和阈值
    • 触发符合条件的通知,同时可以异步更新MongoDB的预警触发记录(比如新增last_triggered字段)

这个方案的优势是内存匹配速度极快,100万条预警分到1000个资产里,每个资产平均1000条规则,内存占用完全可控,而且避免了数据库的实时查询压力,适合高并发、大数量级的预警场景。

方案三:MongoDB Change Stream + 事件驱动(进阶)

如果想进一步降低定时任务的耦合度,可以用事件驱动的方式:

  1. 每分钟把1000个资产的最新价格写入MongoDB的latest_prices集合
  2. latest_prices集合开启Change Stream,监听价格更新事件
  3. 当某资产价格更新时,自动触发对该资产预警规则的查询(同方案一的索引查询),然后做匹配和通知

这个方案的好处是把“定时轮询”变成“事件触发”,更贴合实时场景,但复杂度稍高,需要处理Change Stream的断点恢复、异常重试等问题。

关键注意事项

  • 数值精度问题:股价和阈值建议用Decimal类型存储(MongoDB的Decimal128,Redis的字符串存储避免浮点误差),防止因为浮点精度导致的匹配错误
  • 预警去重:如果同一用户对同一资产设置了多条重复规则,建议在存储时做去重,减少不必要的匹配
  • 通知异步化:触发预警后,通知逻辑要异步处理(比如用消息队列),避免阻塞匹配流程

内容的提问来源于stack exchange,提问作者PirateApp

火山引擎 最新活动