了解如何使用 Azure Functions 和 Azure 事件中心触发器构建可靠的无服务器解决方案。 本文介绍检查点、错误处理和实现断路器模式的最佳做法,以确保不会丢失任何事件,并且事件驱动的应用程序保持稳定且可复原。
假设系统以每秒 100 个事件的常量速率发送事件。 在此速率下,很快就可以由多个并行实例每秒处理传入的 100 个事件。
但是,请考虑以下使用事件流的挑战:
- 事件发布者发送已损坏的事件。
- 函数代码遇到未经处理的异常。
- 下游系统脱机并阻止事件处理。
与在处理过程中锁定消息的 Azure 队列存储触发器不同,Azure 事件中心从流中的单个点读取每个分区。 此读取行为更像是视频播放器,可提供高吞吐量、多个使用者组和重播能力所需的优势。 事件可以从检查点向前或向后读取,但必须移动指针以处理新事件。 有关详细信息,请参阅事件中心文档中的 检查点 。
当流中出现错误且您选择不移动指针时,将阻止对后续事件的处理。 换句话说,如果您停止游标以处理事件处理中的一个问题,未处理的事件将开始堆积。
无论成功还是失败,函数始终推进流的指针,从而避免死锁。 由于指针不断向前推进,函数需要适当地处理故障。
Azure Functions 通过循环执行以下步骤,从事件中心消费事件:
- 为事件中心的每个分区在 Azure 存储中创建并保留一个指针。
- 默认情况下,新事件以批量方式接收,然后主机会尝试触发一个函数来处理这批事件。
- 当函数完成执行(不例外)时,指针是高级的,检查点将保存到默认主机存储帐户。
- 如果条件阻止函数执行完成,主机无法推进指针。 当指针无法前进时,后续执行将重新处理相同的事件。
此行为揭示了一些要点:
未经处理的异常可能会导致事件丢失。
引发异常的函数执行将继续推进指针位置。 设置 重试策略 或其他重试逻辑会延迟指针前进,直到整个重试完成。
函数保证 至少传递一次 :
你的代码和依赖系统可能需要考虑到同一事件可以两次处理的事实。 有关详细信息,请参阅 为相同的输入设计 Azure 函数。
虽然所有函数代码都应在最高级别的代码中包含 try/catch 块 ,但对于使用事件中心事件的函数,拥有 catch
块更为重要。 这样,当引发异常时,catch 代码块会在指针前进之前处理该错误。
由于云中的许多异常是暂时性的,因此错误处理的第一步始终是重试作。 可以应用内置重试策略或定义自己的重试逻辑。
Functions 为事件中心提供内置的重试策略。 使用重试策略时,只需引发新的异常,主机会尝试根据定义的策略再次处理事件。 此重试行为需要 5.x 或更高版本的事件中心扩展。 有关详细信息,请参阅重试策略。
还可以在函数本身中定义自己的重试逻辑。 例如,可以实施遵循以下规则演示的工作流的策略:
- 尝试处理事件三次(可能重试之间有延迟)。
- 如果所有重试的最终结果为失败,请将事件添加到队列中,以便处理可以在流中继续。
- 随后会处理损坏或未处理的事件。
备注
Polly 是 C# 应用程序的复原和暂时性故障处理库的示例。
可能会出现一些问题,而不会引发异常。 例如,请考虑请求超时或运行函数的实例崩溃的情况。 如果一个函数在未发生异常的情况下无法完成,则偏移指针永远不会前进。 如果指针未推进,则在执行失败后运行的任何实例将会继续读取相同的事件。 这种情况提供至少一次的保证。
保证每个事件至少处理一次意味着可以多次处理某些事件。 函数应用需要注意这种可能性,并且必须围绕 幂等性原则构建。
你的应用在事件处理中可能能够接受地处理一些错误。 但是,还应准备好处理永久性故障状态,这可能是下游处理失败导致的。 在此类故障状态(例如下游数据存储处于脱机状态)中,函数应停止对事件触发,直到系统达到正常状态。
实现 断路器 模式时,应用可以有效地暂停事件处理,然后在解决问题后稍后恢复它。
在事件流进程中实现断路器需要两个组件:
- 在所有实例之间共享状态,用于跟踪和监视线路的运行状况。
- 一个可以管理线路状态的主要进程,可以是
open
或closed
。
实现细节可能会有所不同,但为了在各个实例之间共享状态,你需要一个存储机制。 可以在 Azure 存储、Redis 缓存或任何其他可由函数应用实例访问的持久服务中存储状态。
Durable Functions 和 Azure 逻辑应用都提供基础结构来管理工作流和线路状态。 本文介绍如何使用逻辑应用暂停和重启函数执行,从而提供实现断路器模式所需的控制。
当多个实例同时处理事件时,需要保留的共享外部状态来监视线路的运行状况。 然后,可以根据指示失败状态的规则监视此持久状态,例如:
在所有实例的 30 秒内发生超过 100 个事件故障时,断开电路以停止对新的事件进行触发。
此监视逻辑的实现详细信息因特定应用需求而异,但一般情况下,必须创建一个系统:
- 将失败记录到持久存储。
- 在记录新失败时检查滚动计数,以确定是否满足事件失败阈值。
- 满足此阈值时,发出一个事件,告知系统中断线路。
Azure 逻辑应用附带了用于不同服务、功能和有状态业务流程的内置连接器,这是管理线路状态的自然选择。 检测线路何时必须中断后,可以生成逻辑应用来实现此工作流:
- 触发停止函数处理的事件网格工作流。
- 发送包含重启工作流的选项的通知电子邮件。
若要了解如何使用应用设置禁用和重新启用特定函数,请参阅 如何禁用 Azure Functions 中的函数。
电子邮件收件人可以调查线路的运行状况,并在适当情况下通过通知电子邮件中的链接重启线路。 当工作流重启函数时,将从最后一个事件中心检查点处理事件。
使用此方法时,不会丢失任何事件、按顺序处理事件,并且可以根据需要中断线路。