如何在Event Sourcing系统中统计过去24小时新增用户数?
实现过去24小时新增用户统计的投影方案
针对你遇到的问题,这里提供几种实用的投影实现思路,适配不同场景需求:
方案1:带时间分片的专用维护投影
适合需要低延迟查询的场景,投影直接维护好可直接使用的统计值:
- 投影内部维护两个核心数据:
- 按小时(或更小时间粒度)划分的用户计数分片,比如
hourly_counts: { "2024-05-20T10:00": 15, "2024-05-20T11:00": 22, ... } - 当前24小时内的累计总数
total_last_24h
- 按小时(或更小时间粒度)划分的用户计数分片,比如
- 初始化阶段:遍历所有
UserWasCreated事件,按事件携带的createdAt时间戳分配到对应时间分片,同时计算出初始的total_last_24h - 实时同步阶段:
- 收到新的
UserWasCreated事件时,将对应时间分片的计数+1,同时total_last_24h+1 - 配置定时任务(比如每小时执行一次),清理掉超过24小时的时间分片,并将
total_last_24h减去这些分片的计数总和
- 收到新的
- 查询面板时,直接读取
total_last_24h即可,无需额外计算
方案2:实时监听+定期全量校准的轻量投影
如果你的事件存储支持按时间范围高效查询,这种方案实现更简单:
- 投影只维护一个实时统计值
current_count,以及记录最后一次校准的时间 - 实时同步阶段:收到新的
UserWasCreated事件,直接将current_count+1 - 定期校准阶段:每隔一段时间(比如5分钟),从事件存储中查询过去24小时内所有的
UserWasCreated事件,重新统计总数并覆盖current_count - 这种方式可以避免因服务重启、事件丢失等导致的统计误差,同时实时性也能满足大部分面板需求
方案3:全量时间索引投影
适合数据量中等,且不需要极致查询性能的场景:
- 投影同步所有
UserWasCreated事件,将每个用户的ID和对应的createdAt时间存储到带时间索引的存储中(比如带TTL的键值库、关系型数据库的带索引表) - 当需要展示面板时,直接执行时间范围查询:统计
createdAt在过去24小时内的条目数量 - 如果数据量较大,给
createdAt字段建立索引即可保证查询效率;也可以配置自动清理超过24小时的历史数据,减少存储占用
关键注意事项
- 必须使用事件中携带的业务时间(即用户实际创建的时间
createdAt),而非事件被写入事件流的存储时间,避免因事件延迟导致统计偏差 - 统一使用UTC时间处理,避免时区差异带来的错误
- 定时任务或校准操作要处理并发问题,比如加分布式锁防止重复计算
内容的提问来源于stack exchange,提问作者Hector Ordonez
相关产品推荐
相关产品推荐

