Closed SaltedFishKnight closed 1 month ago
可以尝试自定义配置
private void setListener(TimeRangeInOut inOut) {
inOut.setListener(new TimeRangeInOut.ChangeListener() {
@Override
public List<TimeRangeInOut.TimeRangeMinute> createListenerTimeRangeMinuteList() {
return List.of(
TimeRangeInOut.TimeRangeMinute.create(10, 19),
TimeRangeInOut.TimeRangeMinute.create(20, 29)
);
}
});
}
让我详细地展开说一下
假设 action 有捕获到以下这些执行时间:19.00 ms,19.12 ms,19.56 ms,19.99 ms,20.00 ms,20.23 ms,20.45 ms,20.99 ms
1、第一种设置
StatActionInOut.TimeRange.create(10, 19),
StatActionInOut.TimeRange.create(20, 29),
统计区间为 [10, 19],[20, 29],但是统计时间的最小单位是 ms,所以 19.12 ms,19.56 ms,19.99 ms 都被截断为 19 ms,导致 19.12 ms,19.56 ms,19.99 ms 被统计到 [10, 19],但实际上它们不应该被统计,因为它们是落入 (19, 20) 区间的
2、第二种设置
StatActionInOut.TimeRange.create(10, 20),
StatActionInOut.TimeRange.create(20, 29),
统计区间为 [10, 20],[20, 29],但是统计时间的最小单位是 ms,所以 20.23 ms,20.45 ms,20.99 ms 都被截断为 20 ms,因为统计次数是找到第一个符合的区间
public TimeRange getTimeRange(long time) {
return this.timeRangeList.stream()
.filter(timeRange -> timeRange.inRange(time))
.findFirst()
.orElse(this.lastTimeRange);
}
导致 20.23 ms,20.45 ms,20.99 ms 被统计到 [10, 20],实际上应该统计到 [20, 29]
所以不管是哪种设置,在闭区间的情况下,要么是缺少统计区间,要么是统计区间重叠
action 执行时间不论是多少,它最终落入的区间是 [0, +∞),如果你要完美的切割统计区间,应该是左闭右开区间
感谢你的详细说明。
但目前对称更符合人类理解,要么两边包含(默认实现)、要么两边不包含。而左闭右开、左开右闭并不太符合。
同样,默认实现的两边包含在配置上可以减少使用者的心智负担。如下示例配置
private void setListener(TimeRangeInOut inOut) {
inOut.setListener(new TimeRangeInOut.ChangeListener() {
@Override
public List<TimeRangeInOut.TimeRangeMinute> createListenerTimeRangeMinuteList() {
return List.of(
// 只统计 0、1、59 分钟这 3 个时间点
TimeRangeInOut.TimeRangeMinute.create(0, 0),
TimeRangeInOut.TimeRangeMinute.create(1, 1),
TimeRangeInOut.TimeRangeMinute.create(59, 59)
);
}
});
}
不好意思,我才看到你写的代码是 TimeRangeInOut 插件,我说的是 StatActionInOut 插件,我回复的代码已经修正过来了
我没有使用 TimeRangeInOut,但我看了源代码,TimeRangeInOut 是有着 StatActionInOut 相同的问题的
如果说 StatActionInOut.TimeRange 统计单位时间为 ms,在一毫秒内的几个 action 统计次数存在错误是可以接受的;但 TimeRangeInOut.TimeRangeMinute 统计单位时间为 minute,当统计单位时间从 ms 扩大到 minute,这无疑都会放大这两种统计错误:缺少统计区间、统计区间重叠
而且当你的 action 调用次数的数据量足够大时,StatActionInOut 和 TimeRangeInOut 都肯定会出现严重的统计数据失真
是我看错了,看成 TimeRangeInOut 了。StatActionInOut 与 TimeRangeInOut 类似 ,两者都不会出现统计数据失真,统计数据是符合预期的。
使用示例
private void setListener(StatActionInOut inOut) {
inOut.setListener(new StatActionInOut.StatActionChangeListener() {
@Override
public List<StatActionInOut.TimeRange> createTimeRangeList() {
return List.of(
StatActionInOut.TimeRange.create(1000, 1999),
StatActionInOut.TimeRange.create(2000, Long.MAX_VALUE, "> 2000"));
}
});
}
以下是模拟的测试数据
cmd[1 - 1], 执行[50]次, 异常[0]次, 平均耗时[1663], 最大耗时[2924], 总耗时[83163]
1000 ~ 1999 ms 的请求共 [26] 个
> 2000 ms 的请求共 [24] 个
cmd[1 - 2], 执行[50]次, 异常[0]次, 平均耗时[1699], 最大耗时[2940], 总耗时[84984]
1000 ~ 1999 ms 的请求共 [19] 个
> 2000 ms 的请求共 [31] 个
boolean inRange(long time) { return time >= this.start && time <= this.end; }
我注意到判断 action 执行时间的范围是闭区间,这在统计次数上会产生一些错误
假如按照原来的代码,当我要记录 [10, 20] [20, 30] 区间的 action 执行次数
此时捕获到有一个 time 为 20 的 action 被执行,根据源代码,这次 action 会被统计到 [10, 20] 区间,但实际上应该统计到 [20, 30] 区间
统计区间不应该有重叠,原理就和频率分布直方图一样,各数据组的边界范围应该是半开半闭区间,即 [10, 20) [20, 30)
只要将 time <= this.end 改为 time < this.end,同时在文档里说明是左闭右开区间