作者:admin
最后编辑:2024-12-11 16:34:50
范例场景描述
在该场景中假设订单有四种状态:支付成功、支付失败、超时未支付、订单取消。
假如有如下数据需求:
订单量:
1、每10分钟_各状态_订单量
2、每天_各状态_订单量
订单异常率:
1、每10分钟_订单异常率
2、每天_订单异常率
支付失败用户数统计:
1、每5分钟_支付失败用户数
2、每小时_支付失败用户数
3、每天_支付失败用户数
定义元数据结构
字段 | 字段类型 | 描述 | 示例 |
---|---|---|---|
userId | string | 用户ID | |
orderId | string | 订单ID | |
state | string | 订单支付状态 | 1:支付成功、2:支付失败、3:超时未支付 4:订单取消 |
消息上报时机
此类需求上报时机至关重要,因为上报时机的选择决定了统计原始消息数据本身,也决定了统计项的配置方式和最终的统计结果。
对于此类“状态变更”的数据需求,统计逻辑相对较复杂,一般可分为两种上报时机:
- 在订单状态发生变化时上报,使用该上报方式一笔订单可能对应多条状态变更消息,比如第一次支付失败,用户重新发起支付随后成功,订单状态会变更两次,一笔订单对应两条原始消息。
- 在订单的最终状态确定时上报,使用该上报方式一笔订单只对应一条状态变更消息。
具体选择哪一种上报时机,请根据您的实际需求和您的业务逻辑综合确定,比如:
- 如果您期望监控订单支付异常的次数数据,则可以选择第一种;
- 如果您期望监控订单数据中成功与失败的比率,则可以选择第二种;
本范例以第一种为例。
跨周期统计问题
关于此类“状态变更”的指标统计会涉及跨周期统计问题,XL-LightHouse的每一条原始数据消息都对应一个时间戳,内部的运算逻辑也完全基于这个时间戳来划分时间窗口。
在这种“状态变更业务场景”中使用时,状态变更可能会横跨不同的统计周期,比如我们要计算“每小时_异常支付订单数量”这个数据指标,订单创建消息可能是在10点,订单支付失败的消息可能是在12点,这个时候如果您的业务期望这个异常值统计在订单创建的统计周期内,就传订单创建的时间戳。如果您期望统计在订单异常消息的统计周期内,就传异常消息本身的时间戳。
配置统计项
Template:<stat-item title="每10分钟_各状态_订单量" stat="count()" dimens="state" />
TimeParam:10-minute
Template:<stat-item title="每天_各状态_订单量" stat="count()" dimens="state" />
TimeParam:1-day
Template:<stat-item title="每10分钟_订单异常率" stat="count(state != '1')/count()" />
TimeParam:10-minute
Template:<stat-item title="每天_订单异常率" stat="count(state != '1')/count()" />
TimeParam:1-day
Template:<stat-item title="每5分钟_支付失败用户数" stat="bitcount(userId,state == '2')" />
TimeParam:5-minute
模拟数据接入
private static final String userId_RandomId = RandomID.id(10);
private static final String dealerId_RandomId = RandomID.id(5);
@Test
public void orderStatTest() throws Exception {
//连接RPC模块注册中心,集群版本默认为RPC部署(lighthouse-ice)的前两个节点(一主一从),单机版本只使用一个节点即可。
LightHouse.init("10.206.7.15:4061,10.206.7.5:4061");
for(int i=0;i<1000;i++){
HashMap<String,Object> paramMap = new HashMap<>();
paramMap.put("userId",userId_RandomId +"_" + ThreadLocalRandom.current().nextLong(100L));
paramMap.put("orderId","order_"+i);
paramMap.put("state",ThreadLocalRandom.current().nextLong(4)+1);
//参数1对应统计组token,参数2对应统计组秘钥,参数3是消息事件的13位时间戳 。
LightHouse.stat("Gjd:order_state_monitor","rULeSd86sbSIkFeLqQmM0bqeZFMpWNWNbYp8BaZA",paramMap,System.currentTimeMillis());
}
//注意:stat方法为异步发送,如果进程直接退出可能会导致部分消息没有发送出去,所以这里加一个sleep。
Thread.sleep(10 * 1000);
System.out.println("send ok!");
}
查看统计结果
注意事项
- 如果使用单元测试发送完统计消息后进程直接退出,请务必加一个Thread.sleep(10 * 1000),否则部分内存中的消息可能没有发送出去而影响统计结果。
- 系统内置的监控功能(集群监控和首页报表)都是基于系统处理消息的时间戳,与原始消息指定的时间戳不同,所以两者的统计结果不完全一致。比如:调用SDK的stat方法上报消息时,如果指定的是昨天的时间戳,则对应统计指标的值都是计算在昨天的统计周期内,但集群监控的统计周期是当前时间。