您现在访问的是微软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. 分区意味着分区实体的总吞吐量不再受单个消息中转站或消息存储的性能所限制。Partitioning 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.

备注

分区在为基本或标准 SKU 中的所有队列和主题创建实体时可用。Partitioning is available at entity creation for all queues and topics in Basic or Standard SKUs. 它不可用于高级消息传送 SKU,但高级命名空间中任何先前已存在的分区实体将继续按预期方式工作。It is not available for the Premium messaging SKU, but any previously existing partitioned entities in Premium namespaces continue to work as expected.

无法更改任何现有队列或主题中的分区选项,只能在创建实体时设置此选项。It is not possible to change the partitioning option on any existing queue or topic; 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

在高级层命名空间中,不支持分区实体。In a Premium tier namespace, partitioning entities is not supported. 但是,仍然可以创建 1、2、3、4、5、10、20、40 或 80 GB 大小的服务总线队列和主题(默认值为 1 GB)。However, you can still create Service Bus queues and topics in 1, 2, 3, 4, 5, 10, 20, 40, or 80-GB sizes (the default is 1 GB). 可通过在 Azure 门户中队列或主题的“概述”边栏选项卡中查看该实体的条目来了解该队列或主题的大小。You can see the size of your queue or topic by looking at its entry on the Azure portal, in the Overview blade for that entity.

创建分区实体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. 这些属性必须在创建队列或主题时设置,并仅在较旧的 WindowsAzure.ServiceBus 库中可用。These properties must be set at the time the queue or topic is created, and are available only in the older WindowsAzure.ServiceBus library. 如前面所述,无法更改现有队列或主题的这些属性。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 门户中创建分区队列或主题。Alternatively, you can create a partitioned queue or topic in the Azure portal. 在门户中创建队列或主题时,队列或主题的“创建”对话框中的“启用分区”选项是默认选中的。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 not supported, and the checkbox has no effect.

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

PartitionKey:如果消息已设置 PartitionKey 属性但未设置 SessionId 属性,则服务总线将 PartitionKey 属性值用作分区键。PartitionKey: If a message has the PartitionKey property but not the SessionId property set, then Service Bus uses the PartitionKey property value 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:如果队列或主题将 RequiresDuplicateDetection 属性设置为“true”且未设置 SessionIdPartitionKey 属性,则 MessageId 属性值将充当分区键。MessageId: If the queue or topic has the RequiresDuplicateDetection property set to true and the SessionId or PartitionKey properties are not set, then the MessageId property value serves as the partition key. (如果发送应用程序不这样做,Microsoft .NET 和 AMQP 库会自动分配消息 ID。)在这种情况下,同一消息的所有副本都由同一消息中转站处理。(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. 此 ID 使服务总线能够检测并消除重复的消息。This ID enables Service Bus to detect and eliminate duplicate messages. 如果 RequiresDuplicateDetection 属性未设置为“true”,服务总线不考虑将 MessageId 属性用作分区键。If the 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.

要给服务总线足够的时间将消息排入不同片段的队列中,客户端指定的发送消息的 OperationTimeout 值必须大于 15 秒。To give Service Bus enough time to enqueue the message into a different fragment, the 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.

分区键会将消息“固定”到特定片段。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. 键可以是以下属性之一:SessionIdPartitionKey,或 MessageIdThe key can be one of the following properties: SessionId, PartitionKey, or 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))
{
    Message msg = new Message("This is a message");
    msg.PartitionKey = "myPartitionKey";
    messageSender.SendAsync(msg); 
    ts.CompleteAsync();
}
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

要将事务消息发送到会话感知的主题或队列,消息必须设置 SessionId 属性。To send a transactional message to a session-aware topic or queue, the message must have the SessionId property set. 如果还指定了 PartitionKey 属性,该属性必须与 SessionId 属性相同。If the 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))
{
    Message msg = new Message("This is a message");
    msg.SessionId = "mySession";
    messageSender.SendAsync(msg); 
    ts.CompleteAsync();
}
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.
  • 浏览/扫视消息:仅在较旧的 WindowsAzure.ServiceBus 库中可用。Browse/Peek messages: Available only in the older WindowsAzure.ServiceBus library. PeekBatch 不一定返回 MessageCount 属性中指定的消息数目。PeekBatch does not always return the number of messages specified in the MessageCount property. 此行为有两个常见的原因。There are two common reasons for this behavior. 其中一个原因是消息集合的汇总大小超过设置的 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 are not supported in the Premium messaging tier.
  • 分区的队列和主题不支持在单个事务中发送属于不同会话的消息。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.