如何监控测量你的代码
对于如何监控测量你的代码这个问题,有一个粗暴的答案就是对所有东西监控,每个库、每个子系统和服务都应该至少有几个监控指标,这样你可以了解你的代码是如何运行的。
监控应该是代码的一部分,如果在一个文件中有监控指标,在发生错误的时候就可以定位追踪,从报警到控制台到定位代码位置就变的非常容易。
三种类型的服务
为了进行监控,通常可以将服务分为三类:在线服务,离线服务和批处理作业。它们之间有重叠,但是每种服务都非常适合这些类别之一。
在线服务
在线服务系统有一个特点,用户或者其他系统对他发出请求以后,希望能够立即获得响应。比如,大多数数据库和 HTTP 请求都属于这一类。
在线服务系统的关键指标是执行的查询数、错误数、延迟时间、正在进行的请求的数量、请求失败的数量。
在线服务系统应该同时在客户端和服务器端进行监控,对于调试来说有一个非常有用的信息是双方看到的不同行为。如果一个服务有很多客户端,让这个服务单独跟踪他的客户端是不现实的,所以客户端必须依靠自己的统计数据。
在计算查询的开始时间或结束时间时要保持一致。当它们结束时,它将与错误和延迟统计数据一致,并且容易编写代码。
离线服务
离线处理服务是指没有人要求这个服务及时响应,这个服务可以分批处理已有的任务,也有可能是多阶段处理。
在每个阶段,跟踪进入的项目、有多少项目正在进行、最后一次处理某件事情的时间以及有多少项目已发出。如果是批处理,你还应该跟踪批的进出。
可以通过系统最后一次处理某件事情来判断他是否已经停止,但是这种判断方法存在一定的局限性,另一种更好的方式是通过系统发送心跳信息,并且在心跳信息中插入时间戳。这样可以在离线处理服务的每个阶段看到他最近的心跳时间戳,可以了解当前的处理进度。对于没有在处理任务的时间范围内,可以暂时关闭心跳,不让他显示出现。
批处理作业
离线处理和批处理作业之间有一条模糊的界线,因为离线处理可以在批处理作业中完成。批处理作业的区别在于它们不是连续运行的,这使得监控它们的指标很困难。
批处理作业的关键指标是它最后一次成功的时间,跟踪作业的每个主要阶段所花费的时间、总体运行时和作业最后完成的时间(成功或失败)也很有用。这些都是数据指标,应该推送到 PushGateway。通常还有一些对跟踪有用的总体特定于工作的统计数据,例如处理的记录的总数。
对于需要运行几分钟以上的批处理作业,使用基于拉取数据的监控方式来获取它们的监控指标也是很有用的。这使得您可以在一段时间内跟踪与其他类型作业相同的指标,例如与其他系统通信时的资源使用和延迟。如果作业开始变慢,这可以帮助调试。
对于经常运行的批处理作业(例如,超过每15分钟运行一次),应该考虑将它们转换为守护进程,并将其作为离线处理作业处理。
子系统
除了上边的三种主要服务类型之外,系统还应监控其子部分。
库文件
库应提供用户无需额外配置的工具。如果它是一个用于访问进程之外的某些资源(例如,网络、磁盘或IPC)的库,则在最低限度上跟踪总体查询计数、错误和延迟。
根据库的复杂程度,跟踪库本身的内部错误和延迟,以及你认为可能有用的任何常规统计数据。
一个库可能被应用程序的多个独立部分针对不同的资源使用,因此要注意在适当的地方使用标签来区分使用。例如,数据库连接池应该区分与之通信的数据库,而不需要区分DNS客户端库的用户。
日志
一般的规则是,对于每一行日志代码,还应该有一个递增的计数器。如果您发现了一个有趣的日志消息,您希望能够看到它发生的频率和发生的时间。
如果同一个函数中有多个密切相关的日志消息(例如,If 或 switch 语句的不同分支),有时为所有这些消息增加一个计数器是有意义的。
通常,导出应用程序作为一个整体记录的 info/error/warning 行总数也是很有用的,并检查作为发布过程的一部分的显著差异。
失败
对失败的处理应与日志记录类似。每当出现故障时,计数器就应该递增。与日志记录不同的是,根据代码的结构,错误也可能上升到一个更通用的错误计数器。
当报告失败时,您通常应该使用其他度量来表示总尝试次数。这使得故障率很容易计算。
线程池
对于任何类型的线程池,关键指标是排队请求的数量、正在使用的线程数量、线程总数、已处理的任务数量以及它们所花费的时间。跟踪在队列中等待的时间也很有用。
缓存
缓存的关键指标是总查询、命中、总延迟,然后是查询计数、错误和缓存所在的在线服务系统的延迟。
收集
在实现一个重要的自定义指标的 Exporter 时,建议导出一个 Gauge ,以秒为单位收集所需的时间,以及另一个指标所遇到的错误数量。
这是两种情况中的一种,可以将持续时间作为 Gauge 而不是 Summary 或 Histogram 导出,另一种情况是批处理作业持续时间。这是因为这两种方法都表示关于特定推送/刮擦的信息,而不是在一段时间内跟踪多个持续时间。