PV、UV 统计方案

868 字
4 分钟
PV、UV 统计方案

业务背景#

近期有个CPS相关的需求,其中有一个功能,是对CPS合作商(partner)的引流效果进行统计分析,需要以合作商的维度,统计PV、UV信息(合作商存在多级,但是不超过3级),数据情况大致如下

  • QPS,日间峰值360, 夜间低谷80, 均值250
  • PV 500W,带合作商信息的数据,预计在100W左右
  • 数据实时性要求 5 分钟,准确性要求相对准确

数据收集链路#

C端 → nginx → 后端应用 → kafka → CPS统计服务 → MongoDB

PV 统计实现方案#

基于 redis,后台线程异步从 redis 分桶数据中,获取增量数据,刷入到 mysql 中

redis 中的 key 命名规则 appns:pv:导流商id:日期(yyyyMMdd):时间(HH:mm),每个 key 默认过期时间为 30 分钟,其中时间分桶规则为每5分钟一个桶,示例如下

时间范围(闭区间)分桶
01:00<00> ~ 01:04<59>0100
01:05<00> ~ 01:09<59>0105
23:55<00> ~ 23:59<59>2355
  1. 消费数据时,保存到 mongo 后,计算得到对应的 key 集合中,value 使用 redis 的 INCR 自增,并将 key 保存到一个 特殊的 app:pv:keys 中(zset 结构),score 为 yyyyMMddHHmm
  2. 通过定时调度,每5分钟扫描 app:pv:keys 中分数 < 5分钟之前score 的 keys,遍历每个key,将对应的增量数据,刷入到数据库中,并从 app:pv:keys 删除(同时删除对应的 key)
  3. 增加兜底调度,每天凌晨时刻,基于 MongoDB 中的数据重新统计前一天每个 partner 的 PV,更新到数据库中

方案优势

  1. 避免频繁的更新 mysql(每次pv + 1 都更新完全没必要);
  2. 通过时间分桶方式,等到每个分桶中的增量完全固定之后,再将桶内的数据加回到数据库,降低代码实现的复杂度(否则需要考虑对桶操作的加锁)
  3. 每日兜底的重新统计任务,可以保证统计的数据准确性

后续优化方案

  1. mongo写入改为批量,INCR 前在内存中先小批次聚合一下,减少 io 次数
  2. 如果 parnter 层级过多,子 partner 比较多时,考虑同时聚合后更新 父级partner 的 PV

UV 统计实现方案#

如果用户张三,通过 partnerA 的引流链接进入到应用中,partnerA 的 UV + 1, 相同一天,张三又通过 partnerB 的引流链接进入应用时,partnerB 的 UV + 1

技术方案考虑使用 redis 的 HyperLogLog 实现,实现细节如下

  1. 消费数据时,保存到 mongo 后,计算对应事件的 key,格式为 appns:uv:导流商id:日期(yyyyMMdd),使用 PFADD KEY VALUE 命令,将对应的 openid 添加到指定的 HyperLogLog 中, 同时将 key 保存到 app:uv:keys:yyyyMMdd 集合中(只用redis的list)
  2. 定时调度,每5分钟扫描当日的 app:uv:keys:yyyyMMdd,遍历其中的key,再次将数据刷回 mysql
  3. 增加兜底调度,每天凌晨时刻,基于 MongoDB 中的数据重新统计前一天每个 partner 的 UV,更新到数据库中,同时清理昨日的 app:uv:keys:yyyyMMdd

方案优势

  1. 较与 set 或者 bitmap 实现形式,HyperLogLog 更加节省内存,标准的 0.81% 误差业务上能接受

后续优化方案

  1. 考虑在 应用内存中,积攒一小批后,通过 PFADD key element1 element2 element3 ... elementN 去操作 HyperLogLog

📎 参考文章#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

PV、UV 统计方案
https://blog.sephy.top/posts/pvuv-统计方案/
作者
虾米
发布于
2025-07-09
许可协议
CC BY-NC-SA 4.0
随机文章随机推荐
Profile Image of the Author
虾米
coder
分类
标签
站点统计
文章
61
分类
4
标签
52
总字数
64,663
运行时长
0
最后活动
0 天前
站点信息
构建平台
GitHub Actions
博客版本
Firefly v6.13.9
文章许可
CC BY-NC-SA 4.0