当我说监控时,该关注什么?

监控,首先要知道想监控什么。然后要想监控这些东西到底需要什么样的数据,也就是,收集哪些指标。 一个库,或者子系统,或者服务,都应该收集一些指标以方便监控。

三种服务类型

服务可以归纳为以下三种类型:在线服务,离线服务,批处理任务。可能有些重叠,但大多服务都可以归到这其中一类。

在线服务

在线服务是指那些需要立即响应的系统,比如,大部分的数据库和 HTTP 请求都属于这一类。 监控这类系统关键的指标是,执行请求数,错误数,以及延迟。记录正在处理中的请求数量也很有意义。 对请求进行计数时,开始和结束都要记录。结束的时候,可以记录下 error 和延迟情况。

离线服务

离线处理并不需要马上响应请求,而且通常都是批量处理的。处理过程可能还分多个阶段。 对于每个阶段,记录 来了多少请求 , 有多少是正在处理中 ,处理完时要记录下 完成时间 ,以及 发送出去了多少响应 。如果是批处理的,还要记录下每一批请求的进入和离开。 知道处理完某任务的最后时间对于检测系统是否卡住了非常有用,但是这些信息还是有一定的局限。更好的方法是,系统定时地发心跳信息,带上时间戳。作业在经历每个阶段都导出最近心跳的时间戳,这样就可以知道一个作业从进入系统到完成离开所经历的每个阶段的具体耗时。

批处理任务

批处理和离线之间的界限很模糊,因为离线处理任务一般也是批处理的。辨别批处理任务的方法是看,它是不是连续不断地运行的,这个特征使得拆分它们很不容易。 监控批处理任务的关键指标是记录 最后完成的时间 。记下 每个主要阶段花费的时间也很有用。这些应该以推的形式收集。有时候一些特定任务的统计也值得关注,比如处理的记录的总数。 对于那些需要运行几分钟以上才完成的作业,基于周期性拉取的方式监控也很好。这样可以收集到随时间变化的一些数据,比如资源占用以及延迟情况,如果发现任务运行变慢,这些信息对调试会有帮助。 对于运行比较频繁(15 分钟内就会运行一次)的批处理任务,可以考虑将它们做成 daemon 并作为离线服务处理。

子系统

除了上面主要的三种服务类型,系统的一些子系统也值得一提。

在用户不做额外配置情况下,库都需要提供一些基本的信息。 如果库是用于访问外部进程(比如网络,磁盘,或者进程通信),至少要记录下总的请求数,错误数,和延迟。 取决于是轻量级库,还是比较重的库,可能还要记录下库自身的内部错误和延迟情况。 因为一个库可能使用到不同部分的资源,记录时注意加上合适的标签区分。比如,数据库连接池应该跟连续到的数据库区分开来。

日志

作为一个通用规则,对每类日志都应该有一个计数器,每记一行都对计数器加加。这样就能知道哪类日志出现的频率是多少,发生了多少次。 记录应用发生的 info / error / warning 的日志的数量也很有用。可以检查它们并对比最近发布版本之间是否有大的变化。

失败

失败跟日志的处理类似。每次有执行失败,都应该将计数器增加。 报告失败时,应该使用一个指标记录总的尝试次数。这样可以方便计算失败率。

线程池

对于任何类型的线程池,最关键的指标是 排队请求数 , 运行中的线程数 , 总的线程数 , 已处理的作业数 ,以及花了多久。记录 排队等待时间 也很有用。

缓存

缓存要监控的关键指标包括, 总的请求数 , 命中数 , 延迟 ,其次是具体到某一类的在线服务的请求数,错误数,延迟。

其它

对于指标名称,学会使用标签。但是不要滥用标签。比如,不要使用 http_responses_500_total 和 http_resonses_403_total ,而应该使用 http_resonses_total 作为指标名,但是加上code标签。 对于计数器的指标类型,可以使用rate()函数。比如总的HTTP请求数或者HTTP请求的总字节数,rate函数可以得到每秒的速率。但是对于量值类型的指标,比如正在处理中的请求数,总的/可用的 内存,不能使用rate函数。 有时候收集到的指标会有一些缺失的数据点,注意补零或者NaN。