本指南描述了服務總線(Aqualogic Enterprise Service Bus --- 簡稱:ESB)的一些典型使用場景、設計模式和實踐經驗。同時對于ESB上一些常見的問題予以解答。
本文的讀者應該已經了解ESB的基礎概念、進行了相關實踐,以及熟悉ESB的管理配置界面。
ESB提供了豐富的消息流程處理的模型,可以有多種方式來實現(xiàn)。因此需要有一個指導來表明在何時使用哪種方式比較適合。
路由節(jié)點(route node)是消息流樹上的一個頁節(jié)點。如果我們需要轉換成或需要轉換的消息格式依賴于目標服務,因此在路由節(jié)點(route node)或發(fā)布節(jié)點(publish node)中的請求/響應動作。在發(fā)布節(jié)點的操作中,任何請求過程中的數(shù)據轉換是發(fā)布動作目標服務所私有的。換一種方式講,當發(fā)布完成后,任何請求信息的改變會回滾到初始狀態(tài)。另一種請求動作是在outbound上下文變量($outbound)中設定控制變量來影響系統(tǒng)對于發(fā)送出去消息的操作(如:設定服務質量QoS等)。
如果轉換是在消息請求(或消息響應)過程中執(zhí)行,而不考慮路由終點,那么需要在請求(或響應)的管道中配置消息轉換。
例如,對于一個大批量的訂單,需要對收到的SOAP報文生成一個訂單匯總,并通過eMail發(fā)送給采購經理。為支持這種場景,在請求管道中需要包含一個發(fā)布動作。如果訂單很大,請求動作需要將該訂單轉換成一個訂單匯總,并將$attachments變量中的附件信息全部刪除
假設請求中附件信息的轉換不需要理會最終的路由節(jié)點,因此建議在請求管道中的一個階段(stage)將附件進行格式的轉換。
假設消息需要根據WS-addressing頭信息路由到兩個終點中的一個。其中第二個終點(Web Service)需要將SOAP消息體中的訂單轉換到一個新版本。此時,路由節(jié)點需要進行條件路由,以將信息發(fā)送到兩個終點中的一個,在第二個路由終點的請求動作中需要對訂單信息進行格式轉換。另外,如果該服務采用的是JMS方式發(fā)送,還可以在$outbound變量中設定QoS為“exactly once”。
如果一個代理服務提供的WSDL中包含多個操作,通常建議采用操作分支(operational branching)來對每個操作分別處理消息。
如果一個代理服務的類型是 Any SOAP 或 Any XML,就需要在階段動作中判斷消息具體類型,然后需要一個條件分支(conditional branching),通過條件分支節(jié)點來根據消息類型路由消息 。
條件分支可以用于代理服務的最外層,來對外提供路由選擇。例如:如果需要根據條件來調用服務A或服務B,上述動作如果不在路由節(jié)點中實現(xiàn)的話,就需要在消息流中配置條件路由。在每個分支中使用路由節(jié)點作為其子節(jié)點,這是一種典型的決策方式,但如果消息分支數(shù)量比較多的時候,配置每個分支中子節(jié)點的路由就不能算是一個好的方案了。
管道中單一的階段通常能夠滿足大多數(shù)使用案例。但是有些情況下,需要考慮多個階段動作(stage action)。
在一個階段中典型的動作包括:
ESB提供了三種差錯處理的選擇
通常情況下,最容易的差錯處理是在最低的級別進行捕獲,使用高級別的差錯處理來處理更普遍的差錯。但是對于inbound 的WS-Security 相關的差錯只能在服務層進行捕獲和處理。
如果輸入的消息是一種請求/響應型的消息,差錯處理還需要包括產生應答消息通過reply with failure動作發(fā)送回去。在HTTP方式,reply with failure會產生一個HTTP 500狀態(tài)信息。而在JMS方式,reply with failure會將JMS屬性JMS_BEA_Error設置成為ture。
如果服務是通過另外一個代理服務而調用的,其返回SOAP錯誤或傳輸錯誤,差錯處理管道會被調用。對于SOAP訪問,如果reply with failure動作被執(zhí)行,則系統(tǒng)會將最初的SOAP錯誤會返回給調用者。否則,系統(tǒng)錯誤處理機制會產生一個新的SOAP錯誤信息發(fā)送回去。代理服務可以識別SOAP錯誤,但它通常是不需要檢測消息(此種設計主要是考慮除非需要,可以盡量避免解析消息內容),因為HTTP返回狀態(tài)設定的不是200和202,或者JMS屬性JMS_BEA_Error設定為true。而對于非SOAP的消息,JMS_BEA_Error = true也會被設定以標識這是一個差錯響應。
通常情況下,明確的對可預期的差錯在管道之中進行處理是一個好的習慣,采用系統(tǒng)的差錯處理機制只可用于不可預期的差錯情況。
某些用例調用會報告一個錯誤,使用報告(report)動作可以處理此場景。例如:當請求管道報告消息以便跟蹤時,但在報告動作后,其路由節(jié)點中的服務調用失敗,報告消息只能解析為消息已經被提交處理。差錯處理中的報告處理失敗只能進行補償操作,當有人在管理控制臺中使用報告系統(tǒng)可以跟蹤該消息,判斷出最初提交的消息和其后續(xù)的差錯表明該消息沒有被正常處理。
服務總線支持各種類型的服務,包括Web Services(使用XML或WSDL中的SOAP綁定),以及各種非XML或其他通用的服務。
如果一個服務具備一個定義良好的WSDL接口,使用WSDL來定義服務。它具有以下可選的優(yōu)勢:
服務總線并不自動根據接口定義(WSDL或消息接口定義)來校驗服務發(fā)送或接收的消息。但是通過將服務接口定義放置到某一位置,在將來是可以通過打開開關方式來讓系統(tǒng)對消息進行校驗,雖然上述校驗的代價比較大。目前對于消息流的設計者使用校驗動作和XQuery條件表達式來在消息流中進行明確的校驗。
服務總線不自動做必須理解的SOAP消息頭的合法性校驗,而是可以在消息流中通過Xquery明確的進行處理。另外將來服務總線是可以增加選項來進行該項工作
當使用WSDL,在下述場景中,建議選擇WSDL Port方式來綁定服務而非直接綁定:
如果用戶希望暴露一個port給客戶端,以涵蓋后端各種企業(yè)應用,可以使用Any SOAP或Any XML服務類型。
如果消息(請求/響應)中至少一個類型不是XML,則使用 messaging service 類型定義服務。
對于整個流程,存在一個消息,該消息存在于$header, $body和$attachments變量中。即使服務類型不是SOAP方式,消息的規(guī)范模式遵循SOAP格式,在上下文中,消息的體現(xiàn)方式為SOAP格式。
$header 變量包含SOAP Header 元素, $body 元素包含SOAP Body 元素,而$attachments變量則封裝了附件,每個附件為一個子附件元素。附件元素包含body元素來表示真實的附件數(shù)據。
如果消息格式是二進制格式,$body變量中的Body元素包含一個XML的指針元素,它表示二進制數(shù)據內容的指針。而在二進制附件數(shù)據,附件元素中的body元素同樣包含數(shù)據的指針信息。
對于MFL格式的消息,$body 變量中的Body 元素則按照MFL文件所定義的XML格式體現(xiàn)。
對于文本數(shù)據,$body 變量中的Body 元素為文本。而對于文本格式的附件,$attachments變量中body元素為文本。
對于XML格式的附件,$attachments變量中body元素為XML。
下面給出了這些元素的格式定義,這些元素的命名空間為預先定義的”ctx” :
<element name="attachments" type="mc:AttachmentsType"/><!-- Each attachment in the 'attachments' variable is represented by an instance of this element --><element name="attachment" type="mc:AttachmentType"/><!-- Element used to represent binary payloads and pass-by reference content --><element name="binary-content" type="mc:BinaryContentType"/><complexType name="AttachmentsType"><sequence><!-- the 'attachments' variable is just a series of attachment elements --><element ref="mc:attachment" minOccurs="0" maxOccurs="unbounded"/></sequence></complexType><complexType name="AttachmentType"><sequence><!-- Set of MIME headers associated with attachment --><element name="Content-ID" type="string" minOccurs="0"/><element name="Content-Type" type="string" minOccurs="0"/><element name="Content-Transfer-Encoding" type="string" minOccurs="0"/><element name="Content-Description" type="string" minOccurs="0"/><element name="Content-Location" type="string" minOccurs="0"/><element name="Content-Disposition" type="string" minOccurs="0"/><!-- Contains the attachment content itself, either in-lined or as <binary-content/> --><element name="body" type="anyType"/></sequence></complexType><complexType name="BinaryContentType"><!-- URI reference to the binary or pass-by-reference payload --><attribute name="ref" type="anyURI" use="required"/></complexType>
另一個Xquery示例是獲取第二個附件中的訂單信息,這樣訂單的獲取為: $attachments/ctx:attachment[2]/ctx:body/*
assign data($header/wsa:MessageID) to variable idvar.
注意:如果有兩個WS-Addressing MessageID頭存在,變量中只包含第一個頭的信息。
服務總線設計是考慮到代理服務的接口和調用的業(yè)務服務的接口是不同的情況。因此,缺省它不會從輸入消息的上下文復制任何信息到輸入信息的上下文中(例如:transport header和JMS屬性)。
代理服務請求和響應的transport headers 是存儲于$inbound,而調用業(yè)務服務請求/響應的transport header存于$outbound變量中。
例如:對于單向的消息(交互而不需響應)的情況,XQuery可以將用戶定義的JMS屬性 從$inbound復制到$outbound:
Insert$inbound/ctx:transport/ctx:request/tp:headers/tp:user-header as first child of ./ctx:transport/ctx:request/tp:headers in variable $outbound.
很多情況下,用戶在使用產品時,需要了解該產品支持那種類型的消息可靠傳遞機制。
對于ESB而言,只有當輸入請求的傳輸協(xié)議是基于XA連接工廠的JMS方式,而且輸出服務的QoS(Qualify of Service)設定為exactly once (此種場景下的缺省配置),系統(tǒng)才實現(xiàn)消息的可靠傳遞機制。而對于其他場景下,消息可能會丟失或多次傳遞 。在$outbound變量中指定的QoS通常只是一個暗示,表明希望能夠實現(xiàn)可靠傳遞。對于exactly once 這種服務質量的實現(xiàn),系統(tǒng)會盡可能實現(xiàn)exactly once 的傳輸保障,其次它會盡可能提供at least once的傳輸保障,最后是沒有任何傳輸保障的方式。而此處所指的傳輸保障會有詳細的描述。
對于使用場景(請求輸入為 JMS/XA 而 QOS = exactly once),傳輸保障的提供機制如下:
如果一個路由節(jié)點或發(fā)布節(jié)點的輸出傳輸協(xié)議為JMS/XA,那么系統(tǒng)會確保消息從輸入通道到輸出通道的過程中只傳送一次,同時保障傳輸中消息不丟失或重復。而對于其他的傳輸協(xié)議(如:email, FTP, file, HTTP, HTTPS, JMS/nonXA),系統(tǒng)會確保消息從輸入通道到輸出通道的過程中傳送至少一次,同時保障消息的不丟失。
而對于HTTP(S)協(xié)議的消息傳輸至少一次還需要進一步的考慮。即使目標服務響應(正確的HTTP 狀態(tài)應答或錯誤應答),傳輸過程被認為已經結束。這是因為目標的服務已經返回信息,盡管是驗證錯誤或者頁面沒有找到,這表明目標服務所在的Server是可用的,而且服務是有可能可以處理其他消息的。如果消息傳輸過程中,代理服務器或者目標服務器宕機,則目標服務不在或者響應實踐超時,則消息會重新傳遞。
消息重發(fā)是基于輸入的JMS。重試的次數(shù)以及如果次數(shù)到了之后的處理可以在WebLogic Server的控制臺中配置(并不在Service Bus的sbsoncole中配置)。缺省的,服務總線創(chuàng)建的消息隊列,其重試次數(shù)為1,當重試次數(shù)到了之后,消息會被拋棄掉。
除了輸入JMS消息之外,還可以對目標服務訪問配置重試和負載均衡。負載均衡和容錯,以及重試連接的目的是為了提供高效訪問和高可用性支持。對于每個消息,URL列表會根據負載均衡的算法自動排列到容錯處理的隊列上。如果服務結束前,配置的訪問重試的次數(shù)為N, 如果出現(xiàn)狀況,整個訪問系列會重試N次,而在每次重試訪問之前,會等待所指定的重試間隔。當所有嘗試結束,如果仍存在錯誤,對于路由節(jié)點的差錯處理管道會被調用以進行后續(xù)處理。
對于 HTTP(S) 協(xié)議,任除了200和202之外的任何 HTTP狀態(tài)都會被認為是錯誤,并會重試。服務總線的錯誤處理機制的設計是盡量簡化、統(tǒng)一和安全的,因此在這樣的設計算法下,服務總線對于認證錯誤之類應答在一段時間范圍內是不會矯正該URL,另一方面,ALSB如果對于后續(xù)的訪問轉發(fā)的其他URL上,而新的URL也許不會產生類似的錯誤應答。
為了方便的與異構系統(tǒng)的互操作性,用戶可以控制消息所使用的內容類型(content type),JMS類型以及編碼類型。這是一個通用的使用狀況。
服務總線避免在服務定義時,對于外部客戶或服務需要或使用信息配置進行假設。這最大化保證客戶可以與各種不同的端點服務之間的互操作性。
服務總線繼承服務類型或接口調出消息的內容類型。內容類型是email或HTTP(S)協(xié)議的一個組成部分。
在代理服務調用一個業(yè)務服務時,內容類型可以在輸出上下文變量中覆蓋,也可以是代理服務應答時,覆蓋輸入上下文變量中所設定的內容類型。 例如:用戶可以通過設定outbound-request的Content-Type為“application/x-www-form-urlencoded“以保障傳輸HTTP POST請求到目標業(yè)務服務上。
對于JMS,除了二進制和文本,還有一個例外,JMS的類型可以在服務定義時候明確配置。
同樣的,編碼也可以在服務定義時,對調出消息的編碼明確指定。
一個通用的場景是客戶調用了一個代理服務,如Web Service或HTTP,而該Web Service后臺所調用的系統(tǒng)提供的是JMS請求/響應。這種場景稱為同步轉異步過程。反之亦然,稱為異步轉同步過程。
使用異步請求響應方式可以提供:
另一個要點是,異步服務需要一個關聯(lián)ID(correlation ID)來提供應答,關聯(lián)ID格式通常是一個內部格式,可以兼容如MQ或者是目標服務所使用MQ 本地接口。
異步請求/應答模式是被輸出傳輸通道所控制,消息流程(除了$outbound 變量中transport所指定的數(shù)據)是并不了解JMS請求/應答和HTTP請求/應答這兩種服務之間的區(qū)別。
對于一個使用JMS方式在Service Bus上交互的請求和應答消息,必須通過JMS Correlation ID屬性相互關聯(lián)。換句話說,所實現(xiàn)的業(yè)務服務中,在接收消息時必須需要使用getJMSCorrelationID獲取JMS Correlation ID, 而在消息發(fā)送到queue或topic之前,需要通過setJMSCorrelationID 來設定JMS Correlation ID。
消息接口(javax.jms.Message) 是所有JMS消息的根本接口,JMS消息頭包括了JMSCorrelationID 屬性字段來關聯(lián)不同的消息,JMSCorrelationID 可以保存一個提供者專用的消息ID,或應用專用的string對象或者byte[]值。
在接收消息前,可以獲取 JMSCorrelationID,發(fā)送消息前進行設定:
String getJMSCorrelationID():該方法返回JMS correlation ID 的值,可能是提供者專用的消息ID或是應用指定的String.
void setJMSCorrelationID(String correlationID):該方法用于設定JMS CorrelationID
而如果后端消息處理系統(tǒng)為MQ Series,或者其他的JMS服務器,需要遵循該消息處理器所提供的消息關聯(lián)機制,來設定消息關聯(lián)的ID。例如,如果消息服務提供者為MQ Series,其消息ID關聯(lián)的屬性字段為MessageID,相應的Java實現(xiàn)接口也變?yōu)閷essageID屬性的Get和Set操作了。
在代理服務無法確切的了解哪個服務被調用,但知道接口的類型,而服務的調用是在輸入的消息中所指定(服務接口類型可以被抽象化:命名消息類型、port類型和綁定信息,除了具體接口定義。具體的接口定義是表示服務具體位置的transport URL)
此種場景下,實現(xiàn)機制是注冊一個接口定義的業(yè)務服務(而transport URL的定義可以無關),流程中的路由或發(fā)布節(jié)點中,增加一個動作設定$outbound變量中的服務的URL信息,調用具體的服務,這可以使URL信息可以在運行狀態(tài)時提供,而無需在設計時指定。
Weblogic 8.1 提供一個所謂回調的概念。通常,具有回調接口的WSDL提供一個回調通知或具體的應答操作方法。回調地址在請求消息中的SOAP頭中包含。
為了支持與WebLogic Platform 8.1上的服務的互操作性,用戶可以進行如下配置:
服務總線關注于各種不同傳輸協(xié)議之間的路由消息,同時在處理過程中保障安全和格式轉換。因此它并不真正適合創(chuàng)建復雜的消息,服務協(xié)調和服務數(shù)據的匯總。BEA的其他產品如:Aqualogic Data Service Platofrom或WebLogic Integration更加適合。服務總線的代理服務可以調用Liquid Data 服務或workshop開發(fā)的JPD,反之,Data Service或JPD也可以調用服務總線的代理服務。
WScallouts 提供了服務協(xié)作、組裝和數(shù)據匯總的服務調用功能。但WScallouts的基本使用場景是:
作者簡介 | |
![]() 皮山杉 | 皮山杉是BEA系統(tǒng)(中國)有限公司高級技術顧問 |