1.总体设计方案

35 阅读4分钟

1 业务背景

随着公司产品的上线推向市场,运营的同事会关注产品的用户数、活跃程度、留存数等运营指标,以此指标来指导产品的未来规划。因此需要开发运营平台,来统计展示相关运营指标。

例如:需要统计展示最近7天每天的、不同产品、不同城市:

  • 设备绑定用户数
  • 活跃设备用户数(上线次数>=1的设备用户数)
  • 绑定用户次日留存数(第1天绑定用户中,在第2天上线的设备用户数)
  • 活跃用户次日留存数(第1天上线次数>=1的设备用户中,在第二天上线的设备用户数)

2 技术方案

既然是要展示最近7天每天的用户数,那么首先我们需要存储每天的用户数到数据表中,只要存储了这些数据,后面统计展示就直接查询DB就很简单了。

因此,首要任务就是需要得到每天的用户数,然后存储到DB。实际在我们的运营平台项目中,是要得到:每天的不同产品、不同城市的绑定用户数。

因此,我们的方案是:

  • 存储原始数据,即设备绑定用户记录(dev_id, user_id, product_id,city,bind_time)

  • 每天凌晨跑定时任务,去分组汇总聚合每天的绑定用户数

在开发运营平台之前,我们有device核心业务服务已经存储了原始绑定用户记录(但是没有city字段),目的是为了支撑设备绑定、设备列表查询、设备详情等核心业务需求。我们是否可以直接基于device服务的原始绑定数据,在device服务中开发分组汇总聚合每日绑定用户数呢?答案是不合适。

因为如果是基于device服务存储的原始绑定用户记录,分组汇总聚合每日绑定用户数会有如下问题:

  • 需要添加city字段,如果未来还有其他维度,还需要不断的添加字段,统计业务和核心业务严重耦合

  • device服务在设计之初只是为了支撑设备绑定、查询等业务,不应承担汇总统计职责,违反模块单一职责

  • 同时如果统计业务出现问题或者故障,会影响device核心业务功能

因此最终制定的架构设计方案是:

  • 独立一个统计服务专门负责原始数据存储、汇总聚合统计数据,与device核心服务解耦
  • 采用消息队列异步事件驱动架构传递绑定事件,由独立的统计服务处理聚合,并存储到数据库中。这样可以提高系统的可扩展性、稳定性和性能。
[设备服务] -- 写绑定业务 --> MySQL
           |
           |-- 发布事件 --> RocketMQ
                          |
                          +-- [统计服务] -- 消费处理 --> Mysql原始数据表
                                           |
                                           +-- 汇总聚合 --> Mysql汇总表/Redis缓存

3. 方案细节

3.1 采集原始数据

使用AOP拦截绑定接口收集设备绑定用户信息,发送到RocketMQ,统计服务消费储存原始数据。这样最大程度与device服务绑定业务逻辑解耦。

3.2 汇总聚合每日绑定用户数

统计服务每日凌晨定时汇总聚合每日绑定用户数。

3.3 表设计

基于绑定用户维度统计需求,我们进行如下的相关表设计。

绑定汇总聚合表:用于统计展示每天的不同产品、不同城市的绑定用户数。

字段名称描述
stats_date统计日期
product_id产品id
area_code区域
bind_users设备绑定用户数

绑定信息原始表:基于此原始表,每天凌晨定时汇总聚合生成每天的不同产品、不同城市的绑定用户数。

字段描述
bind_time绑定时间
product_id产品id
area_code区域
dev_id设备id
user_id用户id
bind_status绑定或者解绑

4 总结

实现查询展示每日绑定用户数,需要基于原始绑定数据,汇总聚合存储每日绑定用户数。

需要注意独立一个统计服务,专门负责收集原始绑定数据,然后定时调度汇总聚合生成每日绑定用户数。以此避免和device服务耦合。

在实现细节上使用AOP在绑定接口执行完毕之后,收集绑定信息数据,异步发送RocketMQ,以此最大程度保证和device服务的核心绑定逻辑解耦。

最后,具体实现细节,后面章节在详细说明。