可观测性是大规模微服务的必备能力之一,离开了可观测性,微服务运维一定会是一场灾难。本文介绍了 Salesforce 在构建服务可观测性方面采用的 5 项设计模式,帮助我们完整系统的理解服务可观测性的架构原则。原文:5 Design Patterns for Building Observable Services[1]
怎样让我们的服务容易被观察,让团队能够更方便的管理服务?本文介绍了 5 个通用设计模式,供开发人员参考。
软件开发中的设计模式是解决常见问题的可重复的解决方案和最佳实践。考虑在服务监控的场景下,如果使用得当,设计模式也可以帮助团队方便的管理服务,并在生产中排除故障。可以将服务监控设计模式分为三类:
- 健康检查
如何知道服务正在运行,并且正在做应该做的事情?服务反应是否及时?是否存在潜在的服务问题?是否可以在问题影响到客户之前解决?
- 实时告警
当出现问题时(比如服务无响应、速度变慢或使用了太多资源),是否配置了告警通知?
- 排除故障
服务有什么问题吗?如果有问题发生,可能需要知道三件事:什么时候发生的,在哪里发生的,是什么原因导致的。在问题发生后,通过日志和跟踪来诊断问题,并更新服务,使这些问题不会对客户产生持久影响。
下面我们依次讨论不同类别的模式(以及反模式)。
健康检查
健康检查有两种模式:由外向内的健康检查,验证服务是否正在运行,并确定服务的响应时间/延迟;由内向外的健康检查,跟踪应用程序和系统指标,可以在事故发生前发现潜在的问题(包括性能问题)。
模式 1. 由外向内的健康检查
在此模式中,可以运行健康检查服务或模拟测试工具来 ping 服务端点。可以用自己内部构建的工具,也可以用第三方工具,包括 NewRelic、Gomez 和 DataDog 等。服务对 ping 做出响应,并将检查的输出记录到时间序列度量系统(如 Argus[2]或任何用于此类服务的度量系统)中。一旦有了数据,就可以对一段时间内的服务运行状况和其他关键指标实现可视化,并在特定条件下发送告警信息。
概要模式如下所示。
由外向内运行健康检查的概要设计图
- 正常运行时间(Uptime) —— 这个指标回答了一个由来已久的问题,“我的服务是否在运行,是否在做应该做的事情?”健康检查程序 ping 了待查服务后,如果收到了响应,就说明服务启动了,如果没有响应,就意味着需要开始补救工作
- 用户感知的时延(User-perceived latency) —— 我们必须从全球多个位置检查服务时延。例如,从日本访问服务的用户感知的时延可能与从西班牙和美国访问服务的用户感知的时延不同。可以使用健康状况检查 API 调用的时延作为用户感知时延的代表。
上述两组的组合还可以作为服务的综合可用性信号。
模式 2. 由内而外的健康检查
在此模式中,我们通过检测系统和应用程序指标,从而在潜在问题导致服务中断之前就察觉到它们。
要确定是否存在可能影响服务性能或可用性的潜在问题,需要收集有关应用程序和基础设施的指标。
由内向外运行健康检查的概要设计图
那么应该关注哪些应用程序指标呢?至少收集以下四种信号。
- 请求率 —— 服务有多忙?
- 错误率 —— 服务中是否存在任何错误?如果有,有多少个,多久发生一次?
- 请求时长 —— 服务响应请求需要多长时间?
- 饱和度 —— 服务有没有超载?还有多少增长空间?
此外,对于服务使用的每种资源类型(例如 CPU、内存、磁盘空间、IOPS)收集如下系统指标。
- 利用率 —— 这个资源有多忙?
- 饱和度 —— 影响应用性能/正常运行能力的最受限制的资源的使用情况?
- 错误率 —— 资源的错误计数有多少?
收集这些指标还允许我们计算服务的可用性,这将回答一个关键问题:对客户而言,服务或特性是否可用?在大多数情况下,可以结合正常运行时间、时长(延时)和错误率指标来计算服务的可用性,以代表客户体验。例如,如果只根据正常运行时间来计算服务可用性,那么即使查询需要很长时间才能响应/网页需要很长时间才能加载,仍然会被认为是可用的。因此,采用诸如错误率和时延等额外指标对于恰当定义可用性是至关重要的。
反模式: 使用日志对指标建模
日志数据对于故障排查非常有用,我们将很快讨论这个问题。然而,考虑到目前大多数应用程序生成的日志数据量很大,我们确实不希望基于日志数据生成度量指标。使用日志数据对度量建模开销很大(意味着需要花更多的钱),并且增加了提取、处理和反馈的时间,从而增加了 MTTD(平均检测时间),这两种后果都不可接受。我们在 Salesforce 建立了有效的指标收集工具供开发人员使用。
实时告警
当服务出现问题时,告警和通知是服务所有者希望接收信息的主要方式。当服务和基础架构的关键运行状况和性能指标高于或低于指定的阈值(表明存在问题)时,应当配置告警。例如,服务的响应时间突然增加,超过了可接受的阈值,服务的可用性低于指定的阈值,违反了服务的 SLA。
告警的目的是通知相关人员介入补救流程、修复问题,并将服务恢复到正常状态,以便继续为客户服务。尽管在收到告警时可以通过触发自动工作流自动修复问题,但并不是所有的问题(特别是复杂的服务问题)都可以这样解决。自动修复可能有帮助的典型场景包括重新启动服务、增加/减少云环境中的计算资源、如果有任何未经授权的端口开放(安全漏洞)则终止实例等。
通过使用更复杂的技术(包括机器学习),可以主动发出告警并检测异常情况,从而为服务所有者提供更好的体验。主动告警允许我们在问题影响到客户之前采取补救措施。例如,根据当前的使用趋势,通知我们服务将在一周内耗尽磁盘空间,而不是等到磁盘只剩 10%空间时才通知我们。主动告警为修复问题提供了更多的时间,让我们不需要在凌晨 3 点出现告警的时候来修复问题。这种类型的告警可以创建一个问题单,以便服务所有者在第二天早上查看问题。检测异常可以减少告警噪声,并使服务所有者不必配置静态阈值来获得告警。当系统检测到给定指标的模式中有异常时,可以发出告警。还可以考虑周期性因素,从而减少假阳性(噪音),并在一段时间内自动调整阈值以及异常的定义。
模式 3. 故障修复
一般的告警模式包括确定问题是否可以自动修复,或者是否需要人工干预,以避免违反公司与客户之间的服务水平协议(Service Level Agreement, SLA)。下面的流程图包含了自动修复和需要人工干预的修复。
启动自动补救还是调用人工操作的决策流程图
告警反模式
- 不要依赖人工观察。 随着系统规模和复杂性的增加,我们不能依赖人工 24/7 的盯着监视器来查看服务运行状况趋势,并在超过阈值时呼叫某人来解决问题。我们需要依靠机器和算法,在出现问题时通知我们,这也能够排除人为错误,并尽可能将过程自动化。
- 并非所有告警都是等价的。 不要以相同的方式对待所有告警,将服务中的每个小问题都作为告警发送电子邮件/Slack 通知只会导致垃圾邮件泛滥,并大大降低信噪比。对于每一个可能导致客户问题/违反 SLA(关键问题)的服务问题,都需要呼叫工程师(使用类似 PagerDuty 的东西)进行处理,其他所有内容都应该作为问题单记录,或者作为日志记录。
排除故障
当服务出现问题时,需要有关出错原因、出错时间和出错地点的信息。对服务进行编码,以便此类信息可以用于故障诊断,有两个关键方法可以获得这些可用信息。
- 在日志中记录出错条件和相关信息
- 在服务中启用分布式跟踪(特别是在微服务环境中)
模式 4. 在日志中记录错误信息
日志是帮助我们定位问题的好帮手,所以一定要记录服务的出错条件。可以在服务中包含日志库来捕获应用程序日志,并送到日志服务。我们在 Salesforce 使用 Splunk[3],不过也可以采用其他选择,比如 DataDog、NewRelic 等。
在定位故障时,可以使用应用程序和基础设施日志来帮助我们确定是什么导致了问题,以及如何减少问题再次发生的机会。
下图描述了日志系统的概要架构。
日志系统概要架构图
模式 5. 微服务的分布式跟踪
在微服务体系架构下,当发生事故或性能下降时,不仅仅需要知道哪里出错,还需要知道是哪个微服务引起了问题。
分布式跟踪允许我们通过 requestID 标识每个请求来获得这些信息。当出现问题时,可以查看其在请求流中发生的位置,以及判断该问题是与我们的服务相关还是与依赖的服务相关。我们在 Salesforce 已经将所有应用与自主开发的分布式跟踪服务(构建在 Zipkin 之上)Tracer 集成在一起,生成的 span 被发送到 Tracer 上,上下文通过 B3 报头[4]传播到下游应用,使用 Zipkin[5]或 OpenTelemetry[6]库实现可视化。
然后呢?
通过采用关于健康检查、告警和故障排除的设计模式,可以从头开始构建可观察服务。有很多工具和资源可以帮助我们开始。强烈推荐阅读谷歌的站点可靠性工程(SRE)一书[7],特别是导论[8]中的“监控”部分和第 6 章: 监控分布式系统[9]。此外,还可以查看我们的可观测性 101 系列[10],了解更多关于微服务监控的信息。
References:[1] 5 Design Patterns for Building Observable Services: https://engineering.salesforce.com/5-design-patterns-for-building-observable-services-d56e7a330419
[2] Argus: https://github.com/salesforce/Argus
[3] Splunk: https://www.splunk.com/
[4] B3 propagation: https://github.com/openzipkin/b3-propagation
[5] Zipkin: https://zipkin.io/
[6] OpenTelemetry: https://opentelemetry.io/
[7] Google SRE Book: https://landing.google.com/sre/sre-book/toc/
[8] Google SRE Book Instroduction: https://landing.google.com/sre/sre-book/chapters/introduction/
[9] Google SRE Book Monitoring distributed systems: https://landing.google.com/sre/sre-book/chapters/monitoring-distributed-systems/
[10] Salesforce Observability 101: https://engineering.salesforce.com/tagged/observability