通常,系统的鲁棒性来自全面有效的错误管理。由于在我们的软硬件系统环境中,任何一个部分都可能发生错误,因此我们需要以不同的方式予以处理。例如:
为了应对上述来自各个方面的故障,我们往往需要通过如下手段,来提供系统的自愈能力:
可见,无论是系统架构师、还是应用设计人员,他们的主要目标都要根据实际业务需求和成本影响,精心考虑和设计各个组件的高可用性,并能够优雅地处理应用程序的错误。
目前,业界有许多种架构模式和方法,可以满足不同的应用架构范式、功能需求、NFR(Non-Failure Request)、以及应用程序的故障恢复能力。例如:
如果没有关于错误代码的通用约定与指南,每个应用或系统将会按照自定义的默认错误代码方式,根据用例和设计自行处理。而这有可能会导致不同方式相互之间的冲突。可见,在应用程序的错误处理过程中,我们该事先定义好错误代码,通过标准化且直观的错误处理方式,既提高解决问题的效率,又能够通过离线分析的方式,统计错误数量、负载峰值、以及特定类型故障的影响等细节。
下面的示意图展示了如何在基于事件的应用程序中,处理各种错误。当然,其中具体涉及到的步骤,可能会因架构模式的不同而有所差异。
首先,我们应当区分应用程序的可重试(retryable)错误和不可重试(non-retryable)错误。例如,当输入的消息本身存在问题时,通常除非得到人工干预,否则重试此类错误是没有意义的。而那些数据库连接方面的问题,是值得进行重试的。

当应用程序出现重试类型的错误时,我们可以选择统一的“错误重试配置”方式,来进行微调处理。如下表所示,在基于事件的服务中,一旦基础设施组件出现可用性的缺失,我们需要通过预定义的反复重试机制,来及时确认运营商是否已及时修复。这往往比直接怀疑和处置由并发量请求所引发的问题可能性,要更加符合常理。

在所有重试都以失败告终时,我们需要有一种方法,来触发事件并升级错误。在简单情况下,我们可以将问题的相关信息,直接以通知的形式,反馈给用户,并且建议其重新提交所需的请求。但是有些问题源于某个内部技术问题,所引发并导致的用户体验度的骤降。例如,在基于事件的架构中,异步集成模式通常使用DLQ(译者注:Dead Letter Queue,死信队列)作为错误处理模式。不过,DLQ只是整个过程中的一个临时步骤。我们仍然需要通过触发事件或发送警报的方式,去可靠地升级错误。那么,我们该如何设计一个事件与警报相集成的管理系统呢?下面,我们将讨论两种主要的方法:
第一种方法:当应用程序完成了所有重试之后,我们需要利用其可用的日志功能,构建可靠的错误报告路径,以减少丢失出错信息的可能。虽然业界已有成熟的日志记录标准。但是,我们仍然需要将各个错误日志区别开来,以免事件管理系统中充满了不相关的错误信息。我们通常将此类日志称为“错误警报”。它们往往是由专用的代码库和组件,按照预先设定的格式,及时产生大量的错误信息。下面是一段代码示例:
Java
{
"logType": "ErrorAlert",
"errorCode": "subA.compA.DB.DatabaseA.Access_Error",
"businessObjectId": "234323",
"businessObjectName": "ACCOUNT",
"InputDetails" : "<Input object/ event object>",
"InputContext" : " any context info with the input",
"datetime": "date time of the error",
"errorDetails" : "Error trace",
"..other info as needed": "..."
}由于大多数组织会使用不同的日志监控技术栈,因此,我在此以日志聚合器(log aggregator)为例,会将各种日志路由到不同的组件处,以便读取日志事件、对应的配置,并按需触发警报。如下图所示,如果出现需要在监控的基础上,去解决被发现的问题时,我们往往需要再次调用DLQ予以处理。

为了让警报能够反应有意义且具有操作性的事件,我们通常需要对它们进行必要的配置。由于组织采用的事件管理系统存在着差异性,因此不同的配置可能会驱动不同类型的后续操作。以下是各种需要配置属性的示例。其错误代码会在整个系统中遵循特定的分类方法。当然,它们也可以按需集中到一个中央的配置管理系统中。

如下图所示,第二种方法是将错误警报的调度程序组件写入DLQ,而非各个日志中,而其他方面则与第一种方法基本相似。也就是说,它是基于DLQ的。

从应用程序的角度来看,基于日志的方法更具有灵活性,当然也存在着如下缺点:
而基于DLQ的方法则存在着如下优、缺点:
可见,为了有效地处理应用程序中可能出现的错误,我们需要一种整体的解决方法,能够无缝地集成到现有的IT系统中,实现对于错误和问题的有效管理。虽然上文主要讨论的是如何将应用程序的错误处理,集成到事件管理系统中,但是对于本文开头提到的各种硬件问题,此类思路与方法同样具有适用性。当然,所有这些都应当以自动化的方式,聚集到一处,以便它们能够进一步关联上各种错误与问题,进而采用单一的解决方案,来处置所有可能出现的问题。
前文也向您展示了两种依赖于事件管理系统、并能够与现代技术(如API或某种SDK)相集成的处置方法。当然,具体方法的采用也会因平台而异。不过值得注意的是,在根据问题创建重复性事件时,为了避免“淹没”事件管理系统。我们应当尽量少地使用集成,而尽量多地采用开箱即用的事件管理系统。对此,一些自动化的、智能化的事件去重方案,往往能够有效地解决此类问题。
陈 峻 (Julian Chen),51CTO社区编辑,具有十多年的IT项目实施经验,善于对内外部资源与风险实施管控,专注传播网络与信息安全知识与经验;持续以博文、专题和译文等形式,分享前沿技术与新知;经常以线上、线下等方式,开展信息安全类培训与授课。
原文标题:Building Resiliency With Effective Error Management,作者:Shailesh Agarwal
我正在使用i18n从头开始构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在rubyonrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m
这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c