阿毛
It's me !
想你所想

用户积分

社区等级是用户活跃和魅力的见证,会随着用户的成长,等级也会递增,也会额外享受到不同特权。等级是根据积分进行划分,积分越多,等级越高。用户每天可获得积分,逐步累加至个人总积分中。

用户每日积分与等级会在次日更新。

积分与等级最终在系统中的实现方式为 MySQL 表与 Redis:

  • 积分明细:按用户 id 除以 100 的余数,即用户最后两位尾号分成了 100 张 MySQL 表,表中记录了每个用户历史以来获得所有积分明细,具体到每一分怎么获取来的,如 昨日通过“被点赞” 10 次获得 10 分。
    用户有入口可查询到历史积分明细(接口调用查询该表)
  • 总积分、等级、特权:每个用户的总积分与等级数值会记录在 Redis 中,每个用户一个 K-V,value 不仅包含当前总积分与等级值还包含对应特权限制规则。当然等级值与特权会额外持久化到 MySQL 用户表中。
    APP 个人页会展示总分与等级,同时其他功能接口内部会读取该 Redis K-V 来判断开放程度与增益。

因为用户可获得被动收益积分,所以不仅仅需要计算日活月活用户,实则需要计算全站用户。千万级别的用户体量,其数据计算与数据写入等压力可想而知,积分每天的任务量巨大。

下面大致介绍下「用户积分」的实现历来的演变,其中有些术语和模块这里说明一下:

  • 下文把某个用户昨日新增总积分中的每种组成来源称之为“用户行为”,如“作品被点赞”、“被关注”、“视频分享”等
  • 积分累加完毕后,
  • 次日会将用户昨日积分情况整理成日报内容,通过 IM 消息与 Push 推送 告知用户,下文会将这块逻辑称为“成绩日报”

初版实现

在最早期的积分系统中,因为没有完善的大数据平台等,任务实现粗暴简单:

不同用户行为会在不同接口中被统计到 Redis 中,如用户调用了点赞接口,接口内部会根据计算公式将这部分带来的积分记录到 Redis 中,其他用户行为同理。

每日定时任务启动 Python 脚本,脚本内部开始顺序遍历 User 用户表,每个用户就是一次循环,每次循环内部再去 Redis 中获取到各个行为分值,然后计算出总分,积分明细写入 MySQL 表,并执行等级检查、日报发送等。

尽管写表、等级检查与日报发送均存在耗时,但异步均可忽略,可用户遍历读表操作与数据计算无法异步,在千万用户数据体量下,会使得整个脚本执行非常慢,甚至需要 12 个小时多。如果再遇到数据错误需要回滚重跑更是打击。

重构0.1

随着大数据平台的建立与完善,我们将之前循环遍历用户表并依次统计计算的核心部分重构到了大数据平台,所有涵盖用户行为的接口内均上报数据埋点,最终通过 Spark 进行计算。

https://file.blog.humh.cn/wp-content/uploads/2026/11/20261109154658207.png

彼时的大数据平台因成本等因素考量在七牛云上,数据任务调度系统为 Ariflow,大部分计算代码为 Spark Scala,而我们的后端服务基本均在阿里云上,数据计算完成还需要将结果通过某些手段传输至阿里云并触发后续对应任务。这里我们将积分明细以 csv.gz 的载体分发至 CDN 上,对应任务运行在阿里云上,对应任务内拉取 CDN 数据。

https://file.blog.humh.cn/wp-content/uploads/2026/11/20261109162534915-1024x413.png
https://file.blog.humh.cn/wp-content/uploads/2026/11/20261109162713786-1024x547.png

触发阿里云任务是在七牛云 Airflow 内 ssh 阿里云主机执行相关脚本 pod。

https://file.blog.humh.cn/wp-content/uploads/2026/11/20261109160406218-1024x301.png
ssh部分逻辑示意

这样重构以后大幅减少数据计算的用时,且计算规则更易维护。但依旧存在问题:

  • 跨云厂商网络的数据传输
  • 跨系统调度,增加任务复杂度,不便于任务状态的及时跟进
  • 后触发任务仍需解析 csv 数据遍历,为了实现可重试幂等要求,还需要各种执行记录标识

重构1.0

后来大数据平台进行了迁移,从七牛云转腾讯云最终落地阿里云,数据系统也进行了重构。借着契机,积分任务也进行了再一次重构,不需要再考虑跨厂商网络的数据传输问题,从而将系统简化,部分数据可直接 EMR 写入或通过可简单的形式流转。

埋点数据上报至阿里云 SLS,阿里云 EMR 内直接 ETL 清洗,调度系统内直接原生 MySQL 数据导出组件将积分明细写入表内,同时 Redis 积分总值由数据平台直接更新,无需服务端异步更新。20 ~ 25 min(一般05:30 左右)相当于用户此时已经看到昨日积分加上了。

其他未处理的业务按后触发任务类型以最简洁高效的数据结构写入至 Redis 中,虽然依旧 K8S Pod 形式运行后触发任务脚本,但这里不需要再手动触发,而是定时任务不断轮询检测状态位。

后触发任务里也进行解耦异步,将耗时操作通过 Python Celery 异步消费执行。任务底层通用脚手架设计,所有后触发任务已实现可重跑、幂等以及一键停止功能。

其他优化

1. 业务源头

通过大量的数据探查,并结合业务实际情况出发

  • 因为历史积分明细需要手机滚动下滑翻阅,用户也从不关心很早时间之前的情况,所以将历史按用户尾号分为了 100 张分表和为一张总表。删除了 MySQL 历史存量数据,仅动态保留近 100 天数据,历史数据备份至数仓。
  • 日报不再推送全站用户,仅推送活跃用户,如仅推送最近 180 天有活跃的用户,减少全站有积分变更用户 Push 推送(push优化需求)

2. 数据源头

数据清洗:埋点格式优化,减少数据清洗计算复杂度。

3. 监控&告警

增加自监控:积分 mock 监控,埋点上报监控。通过某个测试账号完成,从发埋点源头处开始 mock,到最终数据落地,完成闭环监控。

https://file.blog.humh.cn/wp-content/uploads/2026/11/20261109170122626-1024x575.png

整个系统所有任务无论成功失败,均会第一时间钉钉告警,若紧急重要会自动电话告警。

同时用到的所有资源,如 Celery 队列压力 Grafana 监控,可随时观察任务压力,超出阈值会告警。

4. 修复

成熟的脚本和数据洞察看板,可随时准备好修复数据,同时一键任务重跑。

humh

文章作者

站长本人,一个憨批!

发表评论

textsms
account_circle
email

想你所想

用户积分
社区等级是用户活跃和魅力的见证,会随着用户的成长,等级也会递增,也会额外享受到不同特权。等级是根据积分进行划分,积分越多,等级越高。用户每天可获得积分,逐步累加至个人总积分中…
扫描二维码继续阅读
2026-11-09