Salesforce 服务可观测性设计模式

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
可观测监控 Prometheus 版,每月50GB免费额度
可观测可视化 Grafana 版,10个用户账号 1个月
简介: Salesforce 服务可观测性设计模式

可观测性是大规模微服务的必备能力之一,离开了可观测性,微服务运维一定会是一场灾难。本文介绍了 Salesforce 在构建服务可观测性方面采用的 5 项设计模式,帮助我们完整系统的理解服务可观测性的架构原则。原文:5 Design Patterns for Building Observable Services[1]


怎样让我们的服务容易被观察,让团队能够更方便的管理服务?本文介绍了 5 个通用设计模式,供开发人员参考。


软件开发中的设计模式是解决常见问题的可重复的解决方案和最佳实践。考虑在服务监控的场景下,如果使用得当,设计模式也可以帮助团队方便的管理服务,并在生产中排除故障。可以将服务监控设计模式分为三类:


  1. 健康检查


如何知道服务正在运行,并且正在做应该做的事情?服务反应是否及时?是否存在潜在的服务问题?是否可以在问题影响到客户之前解决?


  1. 实时告警


当出现问题时(比如服务无响应、速度变慢或使用了太多资源),是否配置了告警通知?


  1. 排除故障


服务有什么问题吗?如果有问题发生,可能需要知道三件事:什么时候发生的,在哪里发生的,是什么原因导致的。在问题发生后,通过日志和跟踪来诊断问题,并更新服务,使这些问题不会对客户产生持久影响。


下面我们依次讨论不同类别的模式(以及反模式)。


image.png


健康检查


健康检查有两种模式:由外向内的健康检查,验证服务是否正在运行,并确定服务的响应时间/延迟;由内向外的健康检查,跟踪应用程序和系统指标,可以在事故发生前发现潜在的问题(包括性能问题)。


模式 1. 由外向内的健康检查


在此模式中,可以运行健康检查服务或模拟测试工具来 ping 服务端点。可以用自己内部构建的工具,也可以用第三方工具,包括 NewRelic、Gomez 和 DataDog 等。服务对 ping 做出响应,并将检查的输出记录到时间序列度量系统(如 Argus[2]或任何用于此类服务的度量系统)中。一旦有了数据,就可以对一段时间内的服务运行状况和其他关键指标实现可视化,并在特定条件下发送告警信息。


概要模式如下所示。


image.png

由外向内运行健康检查的概要设计图


  • 正常运行时间(Uptime) —— 这个指标回答了一个由来已久的问题,“我的服务是否在运行,是否在做应该做的事情?”健康检查程序 ping 了待查服务后,如果收到了响应,就说明服务启动了,如果没有响应,就意味着需要开始补救工作
  • 用户感知的时延(User-perceived latency) —— 我们必须从全球多个位置检查服务时延。例如,从日本访问服务的用户感知的时延可能与从西班牙和美国访问服务的用户感知的时延不同。可以使用健康状况检查 API 调用的时延作为用户感知时延的代表。


上述两组的组合还可以作为服务的综合可用性信号。


模式 2. 由内而外的健康检查


在此模式中,我们通过检测系统和应用程序指标,从而在潜在问题导致服务中断之前就察觉到它们。


要确定是否存在可能影响服务性能或可用性的潜在问题,需要收集有关应用程序和基础设施的指标。


image.png

由内向外运行健康检查的概要设计图


那么应该关注哪些应用程序指标呢?至少收集以下四种信号。


  • 请求率 —— 服务有多忙?
  • 错误率 —— 服务中是否存在任何错误?如果有,有多少个,多久发生一次?
  • 请求时长 —— 服务响应请求需要多长时间?
  • 饱和度 —— 服务有没有超载?还有多少增长空间?


