服务总线事务处理概述Overview of Service Bus transaction processing

本文将讨论 Microsoft Azure 服务总线的事务功能。This article discusses the transaction capabilities of Microsoft Azure Service Bus. 很多讨论已在服务总线中的 AMQP 事务示例中进行了说明。Much of the discussion is illustrated by the AMQP Transactions with Service Bus sample. 本文仅限于概述服务总线中的事务处理和发送方式 功能,虽然原子事务示例在作用域内更广泛且更复杂。This article is limited to an overview of transaction processing and the send via feature in Service Bus, while the Atomic Transactions sample is broader and more complex in scope.

服务总线中的事务Transactions in Service Bus

一个事务将两个或更多操作组合成执行作用域 。A transaction groups two or more operations together into an execution scope. 就本质而言,此类事务必须确保所有操作属于给定的操作组,无论联合成功还是失败。By nature, such a transaction must ensure that all operations belonging to a given group of operations either succeed or fail jointly. 在这方面,事务作为一个单元进行操作,通常称为原子性 。In this respect transactions act as one unit, which is often referred to as atomicity.

服务总线是事务性消息代理,并确保针对其消息存储的所有内部操作的事务完整性。Service Bus is a transactional message broker and ensures transactional integrity for all internal operations against its message stores. 服务总线内部的所有消息传输,如将消息移到 dead-letter queue 或在实体之间自动转发消息,都是事务性的。All transfers of messages inside of Service Bus, such as moving messages to a dead-letter queue or automatic forwarding of messages between entities, are transactional. 因此,如果服务总线接受一条消息,则该消息已存储并标有一个序列号。As such, if Service Bus accepts a message, it has already been stored and labeled with a sequence number. 从那时起,服务总线内的任何消息传输都是实体之间协调的操作,将从不会导致消息丢失(源成功而目标失败)或重复(源失败而目标成功)。From then on, any message transfers within Service Bus are coordinated operations across entities, and will neither lead to loss (source succeeds and target fails) or to duplication (source fails and target succeeds) of the message.

服务总线支持对事务作用域内的消息传送实体(队列、主题、订阅)执行分组操作。Service Bus supports grouping operations against a single messaging entity (queue, topic, subscription) within the scope of a transaction. 例如,可以从事务作用域内将多条消息发送到一个队列,在事务成功完成时,这些消息将仅提交到该队列的日志。For example, you can send several messages to one queue from within a transaction scope, and the messages will only be committed to the queue's log when the transaction successfully completes.

事务作用域内的操作Operations within a transaction scope

可以在事务作用域内执行的操作如下所示:The operations that can be performed within a transaction scope are as follows:

不包括接收操作,因为假定应用程序在某个接收循环内使用 ReceiveMode.PeekLock 模式或通过 OnMessage 回调获取消息,而且只有那时才打开用于处理消息的事务作用域。Receive operations are not included, because it is assumed that the application acquires messages using the ReceiveMode.PeekLock mode, inside some receive loop or with an OnMessage callback, and only then opens a transaction scope for processing the message.

然后,消息的处置(完成、放弃、死信、延迟)会在事务作用域内进行,并依赖于在事务处理的整体结果。The disposition of the message (complete, abandon, dead-letter, defer) then occurs within the scope of, and dependent on, the overall outcome of the transaction.

传输和“发送方式”Transfers and "send via"

要启用将数据从队列到处理器,然后到另一个队列的事务性移交,服务总线支持传输 。To enable transactional handover of data from a queue to a processor, and then to another queue, Service Bus supports transfers. 在传输操作中,发送程序先将消息发送到“传输队列” ,然后传输队列立即使用自动转发功能依赖的同一可靠传输实现代码,将消息移到预期的目标队列。In a transfer operation, a sender first sends a message to a transfer queue, and the transfer queue immediately moves the message to the intended destination queue using the same robust transfer implementation that the auto-forward capability relies on. 消息永远不会以对传输队列的使用者可见的方式提交到传输队列的日志中。The message is never committed to the transfer queue's log in a way that it becomes visible for the transfer queue's consumers.

当传输队列本身是发送方的输入消息的源时,此事务功能的优势越明显。The power of this transactional capability becomes apparent when the transfer queue itself is the source of the sender's input messages. 换而言之,服务总线可以“通过”传输队列将消息传输到目标队列中,同时对输入消息执行完成(或延迟/死信)操作,所有这一切都通过一个原子操作完成。In other words, Service Bus can transfer the message to the destination queue "via" the transfer queue, while performing a complete (or defer, or dead-letter) operation on the input message, all in one atomic operation.

在代码中查看它See it in code

若要设置此类传输,需创建通过传输队列以目标队列为目标的消息发送方。To set up such transfers, you create a message sender that targets the destination queue via the transfer queue. 还将设置接收方,以便从该同一队列拉取消息。You also have a receiver that pulls messages from that same queue. 例如:For example:

var connection = new ServiceBusConnection(connectionString);

var sender = new MessageSender(connection, QueueName);
var receiver = new MessageReceiver(connection, QueueName);

简单事务处理随后使用这些元素,如以下示例所示。A simple transaction then uses these elements, as in the following example. 若要参考完整示例,请参阅 GitHub 上的源代码To refer the full example, refer the source code on GitHub:

var receivedMessage = await receiver.ReceiveAsync();

using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
    try
    {
        // do some processing
        if (receivedMessage != null)
            await receiver.CompleteAsync(receivedMessage.SystemProperties.LockToken);

        var myMsgBody = new MyMessage
        {
            Name = "Some name",
            Address = "Some street address",
            ZipCode = "Some zip code"
        };

        // send message
        var message = myMsgBody.AsMessage();
        await sender.SendAsync(message).ConfigureAwait(false);
        Console.WriteLine("Message has been sent");

        // complete the transaction
        ts.Complete();
    }
    catch (Exception ex)
    {
        // This rolls back send and complete in case an exception happens
        ts.Dispose();
        Console.WriteLine(ex.ToString());
    }
}

后续步骤Next steps

有关服务总线队列的详细信息,请参阅以下文章:See the following articles for more information about Service Bus queues: