天天看點

Shuttle ESB(三)——架構模型介紹(2)四、模式五、消息路由

上一篇文章中,介紹了Shuttle ESB架構模型中的三個重要部分。今天,我們繼續介紹剩餘的三個内容:模式和消息路由。

四、模式

Request/Response(請求/響應模式)

對基于Request/Response消息機制的内容,你可以看WiKi的一些文章:http://en.wikipedia.org/wiki/Request-response

Shuttle ESB(三)——架構模型介紹(2)四、模式五、消息路由

向一個終端發送請求,執行某項功能,你可以發送一個指令消息:

bus.Send(new RequestMessage());
           

雖然這是一個非常簡單的模式,但是,它卻構成了一種耦合緊密的行為。盡管如此,這也未必是一件壞事,在許多情況下這是絕必需的。

通常,指令消息的Handler(處理程式),進行業務邏輯與消息的處理。但是很多時候,請求需要有響應。

響應可以以指令消息或者事件消息的形式傳回。使用的時候非常簡單,你隻需要通過服務總線執行個體進行如下調用:

bus.Send(new ResponseMessage(), c => c.Reply());
           

當然,隻要你願意,你可以将“響應”作為事件消息傳回,來達到解耦合的目的。那麼這将不再是請求/響應模式了,而是釋出訂閱模式。

請求/響應模式的好處是:它提供了一種機制,使調用者發出調用請求後,能夠收到服務端的反應。

Publish/Subscribe(釋出訂閱模式)

對于基礎釋出訂閱消息模式的更多内容,你可以看這裡:http://en.wikipedia.org/wiki/Publish/subscribe

Shuttle ESB(三)——架構模型介紹(2)四、模式五、消息路由

這種模式的特點就是,讓釋出者和訂閱者之間沒有行為耦合。實際上,一個事件消息可能都沒有訂閱者。但是這是不太符合實際情況的。太多的實踐證明,大多數情況下,我們要求至少要有一個訂閱者。

釋出一個事件消息,你可以采用如下格式:

bus.Send(new ResponseMessage(), c => c.Reply());
           

消息發送後,每一個訂閱者會都到接收到自己的消息。這完全不同于一對一的消息配置設定處理機制。

消息分發

可想而知,如果一個端點接收太多的消息,那麼處理這些消息就會端點處理能力降低,而且變得臃腫不堪。這種情況下,可以将消息改配置設定到服務節點上。

Shuttle ESB(三)——架構模型介紹(2)四、模式五、消息路由

如果該終端接收到一個服務節點的請求消息,它将向其他服務節點自動配置設定該消息。一個終端可以配置成隻發送消息。配置很簡單,隻需要設定收件箱标簽配置設定屬性為true即可。

由于消息分布都內建到收件箱,在處理相同端點時,隻需要在多個不同的機器上安裝一對一的消息。你接收消息的一端,需要一個控制收件箱的配置。因為所有的Shuttle消息都需要處理,而不是在隊列中保持等待狀态。

每一個服務站點在配置中唯一辨別,端點的控制收件箱需要如下配置:

<configuration>
   <configSections>
      <section name="serviceBus" type="Shuttle.ESB.Core.ServiceBusSection, Shuttle.ESB.Core"/>
   </configSections>
<serviceBus>
      <control 
          workQueueUri="msmq://./control-inbox-work" 
          errorQueueUri="msmq://./shuttle-error"/>
      <inbox 
          distribute="true"
          workQueueUri="msmq://./inbox-work" 
          errorQueueUri="msmq://./shuttle-error"/>
   </serviceBus>
</configuration>
           

任何接收消息的一端都能這樣配置。

然後,你就可以根據你的需要,建立多個服務節點。随着相關的所有釋出者的增多,就會形成一個消息的邏輯終點。釋出者的配置如下:

<configuration>
   <configSections>
      <section name="serviceBus" type="Shuttle.ESB.Core.ServiceBusSection, Shuttle.ESB.Core"/>
   </configSections>
<serviceBus>
      <worker
         distributorControlWorkQueueUri="msmq:///control-inbox=work" />
      <inbox
         workQueueUri="msmq://./workerN-inbox-work"
         errorQueueUri="msmq://./shuttle-error"
         threadCount="15">
      </inbox>
   </serviceBus>
</configuration>
           

隻要應用程式配置檔案包含一個閑置線程的标記,它就會發送一個消息給釋出者,表明一個線程成為可執行的。然後訂閱者将為每個可用的線程釋出消息。

當應用程式配置檔案包含勞工标記每個線程去閑置将消息發送到經銷商表示,一個線程已成為可執行的話。經銷商将為每個可用的線程發送消息。

消息分發的特例

一些隊列不需要消息分發。不使用客戶終端,而是用它的另一個執行個體,也可以使用相同的輸入隊列。這種機制适用于代理。因為代理通過消費者線程運作的消耗,集中管理消息。因為消費者來自哪裡都無所謂,是以隊列能夠給各個線程使用。

像基于MSMQ或者基于SqlServer的隊列,這些都是通過啟一個線程運作host,使用Handler進行消息處理。代理的方式不同于這種方式。在代理方式中,過程A将不知道這些消息所消耗的過程,而且導緻B過程可能向其他端點擷取消息。

五、消息路由

通常,我們說發送一個消息。根據“發送”,我們就确定它是一個指令消息。但是,它不一定必須是指令消息。你也可以給一個特定端點發送一個事件消息。實際情況下,更多的往往是發送事件消息,而不是指令消息。消息發送後,通過調用服務總線執行個體相關的重載方法:

TransportMessage Send(object message);
        TransportMessage Send(object message, Action<TransportMessageConfigurator> configure);
           

隻有那些沒有RecipientInboxWorkQueueUri集的資訊,将會通過服務總線進行傳輸。如果你需要通路任何可用的資訊源資料,傳輸資訊的Envelop将被退回。Shuttle ESB采用了ImessageRouteProvider的實作,來确認消息發送。

public interface IMessageRouteProvider
    {
        IEnumerable<string> GetRouteUris(object message);   
    }

The message route provider to use is specified when constructing the service bus:

    bus = ServiceBus
        .Create(c => c.MessageRouteProvider(new DefaultForwardingRouteProvider())
        .Start();
           

預設消息路由提供者,使用應用配置檔案,來确定往哪發送消息:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
      <section name="serviceBus" type="Shuttle.ESB.Core.ServiceBusSection, Shuttle.ESB.Core"/>
   </configSections>
<serviceBus>
      <messageRoutes>
         <messageRoute uri="msmq://serverA/inbox">
            <add specification="StartsWith" value="Shuttle.Messages1" />
            <add specification="StartsWith" value="Shuttle.Messages2" />
         </messageRoute>
         <messageRoute uri="sql://serverB/inbox">
            <add specification="TypeList" value="DoSomethingCommand, Assembly" />
         </messageRoute>
         <messageRoute uri="msmq://serverC/inbox">
            <add specification="Regex" value=".+[Cc]ommand.+" />
         </messageRoute>
         <messageRoute uri="sql://serverD/inbox">
            <add specification="Assembly" value="TheAssemblyName" />
         </messageRoute>
      </messageRoutes>
   </serviceBus>
</configuration>
           

IMessageRouteProvider接口的每一個實作,都能決定一個實作線路。然而,它都需要從給定的消息發送。一個典型的場景,以及defaultmessagerouteprovider的工作方式,是使用完整的類型名稱來确定目标。

注意:使用發送的每個消息類型,隻能被發送到一個端點。

原文位址:http://shuttle.github.io/shuttle-esb/architecture/#Concepts

繼續閱讀