当前位置: 首页 > 科技观察

通过有效的错误管理提高系统健壮性

时间:2023-03-21 13:26:27 科技观察

通常,系统的健壮性来自全面有效的错误管理。由于错误可能发生在我们的硬件和软件系统环境的任何部分,因此我们需要区别对待它们。例如:数据中心-整个数据中心(DC)可能因电源故障、网络连接故障、环境灾难等而变得不可用硬件设备-服务器、存储组件可能会出现硬盘故障、磁盘已满、可分配资源耗尽和其他硬件错误。软件应用程序——无论应用程序的技术堆栈如何,都可能发生应用程序错误、异常软件行为和程序级缺陷。为了从各个方面应对上述故障,我们往往需要通过以下手段来提供系统的自愈能力:通过监控,提供电源、网络、冷却系统等方面的冗余来实现数据中心的高可用性。部署在云端,减少错误实例,使用更成熟的技术栈,基于微服务的分布式架构。监控服务器各项参数,采用多种高可用部署方式,采用容器化方式,具有强大的DevOps功能。通过应用各种替代架构和设计模式来最大限度地减少错误。例如,异步处理用户请求有助于避免服务器过载并为用户提供一致的体验。可以看出,无论是系统架构师还是应用程序设计者,他们的主要目标都是根据实际业务需求和成本影响,仔细考虑和设计各个组件的高可用性,并能够优雅地处理应用程序错误.模式简述目前业界有多种架构模式和方法,可以满足不同的应用架构范式、功能需求、NFR(Non-FailureRequest)、应用故障恢复能力。例如:如果应用是基于微服务的,那么我们的重点应该放在微服务集成依赖的容错上。如果应用程序是基于事件的架构,除了正常的错误处理之外,我们还应该注意处理幂等性和出现问题时可能丢失的数据。虽然基于API的同步应用很容易将错误返回给调用者,但如果问题持续时间较长,我们就需要更实用的监控和事件管理机制。在基于批处理的组件中,我们可能应该专注于以幂等方式重新启动或恢复原始批处理功能。错误代码如果没有关于错误代码的通用约定和指南,每个应用程序或系统将根据用例和设计遵循自己的自定义默认错误代码。这有可能导致不同的方法相互冲突。可见,在应用程序的错误处理过程中,我们应该提前定义错误代码。通过标准化和直观的错误处理方法,可以提高解决问题的效率,以及错误的数量、负载峰值以及特定类型故障的影响等细节。错误处理下图显示了如何在基于事件的应用程序中处理各种错误。当然,所涉及的具体步骤可能因架构模型而异。首先,我们应该区分应用程序的可重试错误和不可重试错误。例如,当传入消息本身存在问题时,除非有人为干预,否则重试此类错误通常没有意义。那些数据库连接问题值得重试。当应用出现重试类型错误时,我们可以选择统一的“错误重试配置”方式进行微调。如下表所示,在基于事件的服务中,一旦基础设施组件的可用性缺失,我们需要通过预定义的重复重试机制来确认运营商是否及时修复了。这往往比直接怀疑并处理并发请求导致问题的可能性更符合常识。触发事件我们需要一种方法来触发事件并在所有重试失败时升级错误。在简单的情况下,我们可以直接将问题的相关信息以通知的形式反馈给用户,建议用户重新提交所需的请求。但有些问题源于内部技术问题,导致用户体验突然下降。例如,在基于事件的架构中,异步集成模式经常使用DLQ(译者注:死信队列,DeadLetterQueue)作为错误处理模式。尽管如此,DLQ只是该过程中的一个临时步骤。我们仍然需要通过触发事件或发送警报来可靠地升级错误。那么,我们如何设计一个集事件和告警于一体的管理系统呢?下面,我们将讨论两种主要的方法:第一种方法:当应用程序完成所有重试后,我们需要利用其可用的logs功能来构建可靠的错误报告路径,以减少丢失错误消息的可能性。虽然业界有成熟的日志记录标准。但是,我们仍然需要将各个错误日志分开,以便事件管理系统不会被不相关的错误消息淹没。我们通常将此类日志称为“错误警报”。它们通常由专用代码库和组件以预设格式生成,及时生成大量错误消息。这是一个代码示例:Java{"logType":"ErrorAlert","errorCode":"subA.compA.DB.DatabaseA.Access_Error","businessObjectId":"234323","businessObjectName":"ACCOUNT","InputDetails":"","InputContext":"任何带有输入的上下文信息","datetime":"错误的日期时间","errorDetails":"错误跟踪","..otherinfoasneeded":"..."}由于大多数组织会使用不同的日志监控技术栈,这里我以日志聚合器(logaggregator)为例,它将各种日志路由到不同的组件,以便于读取日志事件,相应的配置,并根据需要触发警报。如下图所示,如果在监控的基础上出现需要解决的问题,我们往往需要再次调用DLQ来处理。为了让警报响应有意义且可操作的事件,我们通常需要根据需要配置它们。由于组织采用的事件管理系统不同,不同的配置可能会导致不同类型的后续行动。以下是需要配置的各种属性的示例。它的错误代码在整个系统中遵循特定的分类法。当然,它们也可以根据需要集中到一个中央配置管理系统中。如下图所示,第二种方法是将误报的调度程序组件写入DLQ而不是单独的日志,而其他方面与第一种方法基本相似。也就是说,它是基于DLQ的。哪种方法更好?从应用的角度来看,基于日志的方式更加灵活,但当然也有缺点,就是我们需要在错误到达事件管理系统之前处理好各个组件的集成。一般来说,日志数据的关键性不是很高,但如果我们用它来触发事件,那么我们需要检查是否存在丢失或不完整的风险。在之前的系统实现过程中,遇到过应用请求高峰,导致日志数据丢失的问题。当时我们不得不放弃这种方法。当然,这是极端情况,并不是所有的日志环境都会遇到。基于DLQ的方法具有以下优点和缺点:我们可以将基于DLQ的方法用作消息传递系统中的非DLQ冗余传输链路。当然,是否真的需要这种冗余机制完全取决于所传输数据的重要性。如果我们需要在现有系统中结合其他应用程序,则在将其连接到中央总线并发送错误警报时,消息路由器的数量可能会受到限制。就这种组合方案本身而言,不仅会增加系统的复杂度,还会增加额外出错的可能性。推倒重来的方法就是“看起来很漂亮”。毕竟,需要集成的组件或总线越少,误报事件的传输就越可靠。总结表明,为了有效处理应用中可能出现的错误,我们需要一个能够无缝集成到现有IT系统中的整体解决方案,以实现对错误和问题的有效管理。虽然上面主要讨论了如何将应用程序错误处理集成到事件管理系统中,但是这样的思路和方法同样适用于本文开头提到的各种硬件问题。当然,所有这些都应该以自动化的方式集中在一个地方,以便它们可以进一步与各种错误和问题相关联,从而可以使用一个解决方案来处理所有可能的问题。上一篇文章还向您展示了两种依赖于事件管理系统并且可以与现代技术(例如API或某种SDK)集成的处理方法。当然,具体采用的方法因平台而异。但是,值得注意的是,在基于问题创建重复发生的事件时,要避免“淹没”事件管理系统。我们应该使用尽可能少的集成,并使用尽可能多的开箱即用的事件管理系统。对此,一些自动化、智能化的事件去重解决方案往往可以有效解决此类问题。译者介绍51CTO社区编辑JulianChen。他在实施IT项目方面拥有超过十年的经验。善于控制内外部资源和风险。专注传播网络与信息安全知识与经验;翻译等形式分享前沿技术和新知识;经常在线上和线下开展信息安全培训和讲座。原标题:通过有效的错误管理建立弹性,ShaileshAgarwal