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