通过


你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

分区队列和主题

Azure 服务总线使用多个消息代理来处理消息和多个消息存储来存储消息。 传统的队列或主题由单个消息中转站进行处理并存储在一个消息存储中。 服务总线分区使队列和主题等消息实体能够在多个消息代理和消息存储之间进行分区。 分区意味着分区实体的总吞吐量不再受单个消息中转站或消息存储的性能所限制。 此外,消息存储的临时中断不会使分区队列或主题不可用。 分区队列和主题可以包含服务总线的所有高级功能,例如支持事务和会话。

注意

在分区方面,基本/标准和高级 SKU 之间存在一些差异。

  • 分区在为基本或标准 SKU 中的所有队列和主题创建实体时可用。 命名空间可同时具有已分区实体和非分区实体。
  • 分区在为高级消息传送 SKU 创建命名空间时可用,该命名空间中的所有队列和主题都已分区。 高级命名空间中以前迁移的所有分区实体将继续按预期工作。
  • 在基本或标准 SKU 中启用分区时,始终创建 16 个分区。
  • 在高级 SKU 中启用分区时,可以在创建命名空间期间指定分区数。

不能更改任何现有命名空间、队列或主题上的分区选项。 只能在创建实体时设置该选项。

工作原理

每个分区队列或主题由多个分区构成。 每个分区存储在不同的消息传送存储中并由不同的消息中转站进行处理。 将消息发送到分区队列或主题时,服务总线会将消息分配给其中一个分区。 服务总线随机选择分区或使用发送方指定的分区键。

当客户端想要从一个分区队列,或者从一个分区主题的订阅接收消息时,服务总线会查询所有分区以获取消息。 它将从任何消息存储区获取的第一条消息返回到接收方。 服务总线缓存其他消息并在收到其他接收请求时将它们返回。 接收客户端不知道分区。 分区队列或主题(例如读取、完成、延迟、死信、预提取)的面向客户端的行为与常规实体的行为相同。

在未分区实体上进行的速览操作始终返回最旧的消息,但在已分区实体上进行操作时情况有所不同。 它只返回其消息中转站首先响应的分区之一中的最旧消息。 不保证返回的消息是所有分区中最旧的消息。

向分区队列或主题发送一条消息,或从分区队列或主题接收消息时无需额外付费。

注意

速览操作根据消息的序列号返回分区中最旧的消息。 对于分区实体,序列号相对于分区。 有关详细信息,请参阅消息序列化和时间戳

使用分区键

将消息排入分区队列或主题时,服务总线会检查是否存在分区键。 如果找到,它会选择基于该键的分区。 如果找不到分区键,它会选择基于内部算法的分区。

使用分区键

某些应用场景(例如会话或事务)要求将消息存储在特定的分区中。 所有这些应用场景都需要使用分区键。 服务总线将使用相同的分区键的所有消息分配给同一分区。 如果该分区暂时不可用,服务总线返回一个错误。

根据应用场景,将不同的消息属性用作分区键:

SessionId:如果消息设置了会话 ID 属性,服务总线会将其用作分区键。 这样,同一消息中转站处理属于同一会话的所有消息。 通过使用会话,服务总线保证消息排序以及会话状态的一致性。

PartitionKey:如果消息具有分区键属性,但没有设置会话 ID 属性,服务总线将使用分区键属性值作为分区键。 如果消息同时设置了会话 ID 和分区键属性,则这两个属性必须相同。 如果分区键属性设置为与会话 ID 属性不同的值,则服务总线返回无效操作异常。 如果发送方发送不顾及会话的事务消息,请使用分区键属性。 分区键可确保相同的消息代理处理事务中发送的所有消息。

MessageId:如果使用 重复检测功能 创建队列或主题,并且未设置会话 ID 或分区键属性,则消息 ID 属性值将用作分区键。 (如果发送应用程序没有,Microsoft客户端库会自动分配消息 ID。在这种情况下,同一消息中转站处理同一消息的所有副本。 此 ID 使服务总线能够检测并消除重复的消息。 如果未启用重复检测功能,则服务总线不会将消息 ID 属性视为分区键。

不使用分区键

如果未指定分区键,服务总线会以循环轮转方式将消息分配到分区队列或主题的所有分区。 如果所选的分区不可用,服务总线会将消息分配给不同的分区。 这样一来,尽管消息传送存储暂时不可用,发送操作仍可成功。 但是,您无法获得分区键所提供的排序保证。

有关可用性(没有分区键)和一致性(使用分区键)之间的权衡的更深入讨论,请参阅事件中心中的可用性和一致性。 除了分区 ID 不向用户公开这一点外,此信息同样适用于分区服务总线实体。

要给服务总线足够的时间将消息排入不同分区的队列中,客户端指定的发送消息的超时值必须大于 15 秒。 建议使用默认值 60 秒。

分区键会将消息“固定”到特定分区。 如果保存此分区的消息存储不可用,则服务总线会返回一个错误。 如果没有分区键,服务总线可以选择其他分区且操作会成功。 因此,除非需要分区键,否则不要提供分区键。

高级主题

对分区实体使用事务

作为事务的一部分发送的消息必须指定分区键。 键可以是以下属性之一:会话 ID、分区键或消息 ID。 作为同一事务的一部分发送的所有消息都必须指定相同的分区键。 如果尝试在事务中发送消息时未指定分区键,服务总线将返回无效操作异常。 如果尝试在同一事务中发送多条具有不同分区键的消息,服务总线会返回无效操作异常。 例如:

CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
    ServiceBusMessage msg = new ServiceBusMessage("This is a message");
    msg.PartitionKey = "myPartitionKey";
    await sender.SendMessageAsync(msg); 
    ts.Complete();
}
committableTransaction.Commit();

