天天看點

Shuttle ESB(二)——架構模型介紹(1)一、概念二、消息類型三、耦合

該部分包含如下五部分内容,限于篇幅,本文先介紹前三個:概念、消息類型、耦合。

一、概念

二、消息類型

三、耦合

四、模式

五、消息路由

一、概念

本中的文所有代碼,不是一個完整的例子,也不是一個vs解決方案。它隻是為了友善了解,輔助我們了解Shuttle ESB裡面一些比較重要的概念。在Shuttle ESB入門執行個體 裡面,有一個簡單的實作,将這些概念融合在了一起,大家可以結合執行個體,了解本文的概念。

Shuttle ESB的基本組成:消息、隊列和服務總線

每一個服務總線執行個體都是相關聯的,是以隻有一個輸入隊列,注意每一個端點隻能有一個輸入隊列。這個輸入隊列就是一個收件箱。收件箱中接收的所有消息,都是由服務總線執行個體進行使用。

    消息

Shuttle是基于消息的。這些消息是實作了指定接口的資料傳輸對象。例如:

public class ActivateMemberCommand
    {
        string MemberId { get; set; }
    }
public class MemberActivatedEvent
    {
        string MemberId { get; set; }
    }
           

隊列

Shuttle ESB中的消息,都是由Handler處理的。當一個服務總線執行個體啟動的時候,它就開始監聽收件箱裡的隊列消息。是以,在相關隊列裡面處理的消息,一定要有結束。收件箱的配置,是在應用程式配置檔案中設定的。

這種消息發送的方法,采用至少發送一次的機制。這不同于傳統概念上的,準确傳遞一次的例子。在某些臨界情況,它可能多次處理消息。然而,其他機制的臨界情況,可能會導緻資訊的丢失(一個重複的消息比沒有消息更容易點)

很重要的一點就是:所有的隊列都是無損的,并且有确認回報機制。

是以,一旦消息從隊列中重新取回,就有可能是确認消息釋放消息傳回到隊列。

服務總線

在每個應用程式通路服務總線時,服務總線執行個體是必須的。服務總線的基本組成:關聯的代碼、應用程式配置檔案和應用自定義元件。例如:

public class ServiceBusHost : IHost, IDisposable
    {
        private static IServiceBus bus;
public void Start()
        {
            bus = ServiceBus.Create().Start();
        }
public void Dispose()
        {
            bus.Dispose();
        }
    }
           

建立并運作一個服務總線執行個體建立,同時,啟動和配置退出應用程式。服務總線可以在任何類型的應用程式中使用,最經典的情況就是作為服務進行通信。雖然你可以自己寫服務,來作為服務總線,但是它是不必要的,因為你可以能用到通用主機:generic service host:http://shuttle.github.io/shuttle-esb/generic-host/index.html

二、消息類型

指令消息

由于指令是一個要求執行特定功能的明确請求,是以指令會被發送到單獨的終結點。也就是說:為了發送消息,你需要知道某個終結點的相關業務實作。是以,指令導緻了高度的行為耦合。如果在發送消息時,那個接收消息的終結點是可配置的,那麼便可随時更改終結點。

一個指令消息總是屬于單一的一端。發送一個指令也永遠不會導緻一個消息出現在多個隊列裡。

雖然,我們應該盡量減少使用這種消息類型,但是它在特殊情況,也有使用的必要性,例如下面的例子。

    啟動一個應用

在我們的應用程式中,我們需要發送一個CreateOrderCommand 隊列服務。這将啟動相關過程。

是以從用戶端代碼開始:

bus.Send(new CreateOrderCommand("ClientName", "ProductXYZ"));
           

如果沒有消息接收端,這次調用就會失敗。

現在我們釋出一個事件,像OrderReceivedEvent 和我們的隊列服務,能夠訂閱一個事件,也能夠取消訂閱事件。

bus.Publish(new OrderOrderReceivedEvent("ClientName", "ProductXYZ"));
           

如果沒有訂閱者,調用也不會失敗。

是以,不同之處就是:使用消息的情況不同。當我們使用事件時,我們會選擇訂閱模式;但是當一個系統中,已經确定一些特定行為的時候,使用指令的方式,應該更合适一些。當然,當使用一個指令的方法時,仍然有一些其他系統知道對方已經接收到了指令,那麼訂單服務會接着釋出一個事件。

底層方法(RPC)

在某些情況下,一個事件可能無法傳遞某個動作的意圖。例如:當一個指令建立的時候(或者是指令的數量超過上限的時候),我們可能會給上司發一封郵件。電子郵件服務負責通過SMTP伺服器發送電子郵件。這電子郵件是無法通過OrderReceivedEvent事件訂閱的,因為電子郵件系統需要适應另一個系統中的規則。

在這個例子中,郵件系統負責發送郵件。 任何系統發送郵件,都需要決定什麼時候發送。是以,這個訂單服務将向郵件服務發送一個指令:

bus.Send(new SendMailCommand
                 {
                     To = "[email protected]",
                     From = "[email protected]",
                     Subject = "Important Order Received",
                     Body = "Order Details"
                 });
           

事件消息

一個事件消息就是用來通知所有的訂閱元件。每個元件訂閱事件,将得到一份事件消息。對于一個事件來說,如果沒有訂閱者,那麼使用者也不會有什麼影響。

文檔消息

一個文檔消息用來簡單的向一段發送資料。與使用事件消息一樣,文檔消息一定的方向性,接受者可以接收也可以不接收。但是,這不意味着資料會無緣無故的發送到一個終端。終端可能需要從一些服務中擷取一個文檔消息。或者根據需要,資料會自動發送給某些終端。

三、耦合

行為耦合

行為耦合是指一個系統與另一個系統行為的耦合程度。當你的系統接收到一個指令消息,你需要它在某個特定需求中使用。這就代表着一種高度的行為耦合。然而,當一個事件消息釋出好了,沒有訂閱者等待擷取消息。這就是一個較低的行為耦合。

也就是說:可能有一個期望的事件會導緻一個特定的結果。在這種情況下,行為的耦合增加了。

時空耦合

時空耦合指的是一個服務的可用性。例如:ServiceA服務依賴ServiceB服務。為了保證ServiceA能夠正常運作,需要同時保證ServiceB是可用的,然後ServiceA才能夠正常運作。這就是一個高度的時空耦合。相反的,如果ServiceA沒有ServiceB,仍然能夠正常運作,那麼這就是一個低時空耦合。

一個異步Web-Service調用就是一個高時空耦合例子。

現在你可能會心存疑慮:在一個用例中,需要ServiceA和ServiceB兩個服務,才能夠完成。那麼,他們是怎麼單獨進行的?

這其實很簡單,答案就是:使用隊列,進行異步通信。

你可能會說了:一個web-Service的調用可能使用異步通信,但是這裡還是有問題的。當一個用戶端的請求未接到相應時,ServiceA可能會執行失敗。這就會導緻web-Service調用失敗。

我們使用消息進行通信,消息經常會向着一個方向傳遞。從ServiceA到ServiceB是一個動作,執行之後,這個動作就結束了;從ServiceB到ServiceA又是一個動作,執行之後,這個動作就又結束了。

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

繼續閱讀