预取 Azure 服务总线消息

预提取功能用于在后台提取消息到本地预提取缓冲区,直到达到预提取计数上限。 消息由缓冲区提供。 与此同时,缓冲区会腾出空间,接收方会在后台预取更多消息。

若要启用预提取功能,请将队列或订阅客户端的预提取计数设置为大于零的数字。 将该值设为零可关闭预提取。 如果该功能关闭后预提取缓冲区中还有信息,则应用程序将首先从缓冲区接收这些消息,然后才会转向服务。

ServiceBusReceiverOptionsServiceBusProcessorOptions 对象上设置预提取计数属性。

注意

JavaScript 和 Go SDK 不支持预取功能。

尽管消息在预提取缓存区中提供,但后续接收的任何调用均可立即从缓冲区完成。 空间可用时,系统将在后台对缓冲区进行补充。 如果没有消息用于传送,接收操作将清空缓存区,并按预期进行等待或阻止。

预取计数是接收端的设置,而传递给接收调用的消息计数是单个操作的参数。 预取计数决定接收器在你的调用之前预先持有多少条消息,而每次调用计数则限定单次调用可返回的消息数量。 当预取关闭时,接收通话会直接向服务请求每次通话计数,这也是为什么两者看起来像是同一设置。 关于如何将两者同时选择,请参见 预取和接收消息同步

请务必注意, PrefetchCount 定义随时可存在于本地缓冲区中的最大消息数。 这也意味着,它充当可并发处理的消息数的严格上限。 如果 MaxConcurrentCalls 设置为高于 PrefetchCount,处理器将无法利用所有并发消息处理程序,因为只有最多 PrefetchCount 消息可以一次在内存中处于活动状态。

为什么 Prefetch 不是默认选项?

预取可通过在应用程序请求消息之前就使消息可供本地获取,来加快消息传递流程。 这种吞吐量提升是应用程序作者不得不明确作出的某种权衡的结果。

使用“接收-删除”模式时,所有进入预取缓冲区的消息在队列中将不再可用。 消息仅保留在内存预提取缓冲区中,直到系统将其接收到应用程序中。 如果在应用程序接收到消息前终止应用程序,这些消息将丢失,且不可恢复。

在使用 peek lock 接收模式时,提取到预取缓冲区中的消息会以锁定状态被放入该缓冲区。 锁定计时器自消息预提取到缓冲区起开始计时。 如果预提取缓冲区很大,并且处理耗时过长,导致消息在预提取缓冲区中停留期间,甚至在应用程序处理消息期间其锁就已过期,那么应用程序在处理时可能会遇到一些令人困惑的情况。 应用程序可能会获取到锁已过期或即将过期的消息。 如有收到,应用程序可能会处理该消息,但随后发现其因锁定到期而无法完成处理。 应用程序可查看 LockedUntilUtc 属性,但请记住,代理时钟和本地计算机时钟之间存在时钟偏差。

如果锁在预提取缓冲区中悄然过期,则该消息会被视为已放弃,并再次可从队列中检索到。 然后,消息会再次提取到预提取缓冲区中,并置于末端。如果在消息过期期间,预提取缓冲区通常无法使用,则将导致重复预提取消息,但始终无法将其以可用(有效锁定)状态有效送达,并最终在超出最大传送数后移动到死信队列。

如果应用程序显式放弃消息,该消息可能再次可用于从队列中检索。 启用预取功能后,该消息会再次被提取到预取缓冲区中,并放置在末尾。 由于来自预提取缓冲区的消息按先入先出 (FIFO) 顺序排空,应用程序可能会无序地接收消息。 例如,应用程序可能会先从缓冲区收到一条 ID 为 2 的消息,然后再收到一条 ID 为 1 的消息(该消息先前已被放弃)。

如果消息处理需要高度可靠性,且处理需要花费大量精力和时间,则建议谨慎使用或者避免使用预提取功能。 如果需要较高吞吐量且消息处理通常比较便宜,则预提取会产生显著的吞吐量优势。

需要均衡对队列或订阅配置的最大预提取数和锁定持续时间,以便锁定超时至少超出最大预提取缓存区大小外加一条消息的累积预期消息处理时间。 同时,锁定持续时间不应太长,以免消息在锁定时超过其最大生存时间,因为这意味着,如果它们在预提取时无法补全,它们就会被删除。

注意

2026 年 9 月 30 日,我们将停用 Azure 服务总线 SDK 库 WindowsAzure.ServiceBus、Microsoft.Azure.ServiceBus 和 com.microsoft.azure.servicebus,这些库不符合 Azure SDK 准则。 我们还将结束对 SBMP 协议的支持,因此在 2026 年 9 月 30 日之后,你将无法再使用此协议。 请在该日期之前迁移到最新的 Azure SDK 库,新库提供了关键安全更新和改进功能。

尽管旧库在 2026 年 9 月 30 日之后仍可使用,但它们将不再获得 Azure 的官方支持和更新。 有关详细信息,请参阅支持停用公告