如果设置用作分区键的任何属性,服务总线会将消息固定到特定分区。 无论是否使用事务,都会出现此行为。 如果不需要,请不要指定分区键。

将会话中的事务与已分区的实体配合使用

若要将事务消息发送到会话感知主题或队列,请设置消息的会话 ID 属性。 如果指定分区键属性,则它必须与会话 ID 属性相同。 如果它们不同,Service Bus会返回操作无效异常。

与常规(非分区)队列或主题不同,不能使用单个事务将多个消息发送到不同的会话。 如果尝试此操作,Service Bus 将返回一个无效的操作异常。 例如:

CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
    ServiceBusMessage msg = new ServiceBusMessage("This is a message");
    msg.SessionId = "mySession";
    await sender.SendMessageAsync(msg); 
    ts.Complete();
}
committableTransaction.Commit();

使用分区单元自动消息转发

服务总线支持消息自动转发,可以从分区实体发送、向分区实体接收或在分区实体之间进行转发。 创建或更新队列和订阅时,可以启用此功能。 有关详细信息,请参阅启用消息转发。 如果消息指定分区键(会话 ID、分区键或消息 ID),则分区键用于目标实体。

注意事项和指南

  • 高一致性功能:如果实体使用会话、重复检测或对分区键的显式控制等功能,则消息传送作始终路由到特定分区。 如果任何分区遇到过高的流量,或基础存储处于不正常状态,这些操作将失败,可用性会降低。 总的来说,一致性仍远高于非分区实体。 只有一部分流量遇到问题,而不是所有流量。 有关详细信息,请参阅此处对可用性和一致性的讨论
  • 管理:必须对实体的所有分区执行创建、更新及删除等操作。 如果任何分区处于不正常状态,可能会导致这些操作失败。 对于 Get 操作,必须汇总来自所有分区的信息,例如消息数量。 如果任何分区处于不正常状态,则实体可用性状态会报告为受限制。
  • 少量消息的情况:对于这类情况,尤其是使用 HTTP 协议时,可能必须执行多次接收操作,才能获取所有消息。 对于接收请求,前端对所有分区执行接收,并缓存它接收的所有响应。 同一连接上的后续接收请求受益于此缓存和接收延迟较低。 不过,如果你有多个连接或使用 HTTP,则针对每个请求建立新的连接。 因此,不能保证它位于同一节点上。 如果现有的所有消息均被锁定,而且在另一个前端中缓存,则接收操作返回 null。 消息最后会到期,可以再次接收它们。 建议使用 HTTP 保持连接。 在低容量场景中使用分区时,接收操作所用时间可能比预期的长。 因此,在这些方案中不要使用分区。 删除任何现有的分区实体,并在禁用分区的情况下重新创建它们,以提高性能。
  • 浏览/速览消息:速览操作不会始终返回要求的消息数。 这两个常见原因解释了此行为。 其中一个原因是消息集合的汇总大小超过大小上限。 另一个原因是,在分区队列或主题中,分区可能没有足够的消息来返回请求的消息数。 通常,如果应用程序想要查看或浏览特定数量的消息,则应重复调用速览作,直到它获取该数目的消息,或者没有更多消息要查看。 有关详细信息(包括代码示例),请参阅消息浏览

分区实体限制

当前,服务总线对分区队列和主题施加以下限制:

  • 分区队列和主题不支持在单个事务中发送属于不同会话的消息。
  • 服务总线目前允许每个命名空间最多 100 个分区队列或主题,适用于基本层和标准层。 在每个命名空间中,每个分区队列或主题的实体配额不会超过 10,000 个。

后续步骤

可使用 Azure 门户、PowerShell、CLI、资源管理器模板、.NET、Java、Python 和 JavaScript 来启用分区。 有关详细信息,请参阅启用分区(基本/标准)

若要了解高级消息队列协议 (AMQP) 1.0 消息传送规范的核心概念,请参阅 AMQP 1.0 协议指南