通过前 2 个课时的学习,相信你已经对各个端中需要监控的指标有了一个全面的认识。这一节课,我会从业务开发的角度,带你了解哪些是需要自定义的指标,你又怎样通过这些指标去了解你的系统,更好地定位问题。
咱们先来讨论一下哪些地方需要添加指标信息,它们一般分为产品层和性能层,对应业务数据和性能数据。
产品层的数据可以帮助开发、产品、运营等业务人员更好地监测业务,例如评估产品功能、活动效果。业务人员可以通过数据指标预测发展的方向,并用一些策略来提升相应的数据指标。业务不同,数据指标的体系也不一样。目前互联网的产品都和用户相关,在 1 个用户的生命周期中,会有一些比较常见的指标,我们可以通过这些指标搭建模型。
这里我简单介绍一个比较常见的模型,AARRR。它是一个用户增长模型,AARRR 的模型名称来源于组成它的 5 个重要的类别:获客、激活、留存、营收、传播,这 5 个类别又构成一个流程:
在这一流程中,你会发现其中每个部分都可以根据不同的功能,产生不同的数据指标,然后你可以通过这些更细化的指标优化产品,从而让产品更具有商业价值。
性能层的数据会更加方便研发人员了解程序的运行情况。通过观测这部分数据,你能快速感知是哪些业务出现了异常,再结合日志或是我在下一课时要讲的链路,来快速定位问题出现的原因。
我将性能层,在开发时需要注意的数据分为 5 类,分别是操作行为、自定义数据处理、定时/大任务处理、第三方服务商对接、执行异常。
用户请求时,肯定会执行某些业务流程,在业务流程中,有 3 个关键点需要添加指标信息:
相信你在业务开发过程中,肯定有因为某些业务流程处理复杂或者相对耗时较长,而选择使用自定义线程池或是内部队列的形式去实现某个业务逻辑的情况。生产者消费者模式就是一个很典型的例子。这样的处理方式使你可以充分利用系统资源,从而提升效率。在数据处理时的有 2 个常用技术方案点,分别是队列和线程池。
通过观测这两部分的数据,开发人员能清楚地得知任务处理时的处理进度,当处理能力不足时,可以针对具体的指标来进行更细致的优化。
当需要指定时间执行某个业务,或是某个任务需要很长的执行时间时,我们会采用定时任务或者单独线程的方式来处理,这时我们就需要关注这个任务的处理状态。处理状态包括以下 2 点:
服务在处理过程中肯定会和各种的第三方服务打交道,比如支付时和微信服务交互,进行人机验证时和极验交互。有时候经常因为第三方服务不稳定导致我们自己的服务出问题,这时候就要考虑做降级处理。在与第三方服务对接时,我们一般会关注以下指标:
程序执行异常时,除了打印日志的堆栈信息,我推荐你在这个时候再增加一次统计指标的记录。通过这种形式,你可以不局限于异常。在面对其他地方产生的相同的问题时,你可以聚合出指标来更好地辅助你了解业务情况,比如在根据用户ID在查询用户信息时,数据应该是存在的,但是并没有查询到数据,这时候就可以认为是业务异常。
讲到这里,我想你应该对指标的内容有了一个比较清晰的认识。在编写指标后,我再来介绍一下,怎样才能看到指标的结果。
通常我们会通过一些指标函数进行计算,这些指标函数一般是与时间相关的,计算方式一般有 2 种,当前时间段的计算,与之前的某个指标值的计算。
指的是聚合某个时间段内的值最后求出的值,比如 QPS,就是计算 1 秒内的总请求数。这里面通常会用到以下 8 种函数:
// rank = 50;代表P50
// dataMap 中 key和value分别为 <耗时情况, 指定耗时的次数>
// 计算所有的次数
long totalCount = dataMap.values().stream().mapToLong(element -> element).sum();
// 计算出rank%所在位置(索引)
int roof = Math.round(totalCount * rank * 1.0f / 100)
long count = 0;
// 对所有的key进行排序
final List<String> sortedKeys = dataMap.sortedKeys(Comparator.comparingInt(Integer::parseInt));
// 遍历所有的key(耗时)
for (String time : sortedKeys) {
// 获取当前耗时的次数
final Long value = dataMap.get(time);
// 将当前所在的位置增加
count += value;
// 如果已经是超过或者和rank%的位置相同,则认定为当前耗时是P50的值
if (count >= roof) {
return time;
}
}
7.percent:百分比。SLA 就是通过这样的方式计算出来的。业务中同样会使用到百分比,比如我们规定了每月的销售额,通过目前已经销售的金额,就可以算出本月的销售进度。
8.sum:求和。用于计算一段时间内的数据总和。比如我们可以计算 JVM 在一段时间内的 GC 次数,GC 耗时等。
假设当前时间段计算得出的值是 a,在 a 之前的某个时间的值是 b,a 与 b 的计算最后得出了值 c。例如拉勾教育今年 8 月份的营收额 a,相比去年 8 月份的营收额 b,同比增长了多少,这个同步增长的量就是 c,也就是这一节我要讲的内容。以下是 4 个在计算中常用的函数:rate、irate、同比、环比。
1.rate:速率。它可以计算当前时间点的数据和一段时间之前的数据,二者之间的增长率。比如要计算最近 1 分钟的速率。那么计算公式就是:
(当前值 - 一分钟之前值) / 60 秒
这样的计算方式,通常与计数器(Counter)一同使用,因为计数器的数据一般是递增的,但有时很难看到增长率。通过速率,你可以看出哪些时候的增长比较多,哪些时候又基本不变,比如拉勾教育的课程购买人数增速占比。在课程上线时我们会开展 1 元购的活动,通过查看活动前后的人数增长率,我们就能很清楚地知道在活动期间购买的人数会大幅增加,以后也会更多地开展类似的活动。
2.irate:同样也叫速率。与 rate 的计算方式不同,irate 只计算最近两次数据之间的增长速率。rate 和 irate 的函数变化如下图:
这张图中红线的就是 irate 函数,而绿色线的就是 rate 函数。图中可以很明显地看出来,rate 更平缓一些,irate 则能更“实时”地体现出数据。
Rate 会对指定时间段内的所有值做平均计算,导致部分精度丢失。因此,irate 通常比 rate 更加精准。但 rate 的曲线更平滑,能更直接地反映出数据整体的波动。
3.环比:指连续 2 个统计周期的变化率。我们在计算销售量时,就可以使用环比,比如这个月的销售量环比增长 10%,指的就是同上一个月销售量相比,增长了 10%。计算公式如下:
(本期数 - 上期数) / 上期数 * 100%
4.同比:一般指今年的某一个周期和去年的同一周期相比的变化率,比如我前文提到的拉勾教育今年8月与去年8月的同比增长。计算公式如下:
(本期数 - 同期数) / 同期数 * 100%
有些数据是存在一些局限性的,比如雨伞在多雨的时节销量会比较好,如果计算环比,可能上一个月雨水比较少,这会导致计算得出数据并不具备参考性。而同比则计算的是去年相同时候的,相比于环比,具有更高的参考性。
通过对编写指标和常见指标函数的介绍,相信你已经对如何编写和怎样计算/展现指标数据有了一个很好的认识。除了我说的这些性能指标以外,你认为还有哪些是我没有说到的?指标函数还有哪些是你觉得常用的?欢迎在留言区分享你的看法。
© 2019 - 2023 Liangliang Lee. Powered by gin and hexo-theme-book.