监控可以涵盖多种数据,包括监控项、文本日志、结构化事件日志、分布式跟踪与事件自省(event introspection)。本章主要介绍监控项与结构化日志。
监控帮助你获得系统的可视化,判断服务健康和当故障发生时诊断服务的问题。
目的:
1. 在指定情况产生预警
2. 调查与诊断问题
3. 可视化系统信息
4. 对于长期的资源使用与服务健康有预见性
5. 跨时间范围的比较,或者是观察实验组与控制组之间的区别
监控策略的指标
速度
数据实效
事件发生若与出现监控结果的时间隔太久,你会认为该事件没有影响或者推出错误的因果事件关联。决定了你能多快地对一事件做出响应。
数据检索速度
尤其在查询大量数据,影响图表加载的时间,可以对普遍的查询进行预计算,监控系统可以基于最新数据创建与储存新的时间序列。
计算
以数月大小的时间窗口保存数据(分析系统长期的演变趋势)
保存所有详细的独立监控项(方便查看历史系统行为、但存储成本高且很难检索)
时间粒度与数据聚合(聚合的数据无法深入挖掘有效信息)
界面
图展示(包括热点图、直方图和对数曲线图)
创建仪表盘
实时展示某监控项不同聚合结果的图(机器类型、服务器版本、请求类型)(以发现数据的关联与模式)
报警
报警分级
报警抑制(发生全局错误时,仅报警一次;当服务的依赖项已经产生报警,该服务无需再报警)
监控数据来源
日志(事件)与监控项(事件与属性),其它还有分布式追踪,运行期自省。
结构化日志相对于普通文本日志,更适用于丰富的查询与聚合工具。
由于日志分析不具实时性,因此可以采用批处理系统分析日志,使用点到点查询,并以仪表盘的形式展示。用Cloud Dataflow分析日志,BigQuery用于点到点的查询,Data Studio用于仪表盘。
报警和仪表盘通常使用监控项。基于监控项的监控系统具有实时性,帮助工程师快速发现问题。但我们常常使用日志发现某个问题的根本原因,我们需要的信息往往未作为一个监控项。由于日志往往比监控指标生成更准确的数据,所以当报告实时性不高时,通常会利用日志分析系统生成详细报告。
当你需要关注某一特殊事件的发生时,可以使用基于日志的报警。以下场景更适用于基于监控项的报警:当某一特殊事件发生时,为其加上计数指标,并对该计数值进行配置。该方法使得所有统一监控项的报警配置位于一处,方便管理。
举例
移动日志信息到监控项上
问题 HTTP状态码是用户调试错误的重要信号,可以从日志中获取,而不能从监控项中获取。监控项仪表盘只能提供全局错误率,不包含具体的错误码或错误原因等信息。因此,debug的过程包括:
1. 查看全局错误趋势图,确定该错误发生时间。
2. 查询日志文件包含错误的行。
3. 尝试将日志文件中的错误与趋势图关联起来。
日志工具对无法估计比例,很难确定一个日志中的某错误是否频繁发生。日志还包含许多无关行,很难追踪根因。
提出的方法
AppEngine团队选择将HTTP状态码作为监控项的一个标签(例如:requests_total{status=404} vs requests_total{status=500})。由于不同HTTP状态码的数量是相对有限的,没有将监控项数据增加到过大的规模,又能将趋势图的相关数据用于报警。
结果
新标签使得趋势图可以针对不同的错误类型展示不同的曲线。用户可以根据错误码快速推断可能的问题。可以为客户端与服务器的错误设置不同的报警阈值,使得报警触发更准确。
管理你的监控系统
把配置看作代码
将系统配置看作代码一般,将其存储于校正控制系统:更改历史,任务追踪系统的具体更改链接,更方便的回滚和强制性的代码review步骤。
鼓励一致性
一个集中式的方法需要一致性,但每个团队可能想要全权设计各自的配置。
例如dashboard。可以快速理解其它团队的仪表盘,能更快解决问题。尽量使基础监控变得简单。如果所有服务需要输出一组相同的基础监控项,可以自动采集所有监控项,并提供一组相同的仪表盘。任意新的机器接入,都能自动构建基础监控。跨团队人员也能使用该监控数据。
推荐松耦合
监控系统在发生各种情况的故障后,需要不断迭代其服务。推荐系统呈松耦合。这需要为每个模块和监控的数据流提供稳定的接口。不同的模块分别负责采集、存储、报警与可视化。稳定的接口让每个模块的置换更简单。
十年前,监控系统例如Zabbix将所有功能集于一个模块。现代设计则常常包含了独立的采集模块、管理器(例如Prometheus server方法),长时间的存储(InfluxDB),报警聚合(Alertmanager)与仪表盘(Grafana)。
目的明确的监控项
第五章会提到如何实现监控并利用SLI测量指标,在系统错误预算构成威胁时触发报警。基于SLO的报警触发后,首先需要检查的是SLI测量指标。这些指标会在服务的仪表盘中鲜明地展示出来,多为首页。但在调查报警原因时,仅从SLO仪表盘无法获取足够信息,仪表盘还应展示更多数据。
预期变化
为了定位问题,我们需要从关注报警监控项转移到引发报警的监控项。最近该服务发生的改变也许正是问题所在。
监控代码的迭代版本。
监控命令行的flag,尤其在该flag决定了服务的可用与不可用时。
如果该服务的配置数据是动态的,监控动态配置的版本。
如果系统没有进行上述的版本管理,则需监控上次新建或打包的时间戳。
如果你尝试将某次故障与首次上线相关联,在趋势图或仪表盘上与报警相关联,比起通过查找CI/CD(持续集成与持续交付)的日志定位问题要方便多了。
依赖
如果服务未发生变化,其依赖项也许发生了变化或出现了问题,所以需要监控来自直接依赖项的响应。
输出每个依赖项请求与响应的大小、时延、响应码很有必要。可以使用监控项的附加标签拆解出响应码、RPC(远程过程调用)方法名、同级工作名。
饱和度
为了监控与追踪各项资源的利用率,包括RAM、磁盘、分配到该应用的CPU份额。其它资源例如打开文件描述符、线程池中的活跃线程、队列中的等待时间、日志大小等。
使用不同的编程语言,还需监控其它的资源:
Java:根据所使用的垃圾回收机制种类,选取堆和元数据大小以及更具体的监控项
Go:goroutine的数量(Goroutine是轻量级的并行程序执行路径,与线程类似)
语言本身会为追踪这些资源提供多种支持。
除了重要事件的报警,还需设置特殊资源可用率不足的报警:
该资源的使用率有硬性限制
超过某使用率阈值会引发性能退化
服务流的状态
对于HTTP流,监控所有的响应码无法充分提供报警所需的信号,因为有些可能是客户的不正确操作触发的。
如果对用户限制速率与配额,需要监控由于缺少配额而被拒绝请求的聚合值。
该数据的趋势图可以帮助你发现某个事件发生变化时,错误数量的变化。
设置有用的监控项
每个监控项都应为某个特定明确的目的服务。不能因为许多监控项容易生成而大量输出它们。在监控项设计时,要思考每个监控项将被如何使用。
只有在系统进入异常状态时,用于报警的监控项指标才能发生变化。当系统正常运行时,不要改变它们。而用于解决问题的监控项则不具备以上要求。好的debugging metric能够指出系统的潜在问题。在每次故障发生后,应思考哪些监控项可以帮助你更快地定位问题。
测试报警逻辑
理想情况下,监控与报警的代码从属于同一测试标准。在Google,我们使用一种域特定语言生成综合的时间序列。然后基于一段时间序列上的值写断言,或者特定报警的触发状态和标签值。
监控和报警通常是多步骤的,因此需要多组单元测试。这块区域仍然属待开发状态,如果你需要执行监控测试,我们建议一种三层方法,如下图所示。
Figure 4-1 监控测试环境层级
Binary reporting:检查输出的监控项变量值在特定环境下是否如预期变化。
监控配置:确保该监控规则能产生预期的结果,在特定情况下能产生预期的报警。
报警配置:测试产生的报警,根据报警的标签值,可被路由到一个预定义的目标。
如果你不能通过综合的方法测试监控,或者你的监控某一阶段无法测试,可以考虑创建一个运行的系统,用于输出常用的监控项,例如请求与错误的数量。你可使用该系统验证生成的时间序列与报警。你的报警规则非常有可能长年累月都未被触发,但你需要有自信,当该监控项超过某个阈值时,相应的工程师可以及时地接收到报警提醒。
总结
我们希望通过介绍我们监控系统有价值的点,帮助你考量你的监控策略在多大程度上符合你的需求,探索一些你想额外增加的点,并且思考你想要做的改变。你会发现在监控策略中综合多个来源的监控项和日志非常有用;精确的结合分析需要做到高度的上下文相关。确保采集的每个监控项都为一个特定目标服务,这个目标可以是更好的容量规划,改进debug的过程或能直接告诉你问题所在。
网友评论