本文分析Azure提供的两种类型的队列之间的差异和相似性:存储队列和Service Bus队列。 通过使用此信息,可以更明智地选出最适合你需求的解决方案。
简介
Azure支持两种类型的队列机制:Storage 队列和Service Bus队列。
Storage 队列是 Azure Storage 基础结构的一部分。 它们允许您存储大量消息。 您可以使用 HTTP 或 HTTPS,经过身份验证的调用,从世界任何地方访问消息。 队列消息大小最大可为 64 KB。 一个队列可以包含数百万条消息,直至达到存储帐户的总容量限值。 队列通常用于创建需要异步处理的工作积压。 有关详细信息,请参阅 什么是Azure Storage队列。
Service Bus队列是更广泛的Azure消息传送基础结构的一部分,支持队列、发布/订阅和更高级的集成模式。 它们设计为集成可能跨多个通信协议、数据约定、信任域或网络环境的应用程序或应用程序组件。 有关Service Bus队列、主题和订阅的详细信息,请参阅 Service Bus 队列、主题和订阅。
技术选择注意事项
存储队列和Service Bus队列的功能集略有不同。 可以选择其中一种或两者,具体取决于特定解决方案的需求。
在确定哪种队列技术适合给定的解决方案时,解决方案架构师和开发人员应考虑以下建议。
考虑使用存储队列
作为解决方案架构师或开发人员, 请考虑在以下情况下使用存储队列 :
- 应用程序必须在队列中存储超过 80 GB 的消息。
- 应用程序需要跟踪队列中消息的处理进度。 如果处理消息的工作线程崩溃,此功能非常有用。 另一名员工可以使用该信息,从前一名员工停止的地方继续工作。
- 您需要获取与队列相关的所有事务的服务器端日志。
请考虑使用Service Bus队列
作为解决方案架构师或开发人员,您可以在适合的情况下考虑使用 Service Bus 队列。
- 您的解决方案需要能够在不轮询队列的情况下接收消息。 通过使用 Service Bus,并使用 Service Bus 支持的基于 TCP 协议的长轮询接收操作,可以实现此目标。
- 解决方案要求队列必须遵循先入先出 (FIFO) 的传递顺序。
- 解决方案需要支持自动重复检测。
- 希望应用程序将消息作为长时间运行的并行流进行处理(使用消息的 session ID 属性,将消息与流相关联)。 在这种模式下,消费应用程序的每个节点竞争的是流数据而非消息。 当流被提供给某个消费节点时,该节点可以使用事务检查应用程序流的状态。
- 发送或接收来自队列的多个消息时,您的解决方案需要具备事务性行为和原子性。
- 应用程序处理的消息数可能超过 64 KB,但不太可能达到 256 KB 或 1 MB 的限制,具体取决于所选的 服务层(尽管Service Bus队列可以处理高达 100 MB 的消息)。
- 你需要为队列提供基于角色的访问模型,以及发送者和接收方的不同权限和权限。 有关详细信息,请参阅以下文章:
- 队列大小不会超过 80 GB。
- 希望使用基于 AMQP 1.0 标准的消息传送协议。 有关 AMQP 的详细信息,请参阅 Service Bus AMQP 概述。
- 设想最终会从基于队列的点对点通信迁移到发布-订阅消息传递模式。 此模式可以集成其他接收器(订阅者)。 每个接收方都接收发送到队列的部分或全部消息的独立副本。
- 消息传送解决方案需要支持“最多一次”和“至少一次”传递保证,而无需构建其他基础结构组件。
- 解决方案需要发布并使用消息批处理。
比较存储队列和Service Bus队列
在以下各部分中的表将队列功能作了逻辑分组。 它们让你可以一目了然地比较Azure Storage队列和Service Bus队列中可用的功能。
基础功能
本部分比较存储队列和Service Bus队列提供的一些基本队列功能。
| 比较条件 | 存储队列 | Service Bus 队列 |
|---|---|---|
| 订单保障 | 无 有关详细信息,请参阅“ 其他信息 ”部分中的第一条说明。 |
是 - 先入先出 (FIFO) (通过使用消息会话) |
| 交付保证 | 至少一次 | 至少一次(使用 PeekLock 接收模式。这是默认值) 最多一次(使用“ReceiveAndDelete”接收模式) 详细了解各种接收模式 |
| 原子操作支持 | 否 | 是 |
| 接收行为 | 非阻止 (如果没有发现新消息,则立即完成) |
使用或不使用超时阻止 (提供长轮询,或“Comet 技术”) 非阻止 (仅使用.NET托管 API) |
| 推送样式 API | 否 | 是 我们的.NET、Java、JavaScript 和 Go SDK 提供推送式 API。 |
| 接收模式 | 查看与租用 | 扫视与锁定 接收并删除 |
| 独占访问模式 | 基于租赁 | 基于锁的 |
| 租赁/锁定持续时间 | 30 秒(默认值) 7 天(最大值) (可使用 UpdateMessage API 续订或释放消息租赁。) |
30 秒(默认值) 您可以手动续订消息锁,每次保持相同的锁定持续时间,或者使用自动锁定续订功能,由客户端为您管理锁定续订。 |
| 租赁/锁精度 | 消息级别 每个消息可以有不同的超时值,然后可以使用 UpdateMessage API 根据需要更新消息。 |
队列级别 (每个队列都具有一个适用于其中所有消息的锁定精度,但可以如上一行所述续订该锁) |
| 成批接收 | 是 (在检索消息时显式指定消息计数,最多可达 32 条消息) |
是 (隐式启用预提取属性或使用事务显式启用) |
| 成批发送 | 否 | 是 (通过使用事务或客户端批处理) |
其他信息
- 存储队列中的消息通常先进先出,但有时可能会出现顺序错乱。 例如,当消息的可见性超时持续时间过期时,客户端应用程序在处理消息时崩溃。 当可见性超时到期时,消息会再次变成在队列上可见,让另一个工作进程能够取消它的排队。 这时,新变得可见的消息可能会被放置在队列中,以便再次出队。
- Service Bus 队列中 FIFO 模式的保证需要使用消息会话。 如果应用程序在处理 在“速览”和“锁定 ”模式下收到的消息时崩溃,则当队列接收方下次接受消息传送会话时,它会在会话的锁定持续时间到期后以失败的消息开始。
- 存储队列旨在用于支持标准队列方案,例如:
- 解耦应用程序组件,提高可伸缩性和故障容错能力
- 负载分级
- 构建过程工作流。
- 通过使用会话状态来存储应用程序与处理会话消息序列进度相关的状态,并使用围绕处理接收消息和更新会话状态的事务,您可以避免在Service Bus会话上下文中消息处理的不一致问题。 这种一致性功能有时在其他供应商的产品中标记为“只需处理一次”。 任何事务失败都会导致消息被重新传送,这就是为什么术语本身不完全准确。
- 存储队列可在多个队列、表和 Blob 上提供统一和一致的编程模型 - 对于开发人员和运营团队都是如此。
- Service Bus队列在单个队列的上下文中提供对该队列中的本地事务的支持。
- Service Bus支持的Receive and Delete模式提供了减少消息操作计数(及相关成本)以降低传递保证作为交换的功能。
- 存储队列提供租约功能,允许消息的租约延长。 此功能允许工作进程对消息保持短的租赁时间。 如果一个工作线程崩溃,另一个工作线程可以快速处理这条消息。 此外,如果工作人员需要处理消息的时间比当前租赁时间更长,则可以延长该消息的租赁时间。
- 存储队列提供了可见性超时,可针对消息入队或出队进行设置。 此外,可以在运行时使用不同租赁值更新消息,并且可以跨同一队列的消息更新不同值。 锁定超时是在Service Bus的队列元数据中定义的。 不过,你可以手动为消息锁续期,以匹配预定义的锁定时长,或者使用由客户端管理的自动锁定续订功能。
- Service Bus 队列中阻塞接收操作的最大超时时间为 24 天。 但是,基于 REST 的最大超时值为 55 秒。
- Service Bus提供的客户端批处理使队列客户端能够将多个消息批处理到单个发送作中。 批处理仅适用于异步发送操作。
- 有些特性,例如存储队列的 200 TB 上限(虚拟化帐户时更多)和无限制队列,使得它成为 SaaS 提供商的理想平台。
- 存储队列提供灵活且性能良好的委托访问控制机制。
高级功能
本部分比较存储队列和Service Bus队列提供的高级功能。
| 比较条件 | 存储队列 | Service Bus 队列 |
|---|---|---|
| 预定的送货 | 是 | 是 |
| 自动死信 | 否 | 是 |
| 增加队列存活时间值 | 是 (通过就地更新可见性超时) |
是 (通过一个专用 API 功能提供) |
| 有害消息支持 | 是 | 是 |
| 就地更新 | 是 | 是 |
| 服务器端事务日志 | 是 | 否 |
| 存储度量值 | 是 分钟指标提供有关可用性、TPS、API 调用计数、错误计数等的实时指标。 它们都是实时的,每分钟聚合一次,并在几分钟内报告生产环境中刚刚发生的事件。 有关详细信息,请参阅 About Storage Analytics 指标。 |
是 有关Azure Service Bus支持的指标的信息,请参阅 Message 指标。 |
| 状态管理 | 否 | 是(Active、Disabled、SendDisabled、ReceiveDisabled。有关这些状态的详细信息,请参阅队列状态) |
| 消息自动转发 | 否 | 是 |
| 清除队列函数 | 是 | 是的 |
| 消息组 | 否 | 是 (通过使用消息会话) |
| 每个消息组的应用程序状态 | 否 | 是 |
| 重复检测 | 否 | 是 (可在发送端配置) |
| 浏览消息组 | 否 | 是 |
| 按 ID 提取消息会话 | 否 | 是 |
其他信息
- 两种队列技术都允许将消息安排在以后传送。
- 利用队列自动转发功能,数千个队列可将它们的消息自动转发至单个队列,而接收应用程序将使用来自该队列的消息。 可以使用此机制来实现安全性和控制流,并且隔离每个消息发布者的存储。
- 存储队列为更新消息内容提供支持。 可以使用此功能将状态信息和递增进度更新持久保留到消息中,以便能够从上一个已知的检查点处理该消息,而不是从头开始。 通过使用 Service Bus 队列,可以使用消息会话来实现相同的场景。 有关详细信息,请参阅消息会话状态。
- Service Bus队列支持 ad lettering。 若要隔离满足以下条件的消息,这很有用:
- 接收应用程序无法成功处理消息。
- 消息因生存时间 (TTL) 属性过期而无法到达目的地。 TTL 值指定消息在队列中保留的时间。 使用 Service Bus 时,当 TTL 时限到期,消息将被传送至名为 $DeadLetterQueue 的特殊队列中。
- 为了在存储队列中查找“病毒”消息,在将某个消息取消排队时,应用程序将检查该消息的 DequeueCount 属性。 如果 DequeueCount 大于给定的阈值,应用程序会将消息移到应用程序定义的“死信”队列。
- 利用存储队列,可以获取针对该队列执行的所有事务的详细日志以及聚合指标。 这两个选项可用于调试和了解应用程序如何使用存储队列。 它们还用于对应用程序进行性能优化并降低使用队列的成本。
- Service Bus 支持的 会话功能可使属于逻辑组的消息与接收者关联。 它会在消息及其各自的接收方之间创建类似于会话的关联。 可以通过在消息上设置会话 ID 属性,在 Service Bus 中启用此高级功能。 然后,接收者可以侦听特定会话 ID,并接收共享特定会话标识符的消息。
- Service Bus队列的重复检测功能根据消息 ID 属性的值自动删除发送到队列或主题的重复消息。
容量和配额
本部分从可能应用的容量和配额的角度比较存储队列和Service Bus队列。
| 比较条件 | 存储队列 | Service Bus 队列 |
|---|---|---|
| 最大队列大小 | 5 PiB (限制为单个存储帐户容量) |
1 GB 到 80 GB (具有分区的高级或标准层) |
| 最大消息大小 | 64 KB (使用 Base64 编码时为 48 KB) Azure通过将队列与 Blob 结合支持大型消息——此时,单个项目最多可以入列200 GB。 |
256 KB、1 MB 或 100 MB (包含标头和正文,最大标头大小:64 KB)。 取决于服务层级。 |
| 最大消息 TTL | 无限(API 版本 2017-07-27 或更高版本) | TimeSpan.MaxValue(时间跨度的最大值) |
| 最大队列数 | 无限制 | 10,000(标准层) 1000 /消息传送单元(高级层) (按服务命名空间) |
| 并发客户端的最大数目 | 无限制 | 5,000 |
其他信息
- Service Bus强制实施队列大小限制。 创建队列时指定最大队列大小。 大小可以介于 1 GB 和 80 GB 之间。 如果队列的大小达到此限制,Service Bus拒绝其他传入消息,调用方收到异常。 有关Service Bus中的配额的详细信息,请参阅 Service Bus 配额。
- 在标准消息传送层中,可以在 1(默认)、2、3、4 或 5 GB 大小中创建Service Bus队列和主题。 在标准层中启用分区时,Service Bus创建实体的 16 个副本(16 个分区),每个副本的大小都相同。 因此,如果你创建了一个大小为 5 GB 的队列,共有 16 个分区,最大队列大小为 (5 * 16) = 80 GB。 可以在 Azure 门户中查看分区队列或主题的最大大小。
- 在存储队列中,如果消息的内容不属于 XML 安全内容,则必须对其进行 Base64 编码。 如果使用 Base64编码此消息,则用户负载可高达 48 KB,而不是 64 KB。
- 使用Service Bus队列时,存储在队列中的每个消息由两个部分组成:标头和正文。 消息的总大小不能超过服务层级支持的最大消息大小。
- 当客户端通过 TCP 协议与Service Bus队列通信时,与单个Service Bus队列的最大并发连接数限制为 100。 此数值在发送方和接收方之间共享。 如果达到此配额,则其他连接请求将被拒绝,调用代码将遇到异常。 使用基于 REST 的 API 连接到队列的客户端不受此限制。
- 若要将 Service Bus 标准层扩展到超过 10,000 个队列或将 Service Bus 高级层扩展到超过 1000 个队列/消息传送单元,还可以使用 Azure 门户 创建其他命名空间。
管理和操作
本部分比较存储队列和Service Bus队列提供的管理功能。
| 比较条件 | 存储队列 | Service Bus 队列 |
|---|---|---|
| 管理协议 | HTTP/HTTPS 上的 REST | HTTPS 上的 REST |
| 运行时协议 | HTTP/HTTPS 上的 REST | HTTPS 上的 REST AMQP 1.0 标准(具有 TLS 的 TCP) |
| .NET API | 是 (.NET存储客户端 API) |
是 (.NET Service Bus API) |
| 原生 C++ | 是 | 是 |
| Java API | 是 | 是 |
| PHP API | 是 | 是 |
| Node.js API | 是 | 是 |
| 对任意元数据的支持 | 是 | 否 |
| 队列命名规则 | 长度最多为 63 个字符 (队列名称中的字母必须小写。) |
长度最多为 260 个字符 (队列路径和名称不区分大小写。) |
| 获取队列长度函数 | 是 (在消息超出 TTL 但未删除的情况下的近似值。) |
是 (精确时间点值。) |
| Peek 函数 | 是 | 是 |
其他信息
- 存储队列支持任意属性,这些属性可以作为名称/值对应用于队列描述。
- 这两种队列技术都提供了在不锁定消息的情况下速览消息的功能,这在实现队列资源管理器或浏览器工具时非常有用。
- 与通过 HTTP 的 REST 相比,Service Bus .NET中转消息传送 API 使用全双工 TCP 连接来提高性能,并支持 AMQP 1.0 标准协议。
- 存储队列名称长度可以为 3-63 个字符,可以包含小写字母、数字和连字符。 有关详细信息,请参阅 命名队列和元数据。
- Service Bus 队列名称最多可以包含 260 个字符,其命名规则较少限制。 Service Bus队列名称可以包含字母、数字、句点、连字符和下划线。
身份验证和授权
本部分讨论存储队列和Service Bus队列支持的身份验证和授权功能。
| 比较条件 | 存储队列 | Service Bus 队列 |
|---|---|---|
| 身份验证 | 对称密钥和基于角色的访问控制 (RBAC) | 对称密钥和基于角色的访问控制 (RBAC) |
| 身份提供商联合 | 是 | 是 |
其他信息
- 针对任一队列技术的每个请求都必须进行身份验证。 不支持使用匿名访问的公共队列。
- 通过使用共享访问签名(SAS)身份验证,可以在队列上创建共享访问授权规则,该规则可为用户提供只读、只读或完全访问权限。 有关详细信息,请参阅 Azure Storage - SAS 身份验证和 Azure Service Bus - SAS 身份验证。
- 这两个队列都支持使用由 Microsoft 提供的 Microsoft Entra ID 来授权访问。 使用Microsoft Entra ID返回的 OAuth 2.0 令牌授权用户或应用程序提供优于共享访问签名(SAS)的安全性和易用性。 使用Microsoft Entra ID时,无需将令牌存储在代码中,并面临潜在的安全漏洞风险。 有关详细信息,请参阅 Azure Storage - Microsoft Entra身份验证和 Azure Service Bus - Microsoft Entra身份验证。
结束语
通过了解这两种技术,可以就使用哪种队列技术以及何时使用做出更明智的决策。 决定何时使用存储队列或Service Bus队列取决于许多因素。 这些因素很大程度上取决于应用程序及其体系结构的独特需要。
出于如下原因,你可能更愿意选择存储队列:
- 应用程序已使用 Azure 的核心功能
- 需要在服务之间进行基本的通信和消息传送
- 你需要大小超过 80 GB 的队列
Service Bus 队列提供了许多高级功能,例如以下这些。 因此,它们可能是首选,如果您要构建混合应用程序或应用程序需要这些功能。
后续步骤
以下文章提供了有关使用存储队列或Service Bus队列的更多指导和信息。
- 从Service Bus队列开始
- 如何使用队列存储服务
- 使用 Service Bus 中转消息传递提升性能的最佳实践