該部分包含如下五部分内容,限于篇幅,本文先介紹前三個:概念、消息類型、耦合。
一、概念
二、消息類型
三、耦合
四、模式
五、消息路由
一、概念
本中的文所有代碼,不是一個完整的例子,也不是一個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