在ESB中另外一個重要的課題就是Message Endpoint,這是關于一個應用程序如何連接到一個消息系統,并通過它來發送和接收消息。如果你在面向一個消息API編程,則你就正在開發一個endpoint代碼。商業中間件通常都提供了這些工具。
l Messaging Gateway
l Messaging Mapper
l Transactional Client
l Polling Consumer
l Event-Driven Consumer
l Competing Consumers
l Message Dispatcher
l Selective Consumer
l Durable Subscriber
l Idempotent Receiver
l Service Activator
發送和接收模式
有些endpoint模式既可以使用在發送方也可以使用在接受方。它們描述一個應用連接一個消息系統的一般情況。
包裝消息代碼 - 一個應用不應該意識到正在使用消息同另外一個應用程序通訊,大多數應用代碼應該在不知道message的情況下被編寫。在應用集成的地方,應該有一個薄薄的一層代碼來執行應用的集成部分。當集成是由消息實現的,這層將應用連接到消息系統的代碼稱為一個Message Gateway
數據轉換 - 當發送者和接受者使用不同的數據格式,或者不同的消息格式(支持不同的發送和接收者),在這種情況下,使用一個Message Mapper來在應用格式和消息格式之間轉換數據。
外部控制的事務 - 消息系統在內部和外部使用事務,默認的,每個發送和接收方法在他們自己的事務中運行。Message生產者和消費者應可選的使用一個Transactional Client來控制事務,當你需要將幾個消息一起發送伙通過其他事務服務整理消息時是很有用的。
消息消費者模式
其他endpoint模式只適用于消息消費者,發送消息是簡單的。棘手的問題是決定一個消息應該何時發送,它應包含什么,以及怎樣將它送到接受者 - 這是為什么我們有很多消息結構模式 - 但是一旦消息被構建,發送它是很容易的。另一方面,接收消息 - 很麻煩。因此許多endpoint模式是關于接收消息的。
接收消息的一個最重要的主題就是流量控制:一個應用控制,或者調節它消費消息的速度。一個潛在的問題是任何server都面臨著大量的客戶端請求會使其超載。通過遠程過程調用(RPI),server幾乎受到客戶端調用的支配。同樣的,通過消息,server不能控制客戶端發送請求的速度 - 但是server可是控制它處理這些請求的速度。應用不必像消息系統傳送消息那么快的接收并處理消息;使用一個Message Channel可以使它在一個可接收的速率上處理消息。然而,當消息積累太多,而server還有資源可以處理的更快,它可以使用同步message消費者來加快速度。所以使用這些消息消費者模式可以讓你的應用將速度控制在它可以承受的范圍。
許多消息消費者模式都是成對出現的,你可以任選一個使用。
同步或異步接受者 - 可以使用輪詢消費者或一個事件驅動消費者。輪詢提供最好的流量控制,因為如果server忙,則它不再繼續輪詢消息,所以message將阻塞在隊列。事件驅動的消費者傾向于消息到達便觸發處理,所以有可能會使server超載,但是每個消費者每次只處理一個消息,所以限制消費者的數量可以有效的控制消費速度。
消息分派 vs 消息獲取 - 另外一個二選一的模式是一堆消費者如何處理一堆消息。如果每個消費者獲得一個消息,他們可以并行的處理消息。最簡單的方法是Competing Consumers,也就是一個點對點的channel有多個消費者。每個都可能獲得任何消息;消息系統的實現決定那個消費者獲得消息。如果你想控制消息到消費者的匹配過程,使用Message Dispatcher。這時只有一個消費者接收消息,但是將委派消息到一個執行者去處理。一個應用程序可以通過限制消費者或執行者的數量來控制流量。當然,分派者Message Dispatcher也可以實現一個流量控制行為。
接收所有消息或者過濾 - 默認的,任何到達一個Message Channel的消息對于監聽著這個channel的Message Endpoint都是可用的。然而有些消費者并不打算處理channel上的任何消息,而是希望只處理其中幾種。這樣一個識別的消費者可以使用一個Selective Consumer來描述它將接收什么類型的消息。然后消息系統將只將匹配的消息對該接受者描述為可用。
當斷開連接的時候訂閱消息 - Publish-Subscribe Channels帶來的問題是,如果一個消費者感興趣一個channel,但是現在網絡是斷開的怎么辦?是不是一個未連接的應用將錯過發布的消息,即使它已經訂閱過該消息?默認的,是的,訂閱只對連接的訂閱者有效,為了使應用不會因為連接而錯過訂閱的消息,要使用Durable Subscriber。
等冪 - 有時一個消息可能被傳輸不只一次,可能因為消息系統不確定該消息是否已經被成功的傳遞過,或者可能因為Message Channel的QoS被設置較低來提高效率。另一面的,消息接受者認為每個消息只會被傳輸一次,并且當它們重復處理相同的消息,它們會出錯。一個Idempotent Receiver可以優雅的處理重復的消息,并且阻止它們引起接收者應用的發生錯誤。
同步或異步服務 - 另外一個選擇是一個應用應該暴露它的service為同步(RPI)還是異步的(Messaging)。不同的客戶端可能喜歡不同的方式;不同的環境可能需要不同的方式。既然很難選擇,就一起使用。一個Service Activator連接一個Message Channel到一個應用的同步服務以便當一個消息被接收,service就被調用。同步客戶端可以簡單的直接調用service;異步客戶端可以通過發送消息調用service。
Message Endpoint的相關主題
Message Endpoint的另外一個重要主題是很難同其他模式共同應用Transactional Client。Event-Driven Consumer通常不能適當的在外部控制事務,Message Dispatcher也必須小心的設計這個問題,Competing Consumers的事務也是個重大問題。最安全的使用Transactional Client是使用一個單獨的Polling Consumer,但是這不會是一個令人滿意的解決方案。
這里特別要提到應該會保證成功的JMS風格的MDB,EJB的一種。一個MDB是一個消息消費者,它即使一個Event-Driven Consumer又是一個支持J2EE分布式事務的Transactional Client,并且它可以作為Competing Consumers動態的池化,甚至作為一個Publish-Subscribe Channel。這是在一個自由的應用中實現這些是一個困難且乏味的組合,但是這個功能作為一個EJB容器的內建的功能被提供。(MDB框架如何實現的?本質上,容器通過一個動態改變大小的可重用的執行者的線程池來實現了一個Message Dispatcher,在那里每個執行者自己使用自己的session和事務來消費消息。)
最后,緊記一個單獨的Message Endpoint可以很好結合幾個不同的模式。一組Competing Consumers可以被作為Polling Consumers實現,同時也可以是一個Selective Consumers并且可以作為一個Service Activator調用一個應用的service。
一個Message Dispatcher可以是一個Event-Driven Consumer和一個使用Messaging Mapper的一個Durable Subscriber。無論一個endpoint實現什么模式,它總是一個Messaging Gateway。所以,不要考慮使用哪種模式 - 而要考慮如何結合他們。這是使用模式解決問題的魅力所在。
要實現一個Message Endpoint有很多選擇。Message Endpoint模式用于解釋這些選擇是什么以及如何最好的使用它們。