您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

分区的队列和主题Partitioned queues and topics

Azure 服务总线使用多个消息中转站来处理消息,并用多个消息传送存储来存储消息。Azure Service Bus employs multiple message brokers to process messages and multiple messaging stores to store messages. 传统的队列或主题由单个消息中转站进行处理并存储在一个消息存储中。A conventional queue or topic is handled by a single message broker and stored in one messaging store. 服务总线分区允许跨多个消息中转站和消息存储对队列和主题或消息实体进行分区。Service Bus partitions enable queues and topics, or messaging entities, to be partitioned across multiple message brokers and messaging stores. 这意味着分区实体的总吞吐量不再受单个消息中转站或消息存储的性能所限制。This means that the overall throughput of a partitioned entity is no longer limited by the performance of a single message broker or messaging store. 此外,消息传送存储的临时中断不会导致分区的队列或主题不可用。In addition, a temporary outage of a messaging store does not render a partitioned queue or topic unavailable. 分区的队列和主题可以包含所有先进的服务总线功能,如事务和会话支持。Partitioned queues and topics can contain all advanced Service Bus features, such as support for transactions and sessions.

有关服务总线内部的信息,请参阅服务总线体系结构一文。For information about Service Bus internals, see the Service Bus architecture article.

默认情况下,创建实体时,对标准和高级消息传送中的所有队列和主题启用分区。Partitioning is enabled by default at entity creation on all queues and topics in both Standard and Premium messaging. 可以创建标准消息传送层实体而不进行分区,但高级命名空间中的队列和主题始终进行分区;无法禁用此选项。You can create Standard messaging tier entities without partitioning, but queues and topics in a Premium namespace are always partitioned; this option cannot be disabled.

无法更改标准或高级层中现有队列或主题的分区选项,只能在创建实体时设置此选项。It is not possible to change the partitioning option on an existing queue or topic in either Standard or Premium tiers, you can only set the option when you create the entity.

工作原理How it works

每个分区的队列或主题由多个片段构成。Each partitioned queue or topic consists of multiple fragments. 每个片段存储在不同的消息传送存储中并由不同的消息中转站进行处理。Each fragment is stored in a different messaging store and handled by a different message broker. 当向分区的队列或主题发送消息时,服务总线会将该消息分配到其中一个片段。When a message is sent to a partitioned queue or topic, Service Bus assigns the message to one of the fragments. 选择是通过服务总线或发送方可以指定的分区键随机完成的。The selection is done randomly by Service Bus or by using a partition key that the sender can specify.

客户端要从分区队列或从分区主题的订阅接收消息时,服务总线查询所有片段以获取消息,并将自任何消息存储获取的第一条消息返回到接收方。When a client wants to receive a message from a partitioned queue, or from a subscription to a partitioned topic, Service Bus queries all fragments for messages, then returns the first message that is obtained from any of the messaging stores to the receiver. 服务总线缓存其他消息并在收到其他接收请求时将它们返回。Service Bus caches the other messages and returns them when it receives additional receive requests. 接收客户端无法识别分区;分区队列或主题的面向客户端的行为(例如,读取、完成、延迟、死信、预提取)与常规实体行为相同。A receiving client is not aware of the partitioning; the client-facing behavior of a partitioned queue or topic (for example, read, complete, defer, deadletter, prefetching) is identical to the behavior of a regular entity.

向分区队列或主题发送一条消息,或从分区队列或主题接收消息时无需额外付费。There is no additional cost when sending a message to, or receiving a message from, a partitioned queue or topic.

启用分区Enable partitioning

要将分区队列和主题用于 Azure 服务总线,请使用 Azure SDK 2.2 版或更高版本,或在 HTTP 请求中指定 api-version=2013-10 或更高版本。To use partitioned queues and topics with Azure Service Bus, use the Azure SDK version 2.2 or later, or specify api-version=2013-10 or later in your HTTP requests.

标准Standard