此外,对于服务使用的每种资源类型(例如 CPU、内存、磁盘空间、IOPS)收集如下系统指标。


  • 利用率 —— 这个资源有多忙?
  • 饱和度 —— 影响应用性能/正常运行能力的最受限制的资源的使用情况?
  • 错误率 —— 资源的错误计数有多少?


收集这些指标还允许我们计算服务的可用性,这将回答一个关键问题:对客户而言,服务或特性是否可用?在大多数情况下,可以结合正常运行时间、时长(延时)和错误率指标来计算服务的可用性,以代表客户体验。例如,如果只根据正常运行时间来计算服务可用性,那么即使查询需要很长时间才能响应/网页需要很长时间才能加载,仍然会被认为是可用的。因此,采用诸如错误率和时延等额外指标对于恰当定义可用性是至关重要的。


反模式: 使用日志对指标建模


日志数据对于故障排查非常有用,我们将很快讨论这个问题。然而,考虑到目前大多数应用程序生成的日志数据量很大,我们确实不希望基于日志数据生成度量指标。使用日志数据对度量建模开销很大(意味着需要花更多的钱),并且增加了提取、处理和反馈的时间,从而增加了 MTTD(平均检测时间),这两种后果都不可接受。我们在 Salesforce 建立了有效的指标收集工具供开发人员使用。


实时告警


当服务出现问题时,告警和通知是服务所有者希望接收信息的主要方式。当服务和基础架构的关键运行状况和性能指标高于或低于指定的阈值(表明存在问题)时,应当配置告警。例如,服务的响应时间突然增加,超过了可接受的阈值,服务的可用性低于指定的阈值,违反了服务的 SLA。


告警的目的是通知相关人员介入补救流程、修复问题,并将服务恢复到正常状态,以便继续为客户服务。尽管在收到告警时可以通过触发自动工作流自动修复问题,但并不是所有的问题(特别是复杂的服务问题)都可以这样解决。自动修复可能有帮助的典型场景包括重新启动服务、增加/减少云环境中的计算资源、如果有任何未经授权的端口开放(安全漏洞)则终止实例等。


通过使用更复杂的技术(包括机器学习),可以主动发出告警并检测异常情况,从而为服务所有者提供更好的体验。主动告警允许我们在问题影响到客户之前采取补救措施。例如,根据当前的使用趋势,通知我们服务将在一周内耗尽磁盘空间,而不是等到磁盘只剩 10%空间时才通知我们。主动告警为修复问题提供了更多的时间,让我们不需要在凌晨 3 点出现告警的时候来修复问题。这种类型的告警可以创建一个问题单,以便服务所有者在第二天早上查看问题。检测异常可以减少告警噪声,并使服务所有者不必配置静态阈值来获得告警。当系统检测到给定指标的模式中有异常时,可以发出告警。还可以考虑周期性因素,从而减少假阳性(噪音),并在一段时间内自动调整阈值以及异常的定义。


模式 3. 故障修复


一般的告警模式包括确定问题是否可以自动修复,或者是否需要人工干预,以避免违反公司与客户之间的服务水平协议(Service Level Agreement, SLA)。下面的流程图包含了自动修复和需要人工干预的修复。


image.png

启动自动补救还是调用人工操作的决策流程图


告警反模式


  • 不要依赖人工观察。 随着系统规模和复杂性的增加,我们不能依赖人工 24/7 的盯着监视器来查看服务运行状况趋势,并在超过阈值时呼叫某人来解决问题。我们需要依靠机器和算法,在出现问题时通知我们,这也能够排除人为错误,并尽可能将过程自动化。
  • 并非所有告警都是等价的。 不要以相同的方式对待所有告警,将服务中的每个小问题都作为告警发送电子邮件/Slack 通知只会导致垃圾邮件泛滥,并大大降低信噪比。对于每一个可能导致客户问题/违反 SLA(关键问题)的服务问题,都需要呼叫工程师(使用类似 PagerDuty 的东西)进行处理,其他所有内容都应该作为问题单记录,或者作为日志记录。


排除故障


