需要运行24/7的程序中的异常处理


14

我已经读到我们应该只捕获可以处理的异常,这使得捕获基本异常类(在这种情况下为C#)不是一个好主意(除其他原因之外)。我目前是一个项目的一部分,到目前为止,除了捕获到的基本异常之外,我什么都没有看到。我提到这样做是不明智的做法,但是响应是“此服务需要24/7运行,因此是这样。”

由于我对如何正确处理需要24/7运行的程序中的异常没有很好的反应,所以我现在在这里。我没有找到有关如何处理需要全天候运行的“关键”程序/服务中的异常处理的任何信息/建议(在这种情况下,我认为如果该服务关闭一分钟可能会没事的或两个,所以甚至都不重要)。我了解这取决于程序的确切性质。与在线游戏的日志扫描器相比,可能导致生命危险的程序的要求有很大不同。

两个例子:

1:为英国铁路客户提供的提前输入服务,当他们在线搜索火车站时使用。

2:一个程序,该程序基于从轨道,火车等中的各种传感器提供的实时信息,自动控制上述铁路的铁路开关。

如果第一个程序崩溃了一到两分钟,它可能不会引起重大问题,而后者可能会导致人员伤亡。关于如何处理每个建议?指向哪里可以找到有关此问题的更多信息和想法?


2
在实时应用程序中处理异常期间堆栈松开(原文如此!)可能会破坏火车。
迪尔·亨特

4
@DeerHunter错误编码,没有例外,可以得到相同的结果。
2014年

9
好吧,你呢catch Exception。这并不意味着您的程序可以运行,而是意味着故障会使应用程序状态在继续执行时遭到破坏,这是一个更加危险的地方。崩溃的程序可能是灾难性的,但一个程序,是一个无效的状态,但仍然执行操作可积极灾难性的。
Phoshi 2014年

1
如果应用程序需要24/7全天候运行,则在某个地方存在一个无限循环,最好将此无限循环包裹在捕获所有未处理异常的某些构造周围。如果不是这种情况,未处理的异常将渗透到main和kaboom之外的现有捕获全部处理程序!24/7应用程序终止。
David Hammen 2014年

Answers:


7

某些语言功能,例如

  • 垃圾收集
  • 例外系统
  • 懒惰评估

通常不适用于实时系统。人们可能应该选择一种没有这些功能的语言,并尝试证明某些属性,例如最大内存使用量或最大响应时间。


当程序需要连续运行,但是短暂的和非全局的故障是可以接受的,那么我们可以使用类似于Erlang的策略。Erlang是一种并发的功能编程语言。通常,用Erlang编写的程序将由多个工作进程组成,这些工作进程可以彼此通信(角色模型)。如果一个工作线程遇到异常,则将其重新启动。虽然这确实意味着停机时间很短,但其他参与者仍可以照常进行。

总结一下:在一个强大的程序中,各个部分相互隔离,可以独立地重新启动或缩放。

因此,基本上,我们需要一段与此等效的代码:

while (true) {
  try {
    DoWork();
  }
  catch (Exception e) {
    log(e);
  }
}

加上终止循环的方法。这样的循环将驱动每个工作线程。


通过包罗万象忽略错误的问题是错误原因可能侵犯了程序的不变性,并且后续操作可能无用。一个好的解决方案是在独立工作人员之间不共享数据。重新启动工作程序将重建所有必要的不变式。这意味着他们必须进行不同的通信,例如通过消息发送。演员的状态可能不属于其他演员的不变式。

捕获过多异常的另一个问题是,即使采取了这种预防措施,并非所有异常都可以通过重新启动来修复。否则,可以通过重新启动来解决诸如内存不足之类的难题。但是,拔出物理电缆后,重新启动不会帮助您重新获得Internet连接。


1
是的,但是像“物理电缆被拔出”之类的情况恰好是您只希望填充异常日志,直到有人重新插入电缆,然后事情又开始正常工作,而无需进一步手动重新启动应用程序。
Mark Hurd 2014年

2

要回答您的问题,必须了解什么是例外以及它们如何工作。

当此类错误发生时,在需要用户帮助的情况下,通常会引发异常。在这种情况下,展开堆栈和处理异常需要多长时间都没关系。

没有捕获处理程序,程序将停止执行。根据您的设置和要求,它可能是可接受的。

在您的特定情况下:

  1. 如果无法执行查询(例如,错误的城市名称),则将错误告知用户,并要求解决。
  2. 如果您没有从关键传感器获取信息,那么继续进行而不要求操作员解决问题就没有多大意义。

这意味着在两种情况下都可以使用异常,在RT程序中要格外小心,以仅指示无法继续执行的严重问题。


1

到目前为止,除了基本异常之外,我什么都没有看到。

听起来这里有问题,因为没有适当地处理异常。在适当的时候捕获异常并采取适当的措施(取决于异常的类型)将使服务以更加可靠的方式运行。

如果服务必须继续,那么按预期工作很重要。在您的示例中,如果控制铁路道岔的程序引发异常,则可能表明与安全相关传感器的通讯存在问题。如果捕获基本异常并继续运行,则该服务可能会运行,但可能无法正常运行,从而导致灾难。

或者,如果您捕获到传感器发生通信故障时引发的异常并进行适当处理(即,在受影响的区域停止火车),则您的服务正在运行,并且您没有杀死任何人。

因此,据我所知,我建议您最好是先添加更具体的异常处理,而不是删除base-exception-type处理程序。


0

关于第2点:请勿使用C#。这不是一个实时的语言,你如果您尝试使用它作为这样受到伤害。

对于第1点:您可以采用erlang方式:使其崩溃,然后重新启动


我的C#使用和专业知识不在第二点(实时轨道切换)上。我很好奇为什么C#如此不适合执行此任务?
Michael O'Neill 2014年

1
通常:垃圾收集器会使程序的行为在时间方面无法预测。而且,运行时太复杂了,在这些情况下,您需要简单的东西,它们就更加可预测
miniBill 2014年

0

免责声明:这些只是想法,我没有经验。

我猜想,满足第二个示例要求的程序应该是非常模块化的。因此,模块将能够重新启动,而不会破坏系统的稳定性。

例如,一个未能通过内部状态断言的对象应该能够被销毁并重新创建,并在此过程中通知其所有消费者和供应商。更具体地说,如果程序正在控制铁路的开关并在决策循环中使断言失败,则它仍可以运行紧急模块,该模块将停止所有相关列车,并等待主决策模块重新初始化。

更现实的是,将引入冗余 -硬件和软件的重复。一个实例连接到受控系统,另一个实例自由运行。如果检测到错误,则切换系统。

一个示例是同一台计算机上的两个进程,它们相互监视,如果一个进程被杀死,另一个进程将重新生成该进程并将其父PID与其自身解除关联。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.