在标准消息传送层中,可以创建 1、2、3、4 或 5 GB 大小的服务总线队列和主题(默认值为 1 GB)。In the Standard messaging tier, you can create Service Bus queues and topics in 1, 2, 3, 4, or 5 GB sizes (the default is 1 GB). 已启用分区,服务总线指定的每个 GB 的实体创建 16 个副本(16 个分区)。With partitioning enabled, Service Bus creates 16 copies (16 partitions) of the entity for each GB you specify. 因此,如果创建了一个大小为 5 GB 的队列,共有 16 个分区,最大队列大小为 (5 * 16) = 80 GB。As such, if you create a queue that's 5 GB in size, with 16 partitions the maximum queue size becomes (5 * 16) = 80 GB. 可通过在 Azure 门户中分区队列或主题的“概述”边栏选项卡中查看该实体的条目来了解该队列或主题的最大大小。You can see the maximum size of your partitioned queue or topic by looking at its entry on the Azure portal, in the Overview blade for that entity.

高级Premium

在高级层命名空间中,可以创建 1、2、3、4、5、10、20、40 或 80 GB 大小的服务总线队列和主题(默认值为 1 GB)。In a Premium tier namespace, you can create Service Bus queues and topics in 1, 2, 3, 4, 5, 10, 20, 40, or 80 GB sizes (the default is 1 GB). 默认情况下已启用分区,服务总线为每个实体创建两个分区。With partitioning enabled by default, Service Bus creates two partitions per entity. 可通过在 Azure 门户中分区队列或主题的“概述”边栏选项卡中查看该实体的条目来了解该队列或主题的最大大小。You can see the maximum size of your partitioned queue or topic by looking at its entry on the Azure portal, in the Overview blade for that entity.

有关高级消息传送层中的分区的详细信息,请参阅服务总线高级和标准消息传送层For more information about partitioning in the Premium messaging tier, see Service Bus Premium and Standard messaging tiers.

创建分区实体Create a partitioned entity

有多种方法可以创建分区的队列或主题。There are several ways to create a partitioned queue or topic. 从应用程序创建队列或主题时,可以通过分别将 QueueDescription.EnablePartitioningTopicDescription.EnablePartitioning 属性设置为 true 来启用队列或主题的分区。When you create the queue or topic from your application, you can enable partitioning for the queue or topic by respectively setting the QueueDescription.EnablePartitioning or TopicDescription.EnablePartitioning property to true. 这些属性必须在队列或主题创建时设置。These properties must be set at the time the queue or topic is created. 如前面所述,无法更改现有队列或主题的这些属性。As stated previously, it is not possible to change these properties on an existing queue or topic. 例如:For example:

// Create partitioned topic
NamespaceManager ns = NamespaceManager.CreateFromConnectionString(myConnectionString);
TopicDescription td = new TopicDescription(TopicName);
td.EnablePartitioning = true;
ns.CreateTopic(td);

或者,可以在 Azure 门户或 Visual Studio 中创建分区队列或主题。Alternatively, you can create a partitioned queue or topic in the Azure portal or in Visual Studio. 在门户中创建队列或主题时,队列或主题的“创建”对话框中的“启用分区”选项是默认选中的。When you create a queue or topic in the portal, the Enable partitioning option in the queue or topic Create dialog box is checked by default. 只能在标准层实体中禁用此选项;在高级层中,始终启用分区。You can only disable this option in a Standard tier entity; in the Premium tier partitioning is always enabled. 在 Visual Studio 中,单击“新队列”或“新主题”对话框中的“启用分区”复选框。In Visual Studio, click the Enable Partitioning checkbox in the New Queue or New Topic dialog box.

使用分区键Use of partition keys

一条消息在分区队列或主题中排队时,服务总线检查是否存在分区键。When a message is enqueued into a partitioned queue or topic, Service Bus checks for the presence of a partition key. 如果找到,它将选择基于该密钥的片段。If it finds one, it selects the fragment based on that key. 如果找不到分区密钥,它将选择基于内部算法的片段。If it does not find a partition key, it selects the fragment based on an internal algorithm.

使用分区键Using a partition key

某些应用场景(例如会话或事务)中,要求将消息存储在特定的片段中。Some scenarios, such as sessions or transactions, require messages to be stored in a specific fragment. 所有这些应用场景都需要使用分区键。All these scenarios require the use of a partition key. 使用相同的分区键的所有消息都分配到同一片段中。All messages that use the same partition key are assigned to the same fragment. 如果该片段暂时不可用,服务总线将返回一条错误消息。If the fragment is temporarily unavailable, Service Bus returns an error.

根据应用场景,将不同的消息属性用作分区键:Depending on the scenario, different message properties are used as a partition key:

SessionId:如果消息已设置 BrokeredMessage.SessionId 属性,则服务总线将此属性用作分区键。SessionId: If a message has the BrokeredMessage.SessionId property set, then Service Bus uses this property as the partition key. 这样一来,属于同一会话的所有消息都由同一消息中转站处理。This way, all messages that belong to the same session are handled by the same message broker. 这使服务总线得以保证消息顺序以及会话状态的一致性。This enables Service Bus to guarantee message ordering as well as the consistency of session states.

PartitionKey:如果消息已设置 BrokeredMessage.PartitionKey 属性但未设置 BrokeredMessage.SessionId 属性,则服务总线将 PartitionKey 属性用作分区键。PartitionKey: If a message has the BrokeredMessage.PartitionKey property but not the BrokeredMessage.SessionId property set, then Service Bus uses the PartitionKey property as the partition key. 如果消息同时设置了 SessionIdPartitionKey 属性,则这两个属性必须相同。If the message has both the SessionId and the PartitionKey properties set, both properties must be identical. 如果 PartitionKey 属性设置为与 SessionId 属性不同的值,则服务总线返回无效操作异常。If the PartitionKey property is set to a different value than the SessionId property, Service Bus returns an invalid operation exception. 如果发送方发送非会话感知事务消息,应使用 PartitionKey 属性。The PartitionKey property should be used if a sender sends non-session aware transactional messages. 分区键可确保事务中所发送的所有消息都由同一个消息传递中转站处理。The partition key ensures that all messages that are sent within a transaction are handled by the same messaging broker.

MessageId:如果队列或主题将 QueueDescription.RequiresDuplicateDetection 属性设置为 true 且未设置 BrokeredMessage.SessionIdBrokeredMessage.PartitionKey 属性,则 BrokeredMessage.MessageId 属性将充当分区键。MessageId: If the queue or topic has the QueueDescription.RequiresDuplicateDetection property set to true and the BrokeredMessage.SessionId or BrokeredMessage.PartitionKey properties are not set, then the BrokeredMessage.MessageId property serves as the partition key. (请注意,如果应用程序进行分配,Microsoft .NET 和 AMQP 库会自动分配消息 ID。)在这种情况下,同一消息的所有副本都由同一消息中转站处理。(Note that the Microsoft .NET and AMQP libraries automatically assign a message ID if the sending application does not.) In this case, all copies of the same message are handled by the same message broker. 这使服务总线能够检测并消除重复的消息。This enables Service Bus to detect and eliminate duplicate messages. 如果 QueueDescription.RequiresDuplicateDetection 属性未设置为 true,服务总线不考虑将 MessageId 属性用作分区键。If the QueueDescription.RequiresDuplicateDetection property is not set to true, Service Bus does not consider the MessageId property as a partition key.

不使用分区键Not using a partition key

如果没有分区键,服务总线以轮循机制将消息分发到分区队列或主题的所有片段。In the absence of a partition key, Service Bus distributes messages in a round-robin fashion to all the fragments of the partitioned queue or topic. 如果所选的片段不可用,服务总线会将消息分配给不同的片段。If the chosen fragment is not available, Service Bus assigns the message to a different fragment. 这样一来,尽管消息存储暂时不可用,发送操作仍可成功。This way, the send operation succeeds despite the temporary unavailability of a messaging store. 但是,无法实现分区键提供的保证排序。However, you will not achieve the guaranteed ordering that a partition key provides.

有关可用性(没有分区键)和一致性(使用分区键)之间的权衡的更深入讨论,请参阅此文For a more in-depth discussion of the tradeoff between availability (no partition key) and consistency (using a partition key), see this article. 此信息同样适用于已分区服务总线实体。This information applies equally to partitioned Service Bus entities.

要给服务总线足够的时间将消息排入不同片段的队列中,发送消息的客户端指定的 MessagingFactorySettings.OperationTimeout 值必须大于 15 秒。To give Service Bus enough time to enqueue the message into a different fragment, the MessagingFactorySettings.OperationTimeout value specified by the client that sends the message must be greater than 15 seconds. 建议将 OperationTimeout 属性设置为 60 秒的默认值。It is recommended that you set the OperationTimeout property to the default value of 60 seconds.