当服务出现问题时,需要有关出错原因、出错时间和出错地点的信息。对服务进行编码,以便此类信息可以用于故障诊断,有两个关键方法可以获得这些可用信息。

  • 在日志中记录出错条件和相关信息
  • 在服务中启用分布式跟踪(特别是在微服务环境中)


模式 4. 在日志中记录错误信息


日志是帮助我们定位问题的好帮手,所以一定要记录服务的出错条件。可以在服务中包含日志库来捕获应用程序日志,并送到日志服务。我们在 Salesforce 使用 Splunk[3],不过也可以采用其他选择,比如 DataDog、NewRelic 等。


在定位故障时,可以使用应用程序和基础设施日志来帮助我们确定是什么导致了问题,以及如何减少问题再次发生的机会。


下图描述了日志系统的概要架构。


image.png

日志系统概要架构图


模式 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

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
2月前
|
设计模式 API 持续交付
深入理解微服务架构:设计模式与实践
【10月更文挑战第19天】介绍了微服务架构的核心概念、设计模式及最佳实践。文章详细探讨了微服务的独立性、轻量级通信和业务能力,并介绍了聚合器、链式和发布/订阅等设计模式。同时,文章还分享了实施微服务的最佳实践,如定义清晰的服务边界、使用API网关和服务发现机制,以及面临的挑战和职业心得。
|
4月前
|
监控 负载均衡 Dubbo
《Dubbo架构设计大揭秘:八大层次,带你领略微服务之美!》
【8月更文挑战第24天】Dubbo是一款广泛应用于微服务架构中的高性能Java RPC框架。其设计强调可扩展性和可维护性。整体架构分为八个层次:接口层定义服务API;代理层处理RPC请求;服务层实现接口;注册中心层管理服务注册与发现;路由层实现服务寻址;监控层收集调用数据;集群层提供负载均衡及容错;远程调用层负责网络通信。各层职责分明,便于应对多变的业务需求。
46 1
|
4月前
|
设计模式 Java 微服务
你一定要知道业务开发最常用的两种设计模式
文章介绍了业务开发中最常用的两种设计模式:策略模式和异步形式的责任链模式,通过具体案例展示了它们在代码解耦、扩展性增强以及提升响应速度方面的应用,并强调了设计模式在提升代码质量和开发效率中的重要性。
|
7月前
|
设计模式 Java 数据安全/隐私保护
设计模式之六大设计原则
设计模式之六大设计原则
78 0
|
7月前
|
设计模式 Go
23 种设计模式汇集
23 种设计模式汇集
40 0
|
7月前
|
设计模式 程序员
软件设计模式:六大设计原则
软件设计模式:六大设计原则
164 0
|
存储 缓存 监控
架构师进阶,微服务设计与治理的16条常用原则
架构师进阶,微服务设计与治理的16条常用原则
331 0
|
设计模式 缓存 中间件
从设计模式谈业务开发
本文主要讲述我们如何通过一个主干业务流程承接多个业务场景并在数据上可适配到多端型多场景,实现在服务端高质量高效率的“包接口”。
|
设计模式 Java
深入理解设计模式!六大设计原则的分析与介绍
本篇文章开始介绍程序架构设计中的设计模式,介绍了设计模式的基本概念以及23设计模式。主要介绍了设计模式中的六大设计原则。开闭原则,里氏代换原则,依赖倒转原则,接口隔离原则,迪米特原则和合成复用原则。这几大原则是设计模式使用的基础,在使用设计模式时,应该牢记这六大原则。
6003 0
深入理解设计模式!六大设计原则的分析与介绍
|
设计模式 存储 大数据
大数据开发基础的设计模式的观察者
观察者模式是大数据开发基础的设计模式之一。它是一种行为型模式,用于定义对象之间的一对多依赖关系,当一个对象状态发生改变时,其所有依赖者都会收到通知并自动更新。
86 0
下一篇
DataWorks