使用Service Bus中间消息改善性能的最佳方法

这篇文章描述了如何使用Service Bus中间消息功能以某种方式使其产生最佳性能。你可以在MSDN上阅读整篇文章以了解更多的细节。

使用Service Bus客户端协议

Service Bus支持Service Bus客户端协议和HTTP。Service Bus客户端协议更有效,因为只要消息库存在,它就会维持与Service Bus服务的连接。它还实现了批处理和预读取Service Bus客户端协议对.NET应用程序是可用的,即使用.NET托管的API。只要可能,通过Service Bus客户端协议连接到Service Bus。

重复利用Factories 和 Clients

Service Bus客户端对象,例如QueueClientMessageSender是通过一个MessagingFactory创建的,它还提供连接关系的内部管理。在发送完一条消息之后,建议不要关闭任何factories 、 queue、topic 和 subscription clients对象,然后在发送下一条消息时重新发送它们。相反地,请重用factory和client来执行多个操作。关闭一个消息库删除与Service Bus的连接关系。建立一个连接是要付出很大代价的。

使用并发的操作

执行一种操作(发送、接受、删除,等等)需要一定的时间。这个时间包括Service Bus服务操作的执行时间和请求及回复的延迟。为了每次增加操作的数量,应并发地执行操作。如果客户端和托管Service Bus命名空间的数据中心之间的延迟时间长的话,尤其如此。

并发执行多个操作有几种不同的方式:

异步操作。客户端管道通过执行异步操作来进行操作。在前一个请求完成之前开始下一个请求。

多个库。由同一个库创建的所有客户端(发送者以及接收者)都共用一个TCP连接。能够访问该TCP连接的操作的数量限制着最大消息吞吐量。吞吐量可以由单个库获得,因TCP的往返时间和消息大小的不同而不同。

使用客户端批处理

客户端批处理允许一个queue/topic客户端来将多个发送操作处理成单个请求。它还允许queue/subscription客户端将多个Complete的请求处理成单个请求。默认情况下。客户端使用批处理的时间间隔为20毫秒。你可以在创建消息库之前通过设置MessagingFactorySettings.NetMessagingTransportSettings.BatchFlushInterval来改变批处理的间隔时间。这个设定会影响由该库创建的所有客户端。

 MessagingFactorySettings mfs = new MessagingFactorySettings(); 
mfs.TokenProvider = tokenProvider;
mfs.NetMessagingTransportSettings.BatchFlushInterval = TimeSpan.FromSeconds(0.05);
MessagingFactory messagingFactory = MessagingFactory.Create(namespaceUri, mfs);

在低吞吐量、低延迟的情况下,你希望禁用批处理。如果要这么做,请将BatchFlushInterval设为0。对于高吞吐量的情况,将批处理时间间隔增加到50毫秒。如果使用多个发送者,则将批处理时间间隔增加到100毫秒。

批处理只能用于异步的Send 和 Complete的操作。异步操作被立即送往Service Bus服务。批处理不能用于Peek 或 Receive操作,也不能用于跨客户端的操作。

使用批处理的存储访问

为了增加queue/topic/subscription的吞吐量,Service Bus服务对其内部存储进行写操作时批处理多个消息。如果启用一个queue 或 topic,向存储中写消息时将会被批处理。如果启用一个queue 或 subscription,删除存储中的消息将会被批处理。成批的存储访问只会影响到Send 和Complete的操作;接收操作不受影响。

当创建一个新的queue、topic或subscription,批处理存储访问的时间间隔被设为20毫秒。低吞吐量、低延迟的情况下要在创建该实体之前通过将QueueDescription.EnableBatchedOperations设置为false 来禁用批处理存储访问。

 QueueDescription qd = new QueueDescription();
qd.EnableBatchedOperations = false;
Queue q = namespaceManager.CreateQueue(qd);

使用预读取

当执行接收操作时预读取会导致queue/subscription客户端从服务中加载附加消息。客户端将这些消息存储在本地缓存中。QueueClient.PrefetchCount 和 SubscriptionClient.PrefetchCount的值能够确定能被预读取的消息的数量。每个客户端允许预读取维护它自己的缓存。不在客户端之间共享缓存。

Service Bus锁定任何预读取的消息,如此以来预读取的消息就不能被不同的接收者所接收。如果接收者未能在锁超时以前完成消息的接收,该消息就能被其他接收者所接收。预读取消息的副本保留在缓存中。当它尝试接收超时消息缓存的副本,接收者将收到异常。

为了防止接收过期消息,缓存的大小必须小于能够在锁超时时间间隔内被客户端接收的消息的数量。当使用默认的锁超时时间——60秒,SubscriptionClient.PrefetchCount的值最好是该库中所有接收者的最大处理率的20倍。例如,如果一个库创建3个接收机器并且每个接收机器每秒可以处理超过10条消息,预读取的数量不应超过20*3*10 = 600。

默认情况下,QueueClient.PrefetchCount被设为0,这意味着从服务不能获取额外的消息。如果接收者以一个高比例接收消息,则启用预读取。在低延迟的情况下,如果单个客户端从queue 或 subscription获取消息则启用预读取。如果使用多个客户端,则可以将预读取的数量设为0。通过这样做,第二个客户端可以接收第二个消息,虽然第一个客户端仍在处理第一个消息。

在MSDN上阅读整篇文章

本文翻译自:https://blogs.msdn.com/b/windowsazure/archive/2011/11/09/new-article-best-practices-for-performance-improvements-using-service-bus-brokered-messaging.aspx