请注意,分区键会将消息“固定”到特定片段。Note that a partition key "pins" a message to a specific fragment. 如果保存此片段的消息传送存储不可用,服务总线将返回一条错误消息。If the messaging store that holds this fragment is unavailable, Service Bus returns an error. 如果没有分区键,服务总线可以选择其他片段且操作将成功。In the absence of a partition key, Service Bus can choose a different fragment and the operation succeeds. 因此,建议除非必需,否则不要提供分区键。Therefore, it is recommended that you do not supply a partition key unless it is required.

高级主题:将事务用于分区实体Advanced topics: use transactions with partitioned entities

作为事务一部分发送的消息必须指定分区键。Messages that are sent as part of a transaction must specify a partition key. 这可以是以下属性之一:BrokeredMessage.SessionIdBrokeredMessage.PartitionKeyBrokeredMessage.MessageIdThis can be one of the following properties: BrokeredMessage.SessionId, BrokeredMessage.PartitionKey, or BrokeredMessage.MessageId. 所有作为同一事务一部分发送的消息必须指定相同的分区键。All messages that are sent as part of the same transaction must specify the same partition key. 如果尝试在事务中发送一条没有分区键的消息,服务总线会返回无效操作异常。If you attempt to send a message without a partition key within a transaction, Service Bus returns an invalid operation exception. 如果尝试在同一事务中发送多条具有不同分区键的消息,服务总线也会返回无效操作异常。If you attempt to send multiple messages within the same transaction that have different partition keys, Service Bus returns an invalid operation exception. 例如:For example:

CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
    BrokeredMessage msg = new BrokeredMessage("This is a message");
    msg.PartitionKey = "myPartitionKey";
    messageSender.Send(msg); 
    ts.Complete();
}
committableTransaction.Commit();

如果设置了任何作为分区键的属性,服务总线会将消息固定到特定片段。If any of the properties that serve as a partition key are set, Service Bus pins the message to a specific fragment. 无论是否使用事务,该行为都会发生。This behavior occurs whether or not a transaction is used. 建议如非必须不要指定分区键。It is recommended that you do not specify a partition key if it is not necessary.

会话用于分区实体Using sessions with partitioned entities

要将事务消息发送到会话感知的主题或队列,消息必须设置 BrokeredMessage.SessionId 属性。To send a transactional message to a session-aware topic or queue, the message must have the BrokeredMessage.SessionId property set. 如果也指定了 BrokeredMessage.PartitionKey 属性,该属性必须与 SessionId 属性相同。If the BrokeredMessage.PartitionKey property is specified as well, it must be identical to the SessionId property. 如果不同,则服务总线会返回无效操作异常。If they differ, Service Bus returns an invalid operation exception.

与常规(非分区)的队列或主题不同,不可能使用单一事务来将多条消息发送到不同会话。Unlike regular (non-partitioned) queues or topics, it is not possible to use a single transaction to send multiple messages to different sessions. 如果进行尝试,服务总线会返回无效操作异常。If attempted, Service Bus returns an invalid operation exception. 例如:For example:

CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
    BrokeredMessage msg = new BrokeredMessage("This is a message");
    msg.SessionId = "mySession";
    messageSender.Send(msg); 
    ts.Complete();
}
committableTransaction.Commit();

使用分区实体自动进行消息转发Automatic message forwarding with partitioned entities

服务总线支持从分区实体、向分区实体或在分区实体之间进行消息自动转发。Service Bus supports automatic message forwarding from, to, or between partitioned entities. 若要启用消息自动转发,请在源队列或订阅上设置 QueueDescription.ForwardTo 属性。To enable automatic message forwarding, set the QueueDescription.ForwardTo property on the source queue or subscription. 如果消息指定分区键(SessionIdPartitionKeyMessageId),则该分区键用于目标实体。If the message specifies a partition key (SessionId, PartitionKey, or MessageId), that partition key is used for the destination entity.

