故障处理

小窍门

本文档中的所有指导可以用作示例和思考的材料。 不要将其视为规范性解决方案,因为故障处理高度特定于应用程序。 这些模式和其他模式仅在对特定情况有充分了解的情况下应用时才有用。

处理失败通常是对分布式系统进行编程的最难部分。 执行组件模型使得处理不同类型的故障要容易得多,但开发人员负责考虑故障可能性并相应地处理故障。

失败类型

编码 grain 时,所有调用都是异步的,并且可能会经过网络。 每次粒度调用可能会因为以下原因之一失败:

  • 由于网络分区、崩溃或其他原因,该存储单元在当前无法访问的筒仓上被激活。 如果该竖井尚未标记为失效,请求可能会超时。
  • grain 方法调用可能会引发异常,导致任务失败无法继续。
  • Grain 的激活不存在,并且无法创建,因为 OnActivateAsync 方法会引发异常或陷入死锁。
  • 网络故障导致在发生超时之前无法与grain通信。
  • 其他潜在原因。

检测故障

获取对 grain 的引用总是会成功,并且是一个本地操作。 但是,方法调用可能会失败。 当他们这样做时,将会收到一个异常。 捕获任何必要级别的异常; Orleans 可以在孤立的系统之间传播它们。

从故障中恢复

恢复作业的一部分在Orleans中是自动的。 如果不再可访问粒度, Orleans 则在下一个方法调用中重新激活它。 需要处理并确保应用程序上下文中的正确性的部分是状态。 粒度的状态可能会部分更新,或者作可能涉及多个粒度,并且仅部分完成。

观察到颗粒操作故障后,请采取以下一项或多项措施:

  • 重试操作:通常适用,特别是在该操作不涉及可能半完成的状态更改时。 这是最常见的方法。
  • 修复/重置状态:尝试更正部分更改的状态。 为此,请调用一个方法,该方法将状态重置为最后一个已知正确状态,或者只需使用 ReadStateAsync从存储中读取正确的状态即可。
  • 重置相关状态:重置所有相关激活的状态,并确保所有所涉及的粒度的状态一致。
  • 使用事务或进程管理器:使用进程管理器模式或数据库事务执行多粒度状态操作。 这可确保作完全完成或保持状态不变,避免部分更新。

根据应用程序的不同,重试逻辑可能遵循简单或复杂的模式。 可能还需要执行其他作,例如通知外部系统。 通常,可以选择重试该操作、重启相关的程序,或停止响应直到所需的资源再次可用。

例如,如果Grain负责数据库保存操作,并且数据库不可用,则只需在数据库重新联机之前拒绝传入请求。 如果某项操作可以由用户自行决定是否重试(例如保存批注失败),则应允许用户通过按钮点击进行重试(可能会限制重试次数以避免网络饱和)。 具体的实现详细信息取决于应用程序,但基础策略保持不变。

策略参数

如上所述,所选的策略取决于应用程序和特定上下文。 策略通常涉及在应用程序级别决定的参数。 例如,如果没有其他进程依赖于某个作,则决定重试该作,直到完成为止,每分钟最多重试 5 次。 但是,在处理该用户的其他请求之前,可能需要成功处理用户的登录请求。 如果登录操作失败,则无法继续执行对于该用户的其他操作。

Azure 体系结构中心提供有关 云设计模式的指南,这些模式也适用于 Orleans 应用程序。

复杂示例

由于 Orleans 会自动激活和停用粒子,因此不会直接处理其生命周期。 相反,通常重点在于确保粮食状态的正确性,以及涉及多个粮食的操作如何在相互之间正确开始和完成。 了解粒子及其行为之间的依赖关系对于处理任何复杂系统中的故障至关重要。 在颗粒之间建立关系当然是可能的,而且这也是一种常见的做法。

例如,考虑一个 GameManager 谷粒启动和停止多个 Game 谷粒,并向游戏中添加 Player 谷粒。 GameManager如果在启动游戏时失败,相应的Game任务操作Start()也应该失败。 经理可以协调这一点。 内存管理在Orleans中是自动的;只需确保游戏成功启动,并且仅当管理器也成功完成其Start()相关动作时。 通过按顺序调用相关方法或并行执行这些方法,并在任何步骤失败时重置所有相关粒度的状态来实现此协调。

如果一个游戏对象稍后收到呼叫,Orleans 会自动重新激活它。 因此,如果经理需要监督游戏事务,所有与管理相关的对游戏功能的调用都应经过 GameManager。 如果需要粒子之间的协调,Orleans 不能神奇地自动解决;必须实现协调逻辑。 但是,由于不会直接处理创建或销毁粒子,因此资源管理不是问题。 此类问题不需要回答:

  • 应在何处创建监督树?
  • 应注册哪些谷物以便能够根据名称寻址?
  • 粒度 X 是否处于活动状态,因此可以向其中发送消息?

因此,游戏开始示例可以如下汇总:

  • GameManager Game要求谷物开始。
  • Game 谷物将 Player 谷物添加到其自身。
  • GamePlayer颗粒将游戏添加到自己上。
  • Game 将其状态设置为“已启动”。
  • GameManager 将游戏添加到游戏列表。

现在,如果玩家配置无法将游戏添加到自身,则不一定需要杀死所有玩家和游戏然后重新开始。 只需重置成功添加游戏的其他玩家的状态,重置 GameGameManager 状态(如果需要),然后重试操作或声明失败。 如果可以接受后期将游戏添加到玩家,请继续该过程,然后重试通过提醒或在其他游戏调用(例如游戏的 Finish() 方法)中,将游戏添加到该特定玩家。