服务健康健康以及可观测性对于大规模微服务运维具有非常重要的意义,这篇文章介绍了 Salesforce 围绕服务健康指标的最佳实践。原文:READS: Service Health Metrics[1]
当我们打造 SOA 体系架构或者在公司内部署了成百上千个微服务时,如何跟踪每个域中每个服务的性能?如何知道是否已经跟踪了每一个服务?每个服务都不一样,但是否可以以一致的视角看待服务的健康程度?这些都是我们在 Salesforce 遇到的挑战。根据 Salesforce 内外部的最佳实践,我们开发了一个框架,规定了每个服务需要支持的最小指标集,用以在运营和执行层面基于共同的语言来识别服务的健康状况和性能。这篇文章概述的最小指标集参考了两个著名的框架:RED 模式[2]和 USE 方法[3]。每个服务将会(并且应该)定义其额外的特定指标,以进一步了解其性能并有助于调试生产问题。
健康指标
缩写词 READS 表示每个服务的最小指标集:请求速率(request rate)、错误(errors)、可用性(availability)、时长/延时(duration/latency)和饱和度(saturation)。每个服务所有者都需要负责生成正确的度量数据,以便计算或派生出这些指标。
接下来我们详细讨论这些重要指标。
请求速率(每分钟请求数)
度量服务每分钟处理的请求数。和容量一样,这是服务利用率的度量,可以指示服务是否达到了在合理的延迟下可以服务的请求数量的阈值。测量时,应该同时报告每分钟请求的峰值和平均值。平均值表示业务的持续负载,峰值表示业务的最大负载,两种度量对系统规划都很有用。
容量是一个相关的指标,度量一段时间内对服务的请求数量。对该信号在一段较长时间内进行趋势分析将有助于服务所有者了解使用量的增减。以周为单位进行比较将帮助我们理解系统中的异常行为。对于 REST 服务来说,容量是该服务接收到的 HTTP 请求的数量。
错误率(每分钟错误)
应用程序和系统错误为服务所有者提供了关于服务性能的关键数据,这些数据在每次新部署之后立马就能看到效果。一旦看到每分钟新增的错误变多了,很可能表明测试中遗漏了某个错误,或者某个依赖受到了影响或报错,预示着可能需要回滚这次部署。为了度量代码和系统质量,建议度量和跟踪如下两类错误。
- 失败请求(Failed requests) —— 每分钟失败的请求数,当请求产生 5xx 响应代码时生成。
- 记录异常(Logged Exceptions) —— 应用中未处理以及已记录的错误的数量。
可用性
可用性是服务水平目标(SLO)实现代表,可以根据服务类型和体系架构模式做出不同的定义。简单来说,可用性是向客户提供功能的能力。可用性的定义取决于服务希望在错误阈值和/或时延(时长)阈值的范围内提供怎样的关键功能。有两种方法可以度量服务的可用性。
- 考虑每个操作/事务/API 调用/请求来度量可用性。可用性度量可能是由服务认为重要的各种信号组成的聚合度量,以确定服务是否可用。对于某些服务,成功响应请求便意味着该服务可用,而对于其他服务(如告警服务、通知服务以及其他任务),需要在特定时间内完成任务,如果不能满足要求,则认为该服务不可用。
- 通过典型场景的金丝雀测试或者使用来自 Dynatrace 或 NewRelic(或 Salesforce 的 Kaiju)等第三方供应商的模拟测试工具来衡量可用性。金丝雀发起客户事务(最好是针对 API),并度量该事务的速率和质量,将事务成功/失败的信号发送给监控工具(在 Salesforce 是 Argus),用来计算服务的可用性。
我们倾向于使用第一种方法——将每个操作都考虑进去——而不是使用金丝雀测试,除非操作总量少于金丝雀测试数量。这样可以为服务运行状况提供更全面的视图,并且可以帮助我们确定在未来可以服务的客户的百分比,这对于测量服务停机的影响是很有价值的。如果将可用性与模拟测试进行比较,就无法在这方面获益。
正常运行时间(uptime)与可用性密切相关,捕获此信号的目的是确定服务是否启动并运行,这纯粹是一个状态信号,不是对服务是否在正常工作的全面检查,也没有提供任何关于服务性能的洞见。服务所有者可以通过多种方式获取正常运行时间。
- 对于正在运行的提供公开接口的服务,可以利用模拟测试来确定服务是否启动。
- 还可以运行 cron 作业,定期检查服务是否启动,并将状态发送到监控工具。
- 如果服务运行在 Kubernetes 上,可以利用内置的 liveness 和 readiness 检查[4]。在 Salesforce,我们即时捕捉 liveness 和 readiness 信号,并发送给 Argus。
时长/延时(P50, P95, P99 secs)
时长是服务成功处理一个请求所花费的时间,这一度量非常重要,因为响应延时表明服务状况不佳以及客户体验不好。对于 REST 服务,时长是从接收到请求和返回成功响应(例如,HTTP 200)之间的时差。
这个度量的计算只考虑成功的请求。我们也可以同时记录错误响应的时延,但不应该和成功的请求混在一起,这么做将导致误导性的数据。对于时延,平均值不是一个好的指标,会掩盖某些请求(以及一些客户)可能遇到的长尾响应时间。因此,强烈建议将此指标以直方图(histogram)的方式收集,从而可以容易的计算和报告 P95、P99 数据。
饱和度(%)
饱和度标识服务消耗的资源有多少,是对系统状态的度量,强调最受限制的资源。举几个例子:在 CPU 受限的系统中,显示 CPU 使用情况;在内存受限的系统中,显示内存使用情况;在 I/O 受限的系统中,显示 I/O 使用情况。为什么要捕获这个信号?首先,我们需要确定服务最受限制的资源,可能是 IOPS、磁盘空间、内存、网络带宽或计算。一旦了解了这一点,就可以测量饱和度,以确定在系统或服务性能开始下降之前,需要为请求提供多少容量。这一指标以百分比衡量,作为服务所有者,需要确定最受限制的资源,并将其作为饱和度度量的基础进行跟踪。
READS 和标准化仪表板
通过将运行状况指标分类为 READS,存储元数据以及其他元数据(包括服务所有权、实例化和拓扑),并利用这些数据构建标准化仪表板,实时查看组织中服务的健康状况,并能够随着时间的推移分析这些信息。下面的截图显示了 Grafana 和 Tableau 中的信息。
超越 READS
READS 指标只是监控服务运行状况的开始,为了调试服务并了解其性能,还可以考虑其他指标。当然,由于工作负载和每个服务所做的工作是不同的,因此不可能在所有服务中统一应用所有指标,但是可以广泛应用相同类别的指标。例如,对基于 HTTP 的 REST 服务(比如响应码为 500)的错误度量,和批处理服务的错误度量是不一样的。
服务可能想要获取的其他指标可能包括:
- 系统指标(用于运行服务的系统)。自动覆盖每个资源的 USE 指标[5]。在 Salesforce,我们会自动收集这些数据,并提供给监控工具。
- 运行时指标(jvm、golang 等),通过 collectD 或进程内收集。
- 基于 java 运行时的 JMX 度量,如 jvm 堆、GC、线程、资源池度量等。
- 其他运行时(如 golang)的类似指标。
如果想了解更多如何从一开始就将可观察性构建到服务中,可以查看Salesforce服务可观测性设计模式。
References:[1] READS: Service Health Metrics: https://engineering.salesforce.com/reads-service-health-metrics-1bfa99033adc
[2] The RED Method: https://grafana.com/files/grafanacon_eu_2018/Tom_Wilkie_GrafanaCon_EU_2018.pdf
[3] The USE Method: http://www.brendangregg.com/usemethod.html
[4] Configure liveness readiness startup probes: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-liveness-command
[5] How we implemented RED and USE metrics for monitoring: https://medium.com/thron-tech/how-we-implemented-red-and-use-metrics-for-monitoring-9a7db29382af