当我们需要统计实验中每个分支的实际进入次数时,如何设计一个高效、可靠且对业务影响最小的方案,成为了关键。以下是几种常见的流量统计方案的分析与实现设计
目标
- 不影响实际业务使用,不应该因为汇报错误,导致灰度、甚至实际业务受影响
- 尽量保证高性能
- 能容忍一定误差和延迟
各方案分析
方案一:异步消息队列+定时聚合
每次进入分支发送消息到消息队列,由专门服务处理统计
优点:
- 解耦统计和业务逻辑,避免了统计逻辑的复杂性直接影响到主业务流程。
- 可靠性优,不容易丢数据
缺点:
- 需要维护消息队列,复杂性高
- 资源消耗较大
- 实时性差
方案二:本地计数器+定时上报
通过本地内存维护计数器,然后定期上报到关系数据库
优点:
- 实现简单
- 维护成本低
缺点:
- 关系数据库存在性能瓶颈
方案三:分布式计数器
使用redis直接维护计数器
优点:
- 实时性好
- 实现较为简单
- 支持水平拓展
缺点:
- 频繁计数,网络开销较大
- 在Redis宕机的情况下,可能会丢失数据或导致计数不准确
方案四:多级缓存
本地缓存作为一级缓存,在到达阈值时或时间周期后,汇报给redis。并通过额外服务定期更新到关系数据库中
优点:
- 性能与可靠性均衡
- 系统容错性高
缺点:
- 实现较为复杂
- 实时性一般
方案五:日志采集
当进入分支时,利用现有的日志系统打印日志,再通过额外服务采集日志进行统计
优点:
- 对业务零影响,不需要引入额外组件
- 高性能,尤其是在大规模系统中,日志系统可以提供高效的数据采集和处理能力
- 可拓展性
缺点:
- 实时性差
- 精准度差,可能存在日志丢失或采集延迟的问题
- 日志处理麻烦
我的选择
综合来看,多级缓存方案是最适合我当前应用场景的选择。它在性能、可靠性、系统容错性方面取得了较好的平衡,适合在高并发和实时性要求较高的环境中使用。
具体实现
本方案主要引入配置管理器、本地统计器、数据同步器、指标管理器结构
主要职责如下
本地统计器
主要功能如下
- 更新需要进行统计的实验
- 找到对应实验的相应分支,并递增其访问数量
- 在达到阈值或超时需要进行上报
场景特性分析
- 单项目实验数量有限
- 实验流量可能会非常巨大,产生高并发
- 必须保证基本业务不受影响
- 由于监控实验会发生变化,因此要考虑变化时对统计的影响
需要解决的问题
-
全量还是增量?
全量的优势在于直接覆盖,不需要额外的重置增加操作。但问题在于一旦项目发生了重新启动就会被重置,并且由于单项目可能运行了多个实例,因此增量会更好些
-
本地统计器主动汇报,还是管理器进行拉取?
超阈值本地统计器通知管理器,管理器到达一定时间或接受到本地统计器通知,进行拉取
-
在采用增量方案情况下,具体该如何做呢?
本地统计器记录最新全量a,管理器记录最新同步全量b,每次同步时递增 a − b a-b a−b,并在同步成功后,更新管理器最新同步全量为a
方案
监控实验map+实验分支统计map
进入分支时,先判断该实验是否被监控,若是,则找到该实验对应分支进行递增
性能优化点
- 可对监控实验map进行直接替换,而不是增删,以减少并发冲突
- 可一次将本项目所有实验加入实验分支统计map中,以防止在运行中增加之后对该结构进行变更
配置管理器
配置管理器定期检测本项目实验中是否有统计监控变化,在变化之后同步到指标管理器
- 指标管理器传递项目实验初始化配置管理器
- 配置管理器定期拉取,并检查配置是否变化
- 若变化,则将变化后的配置传递给指标管理器
数据同步器
根据指标管理器传递过来的递增数据发送到redis中,在当前设计中主要用于批量更新多个值
其实同步器并非必要,完全可以内嵌能力到指标管理器,但作为一个单一职责划分以及考虑未来可能不仅仅只会如此简单,因此也还能接受
redis可设计为key为实验+分支,value为次数
指标管理器
交互流程如下
- 启动指标管理器
- 异步运行配置管理器
- 异步运行本地统计器
- 异步运行数据同步器
- 配置管理器从远端拉取配置,并通过指标管理器同步到本地统计器
- 本地统计器根据配置初始化结构
- 进入测试分支后,本地统计器判断是否处于被监控实验,并在实验分支统计map中递增数值。若超出次数阈值后,通过管道通知指标管理器
- 指标管理器到达一定时间周期,或接收到本地统计器通知后,遍历所有监控实验分支统计值,并与记录的最新同步统计值计算差值,推送到同步器中
- 同步器推送到redis,成功后反馈指标管理器,指标管理器更新最新同步统计值
- 若配置发生变化,指标管理器直接替换本地统计器中监控实验map