扩展处理应用程序
若要缩放事件处理应用程序,可以运行应用程序的多个实例,并让这些实例自行进行负载均衡。 在旧版本中,EventProcessorHost 允许在接收检查点事件时,在程序的多个实例与这些事件之间进行负载均衡。 在新版本(5.0 或以上)中,EventProcessorClient(.NET 和 Java)或 EventHubConsumerClient(Python 和 JavaScript)允许执行相同的操作。
注意
缩放事件中心的关键在于分区使用者的思路。 与竞争性使用者模式相比,分区使用者模式能够通过消除争用瓶颈和简化端到端的并行度,来实现较高的缩放度。
示例方案
作为示例方案,假设有一个家庭保安公司需要监控 100,000 个家庭。 该公司每隔一分钟就要从每个家庭中安装的各种传感器(例如运动检测器、门/窗打开传感器、玻璃破碎检测器等)获取数据。 该公司为居民提供一个网站,让他们近乎实时地监控家庭中的活动。
每个传感器将数据推送到事件中心。 在事件中心配置了 16 个分区。 在使用端,你需要一种机制,该机制可以读取事件、合并事件,并将聚合转储到存储 blob,该 blob 随后会被投影到一个用户友好的网页。
在分布式环境中设计时使用者时,方案必须处理以下要求:
- 缩放: 创建多个使用者,每个使用者获取若干事件中心分区的读取所有权。
- 负载均衡: 动态增加或减少使用者。 例如,将新的传感器类型(例如一氧化碳检测器)添加到每个家庭后,事件数会增多。 在这种情况下,操作员(人类)会增加使用者实例的数目。 然后,使用者池可以重新均衡它们拥有的分区数,以便与新添加的使用者分担负载。
- 故障时无缝恢复: 如果某个使用者(使用者 A)发生故障(例如,托管使用者的虚拟机突然崩溃),其他使用者能够拾取使用者 A 拥有的分区并继续。 此外,称作“检查点”或“偏移量”的延续点应该位于使用者 A 发生故障时的确切位置,或者略微在该位置的前面。
- 使用事件: 尽管前面三个要点能够应对使用者的管理,但还必须提供代码来使用事件并对其执行有用的操作。 例如,聚合事件并将其上传到 Blob 存储。
事件处理器或使用者客户端
无需生成自己的解决方案即可满足这些要求。 Azure 事件中心 SDK 提供此功能。 在 .NET 或 Java SDK 中,使用事件处理程序客户端 (EventProcessorClient
),在 Python 和 JavaScript SDK 中,使用 EventHubConsumerClient
。
对于大多数生产情形,建议使用事件处理器客户端来读取和处理事件。 在给定事件中心的使用者组上下文中,事件处理器客户端能够以协作方式工作。 当实例可用或不可用于组时,客户端会自动管理工作的分配和均衡。
分区所有权跟踪
事件处理器实例通常拥有并处理来自一个或多个分区的事件。 分区所有权在与事件中心和使用者组的组合相关联的所有活动事件处理器实例之间均匀分配。
每个事件处理器具有唯一的标识符,通过在检查点存储中添加或更新条目来声明分区的所有权。 所有事件处理器实例定期与此存储通信,以更新自身的处理状态以及了解其他活动实例。 然后,使用此数据在活动处理器之间均衡负载。
接收消息
创建事件处理器时,需要指定用于处理事件和错误的函数。 每次调用处理事件的函数都会从特定的分区传送单个事件。 你需要负责处理此事件。 若要确保使用者将每条消息至少处理一次,需要编写自己的包含重试逻辑的代码。 但请注意有害消息。
我们建议以相对较快的速度执行操作。 也就是说,尽量减少处理量。 如果需要写入存储并执行某种路由,最好是使用两个使用者组和两个事件处理器。
检查点
检查点是事件处理器标记或提交上次在分区中成功处理的事件位置的过程。 标记检查点通常在处理事件的函数内部执行,并在使用者组中按分区进行。
如果事件处理器从分区断开连接,另一个实例可以在检查点位置继续处理该分区,该检查点是以前由该使用者组中该分区的最后一个处理器提交的。 当处理器建立连接时,它会将此偏移量传递给事件中心,以指定要从其开始读取数据的位置。 这样,你便可以使用检查点将事件标记为已由下游应用程序“完成”,并在事件处理器出现故障时提供复原能力。 可通过在此检查点过程中指定较低偏移量,返回到较旧的数据。
线程安全性和处理程序实例
默认情况下,将会针对给定分区按顺序调用处理事件的函数。 当事件泵继续在后台的其他线程上运行时,来自同一分区的后续事件和对该函数的调用将在后台排队。 可以同时处理来自不同分区的事件,但必须同步跨分区访问的任何共享状态。