注意事项和指南Considerations and guidelines

  • 高度一致性功能:如果实体使用会话、重复检测或显式控制分区键等功能,则消息传送操作一定会路由至特定的片段。High consistency features: If an entity uses features such as sessions, duplicate detection, or explicit control of partitioning key, then the messaging operations are always routed to specific fragments. 如果任何片段遇到过高的流量,或基础存储处于不正常状态,这些操作会失败,而且可用性会降低。If any of the fragments experience high traffic or the underlying store is unhealthy, those operations fail and availability is reduced. 整体来说,一致性仍然远高于非分区实体;只有一部分流量会遇到问题,而不是所有流量。Overall, the consistency is still much higher than non-partitioned entities; only a subset of traffic is experiencing issues, as opposed to all the traffic. 有关详细信息,请参阅此处对可用性和一致性的讨论For more information, see this discussion of availability and consistency.
  • 管理:必须对实体的所有片段执行创建、更新及删除等操作。Management: Operations such as Create, Update and Delete must be performed on all the fragments of the entity. 如果任何片段处于不正常状态,可能会导致这些操作失败。If any fragment is unhealthy, it could result in failures for these operations. 以“获取”操作来说,必须汇总来自所有片段的信息,例如消息计数。For the Get operation, information such as message counts must be aggregated from all fragments. 如果任何片段处于不正常状态,则实体可用性状态会报告为受限制。If any fragment is unhealthy, the entity availability status is reported as limited.
  • 少量消息的情况:对于这类情况,尤其是使用 HTTP 协议时,可能必须执行多次接收操作,才能获取所有消息。Low volume message scenarios: For such scenarios, especially when using the HTTP protocol, you may have to perform multiple receive operations in order to obtain all the messages. 对于接收请求,前端会在所有片段上执行接收,并缓存所有收到的响应。For receive requests, the front end performs a receive on all the fragments and caches all the responses received. 相同连接上的后续接收请求将受益于此缓存,而且接收延迟会缩短。A subsequent receive request on the same connection would benefit from this caching and receive latencies will be lower. 不过,如果有多个连接或使用 HTTP,则会针对每个请求建立新的连接。However, if you have multiple connections or use HTTP, that establishes a new connection for each request. 因此,不保证抵达相同的节点。As such, there is no guarantee that it would land on the same node. 如果现有的所有消息均被锁定,而且在另一个前端中缓存,则接收操作返回 nullIf all existing messages are locked and cached in another front end, the receive operation returns null. 消息最后会到期,可以再次接收它们。Messages eventually expire and you can receive them again. 建议使用 HTTP 保持连接。HTTP keep-alive is recommended.
  • 浏览/速览消息PeekBatch 不一定返回 MessageCount 属性中指定的消息数目。Browse/Peek messages: PeekBatch does not always return the number of messages specified in the MessageCount property. 这有两个常见的原因。There are two common reasons for this. 其中一个原因是消息集合的汇总大小超过设置的 256 KB 上限。One reason is that the aggregated size of the collection of messages exceeds the maximum size of 256 KB. 另一个原因是,如果队列或主题的 EnablePartitioning 属性设为 true,则分区可能没有足够的消息来完成所请求的消息数目。Another reason is that if the queue or topic has the EnablePartitioning property set to true, a partition may not have enough messages to complete the requested number of messages. 一般情况下,如果应用程序要接收特定数目的消息,则应该重复调用 PeekBatch,直到获得该数目的消息,或者已没有更多消息可速览为止。In general, if an application wants to receive a specific number of messages, it should call PeekBatch repeatedly until it gets that number of messages, or there are no more messages to peek. 有关详细信息,包括代码示例,请参阅 QueueClient.PeekBatchSubscriptionClient.PeekBatch API 文档。For more information, including code samples, see the QueueClient.PeekBatch or SubscriptionClient.PeekBatch API documentation.

最新添加的功能Latest added features

分区实体限制Partitioned entities limitations

当前,服务总线对分区的队列和主题施加以下限制:Currently Service Bus imposes the following limitations on partitioned queues and topics:

  • 分区的队列和主题不支持在单个事务中发送属于不同会话的消息。Partitioned queues and topics do not support sending messages that belong to different sessions in a single transaction.
  • 服务总线当前允许为每个命名空间最多创建 100 个分区的队列或主题。Service Bus currently allows up to 100 partitioned queues or topics per namespace. 每个分区的队列或主题都将计入每个命名空间的 10,000 个实体的配额(不适用于高级层)。Each partitioned queue or topic counts towards the quota of 10,000 entities per namespace (does not apply to Premium tier).

后续步骤Next steps

AMQP 1.0 协议指南中了解 AMQP 1.0 消息传送规范的核心概念。Read about the core concepts of the AMQP 1.0 messaging specification in the AMQP 1.0 protocol guide.