當前位置:工程項目OA系統(tǒng) > 泛普各地 > 河北O(jiān)A系統(tǒng) > 石家莊OA系統(tǒng) > 石家莊OA信息化
Web Service Case Study: 事務性Web服務
Web Service Case Study: 事務性Web服務
柴曉路 (fennivel@uddi-china.org)
Chief System
Architect
2002年4月26日
本文是Web Service Case
Study系列文章的第三篇。在這篇文章中,我將圍繞一個事務性應用展開討論,探討在Web服務環(huán)境中實現(xiàn)原先在數(shù)據(jù)庫層次或者對象層次中實現(xiàn)的事務特性。具體的,這里的應用實例是一個分布式的數(shù)據(jù)庫同步的應用,我們需要解決的是在多個分布在Internet上的同構數(shù)據(jù)庫完成增量式的基于事務的數(shù)據(jù)同步問題。
應用背景
以下描述中使用的地名、機構名和系統(tǒng)名稱純屬虛構,但是是從具體應用中抽象出來的。
Briliiance City是一個醫(yī)療保健公眾服務正處于建設中的城市。市政府的最終目標是將整個城市的醫(yī)療機構(包括綜合性大型醫(yī)院、專業(yè)醫(yī)院、分區(qū)醫(yī)院等)、健康保健機構(社區(qū)醫(yī)院、社區(qū)醫(yī)生)等等通過Internet聯(lián)系在一起,從而實現(xiàn)將市民的醫(yī)療記錄和健康保健記錄統(tǒng)一管理。具體的來看,這個公眾服務網(wǎng)絡最終需要具備以下特性:
一致的邏輯數(shù)據(jù):對于每個市民而言,他的醫(yī)療記錄和保健記錄在邏輯上由這個服務網(wǎng)絡統(tǒng)一管理,從任意的服務結點(任何醫(yī)療機構或是健康保健機構)獲得的個人數(shù)據(jù)都應該是一致的,也就是說,從邏輯上,整個服務網(wǎng)絡只有一個市民個人醫(yī)療保健信息數(shù)據(jù)庫,而所有的服務結點都是這個數(shù)據(jù)庫的客戶端應用。
優(yōu)秀的網(wǎng)絡環(huán)境的適應性:由于整個城市的基礎設置,尤其是網(wǎng)絡基礎設施尚不是非常出色,雖然每個機構都能夠連上Internet,但是除了一些比較大的機構,諸如綜合性大型醫(yī)院、專業(yè)醫(yī)院、社區(qū)醫(yī)院等能夠使用寬帶,并一直在線以外,相當多的機構還是在普遍使用撥號上網(wǎng)的方式。同時有些機構的上網(wǎng)方式是能夠獲得公網(wǎng)IP的,而有些則沒有公網(wǎng)IP。從系統(tǒng)的實現(xiàn)角度來考慮,我們的服務網(wǎng)絡需要滿足這些復雜的網(wǎng)絡環(huán)境。
機構系統(tǒng)的兼容性:由于服務結點的數(shù)量巨大,其使用的平臺和語言各不相同,這個服務網(wǎng)絡需要能夠容納所有類型的服務結點。
開放的界面和接口:由于這是一個公共服務,因此不僅個人用戶能夠方便地通過Web或者桌面應用查詢個人的醫(yī)療保健信息,同時也需要提供非GUI的交互界面,以便使企業(yè)應用或者其他政府應用可以使用這個醫(yī)療保健網(wǎng)絡服務所能提供的信息。
目前,在Brilliance City的東城區(qū),大部分醫(yī)療保健機構都采用了一家稱為Health
Inside的軟件公司的產(chǎn)品部署了各自的應用系統(tǒng),包括醫(yī)院信息系統(tǒng)、醫(yī)療保健系統(tǒng)等等。由于采用了同一家公司的產(chǎn)品,因此他們在底層數(shù)據(jù)層的設計是基本一致的,市政府打算以此為試點,如果應用情況良好再推廣到全市。
解決方案
根據(jù)整個服務網(wǎng)絡的應用背景,我們設計了這樣一個解決方案:一個分布式的醫(yī)療保健的信息服務網(wǎng)絡。具體描述如下:
數(shù)據(jù)邏輯集中,物理分布
在這個服務網(wǎng)絡中,數(shù)據(jù)仍然被保存在各個服務結點,對于這樣一個Internet環(huán)境下的應用而言,數(shù)據(jù)庫集中是無法想象的,Internet不可能永遠穩(wěn)定工作,其次如果采取數(shù)據(jù)庫集中,骨干網(wǎng)上的流量也是無法接收的。由于數(shù)據(jù)是物理分布的,而邏輯上只有一個合法版本的數(shù)據(jù),因此我們需要有跨結點的分布式數(shù)據(jù)同步機制來保障數(shù)據(jù)的一致性。
數(shù)據(jù)同步的事務性
當一個服務結點執(zhí)行了某個事務之后,為了完成數(shù)據(jù)同步,我們需要把這個事務在其他相關的服務結點上也同樣加以運行,由于數(shù)據(jù)之間具有關聯(lián)性,因此在其他結點上的運行必須同樣保證事務性。
通過交換中心的消息隊列傳輸
由于各個服務結點的聯(lián)網(wǎng)狀況比較復雜,很多結點都無法一直保持在線的狀態(tài),因此使用消息隊列來傳遞事務將比較有效。我們設置了一個用于交換事務數(shù)據(jù)的交換中心,在交換中心上為每個服務結點提供了in/out消息隊列。交換中心是部署在Internet主干上的,因此只要服務結點連上了Internet,就可以通過交換中心收發(fā)包含事務的消息。
從數(shù)據(jù)庫模式到邏輯數(shù)據(jù)模式
整個系統(tǒng)的實施將分布走,首先先將服務網(wǎng)絡覆蓋到Health Inside的客戶,此時由于所有服務結點都是同構系統(tǒng),因此我們一開始事務是基于數(shù)據(jù)庫模式的,也就是歸根于數(shù)據(jù)庫表記錄的增刪改等。隨后將慢慢地延伸到其他公司的產(chǎn)品或解決方案,此時基于數(shù)據(jù)庫模式的事務將不在有效,需要就市民的醫(yī)療保健記錄及其操作制訂基于XML的業(yè)務事務規(guī)范,所有的事務都將基于這樣的格式進行傳播,此時在各個服務結點就需要有一個從基于數(shù)據(jù)庫模式的事務到基于XML數(shù)據(jù)模式的業(yè)務事務。為了在這個轉換過程中減少代價,降低風險,我們在一開始的基于數(shù)據(jù)庫模式的事務消息交換時,同樣使用XML來描述事務,使用Web服務架構來構建交換中心。如此,待服務網(wǎng)絡向其他類型的系統(tǒng)延伸的時候,對于服務網(wǎng)絡而言,基本無需更新,工作量集中在每個服務結點的數(shù)據(jù)庫模式向業(yè)務模式的轉化,以及服務結點接入服務網(wǎng)絡兩大塊。前者是面向業(yè)務的,工作量無法節(jié)約。而后者由于采用了Web服務架構,可以通過Web服務的規(guī)范協(xié)議方便地構筑系統(tǒng)交互。
基于數(shù)據(jù)中心的公共界面
在這個服務網(wǎng)絡中,除交換中心外,我們還設置了一個數(shù)據(jù)中心,設置的目的是多方面的。第一個目的是為統(tǒng)一管理市民的基本信息,從這個意義上將,數(shù)據(jù)中心也是一種服務結點,在數(shù)據(jù)中心上對市民信息進行更新,同樣需要通過數(shù)據(jù)同步和消息隊列的機制將這一更新事務傳遞到其他相關的服務結點。第二個目的是為對外的面向市民、面向企業(yè)的公共服務提供數(shù)據(jù),如此就無需在運行時刻頻繁地對各個服務結點進行數(shù)據(jù)請求。同時,當某個服務結點崩潰,需要重建的時候,可以從數(shù)據(jù)中心下載所有其管理和使用的數(shù)據(jù)。
體系架構
Figure 1. 體系架構圖示
這個服務網(wǎng)絡的基本體系架構可參見上圖。其技術核心就是各個服務結點之間的數(shù)據(jù)同步事務的實現(xiàn)。而這一機制的實現(xiàn),在服務網(wǎng)絡的第一期目標下,基本可以歸結為兩點:
數(shù)據(jù)庫事務的XML表示
在Web服務環(huán)境下事務性的保證
數(shù)據(jù)庫事務的XML表示
由于在第一期工程中,所有的服務節(jié)點是同構系統(tǒng),使用了相同的數(shù)據(jù)庫結構,而且為了最大化地減小每個服務節(jié)點的實現(xiàn)代價,因此我們采用了完全基于數(shù)據(jù)庫事務的數(shù)據(jù)同步方式。每條數(shù)據(jù)同步消息將包含一個事務(transaction)的描述,而一個事務可以包含多個操作(operation),每個操作要么是在某張表中更新(或添加)記錄,或是在某張表中刪除記錄。
根據(jù)這樣的設計思想,我們可以定義了transaction元素(包括其子元素)來表示一個事務消息,具體的Schema定義如下:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
targetNamespace="urn:dealeasy:webservice:exchange:schema"
xmlns="dealeasy:webservice:exchange:schema"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:complexType name="field">
<xs:sequence>
<xs:element name="name"
type="xs:string"/>
<xs:element
name="type" type="xs:string"/>
<xs:element name="value" type="xs:base64Binary"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="primaryKey">
<xs:sequence>
<xs:element
name="field" type="field" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="allField">
<xs:sequence>
<xs:element
name="field" type="field"
minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="save_data">
<xs:sequence>
<xs:element
name="tableName" type="xs:string"/>
<xs:element name="primaryKey"
type="primaryKey"/>
<xs:element
name="allField" type="allField" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="delete_data">
<xs:sequence>
<xs:element
name="tableName" type="xs:string"/>
<xs:element name="primaryKey" type="primaryKey"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="operations">
<xs:sequence>
<xs:element
name="save_data" type="save_data"
minOccurs="0"
maxOccurs="unbounded"/>
<xs:element
name="delete_data" type="delete_data"
minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="transaction">
<xs:sequence>
<xs:element
name="operations" type="operations"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
在這個模式定義中,核心是對數(shù)據(jù)的操作,這里為簡便性起見,僅僅定義了兩個操作save_data和delete_data,這也是符合國際慣例的定義。理由是,新增數(shù)據(jù)(記錄級)和更新數(shù)據(jù)(記錄級)可以使用相同的調用。相似的模式定義我在本系列的第一篇文章中已經(jīng)提及。
這里采用的描述方法是針對通用的數(shù)據(jù)庫操作的,也就是說無論具體數(shù)據(jù)庫的結構如何,只要每個端系統(tǒng)都是相同的,那么這個消息模式就可以應用。在save_data元素下,包含了三個元素:
tableName,這個元素指明了需要操作的記錄所在的數(shù)據(jù)庫表(Table)的名字;
primaryKey,這個元素用于描述待操作的數(shù)據(jù)記錄(record)的主鍵,系統(tǒng)通過這個主鍵可以準確定位到需要操作的記錄(Record),如果沒有找到由該主鍵標識的記錄,那么對應的操作就是新增記錄(insert
record),如果找到了由該主鍵標識的記錄,那么對應的操作就是更新記錄(update record);
allField,這個元素用于描述待操作的數(shù)據(jù)記錄中除主鍵字段外的所有字段,值得注意的是主鍵字段也可以是多個的。
而對于delete_data,其結構與save_data是類似的,唯一的差別就是沒有allField元素,原因相信大家也很容易理解,在刪除數(shù)據(jù)時,只要知道主鍵就足夠了。
有了Schema的模式定義文檔,我們就能夠生成SOAP消息了,下面首先給出的是一個由單個save_data操作和單個delete_data操作組成的事務的例子。該事務從candidate_employee中刪除一條記錄,而在employee中添加了一條記錄。
<env:Envelope
xmlns:env="http://www.w3.org/2001/06/soap-envelope"
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding">
<env:Body>
<transaction:transaction
xmlns:po="Some-URI">
<operations>
<delete_data>
<tableName>candidate_employee</tableName>
<primaryKey>
<field>
<name>id</name>
<type>uuid</type>
<value>crystal</value>
</field>
</primaryKey>
</delete_data>
<save_data>
<tableName>employee</tableName>
<primaryKey>
<field>
<name>id</name>
<type>uuid</type>
<value>crystal</value>
</field>
</primaryKey>
<allField>
<field>
<name>name</name>
<type>string</type>
<value>Crystal
Zhuang</value>
</field>
<field>
<name>gender</name>
<type>string</type>
<value>female</value>
</field>
<field>
<name>email</name>
<type>string</type>
<value>crystalzh@email.com</value>
</field>
</allField>
</save_data>
</operations>
</transaction:transaction>
</env:Body>
</env:Envelope>
事務性的保證
由于我們使用Web服務架構來架構我們的交換中心。因此在我們定義好了事務消息的XML描述之后,就需要實施如何通過SOAP消息來傳輸所需要傳播的事務消息了。對于這個服務網(wǎng)絡而言,其核心問題就是要將服務節(jié)點的事務(目前是數(shù)據(jù)庫事務,以后將延伸到業(yè)務事務)在各個相應的服務結點上同樣以滿足事務性的條件下執(zhí)行。由于我們采用的是Web服務架構,Web服務架構的現(xiàn)有技術中尚未有正式的支持事務的規(guī)范或技術。因此在這部分,我們將首先圍繞當前這個服務網(wǎng)絡中的應用來討論Web服務的事務性,當解決了當前這個應用實例中的問題之后,我們將從通用全面的角度繼續(xù)考察更復雜情況下的Web服務事務性的保證。
最簡單的情況
如果我們在傳輸事務消息的時候,總能保證單個事務消息使用單個SOAP消息來傳輸?shù)脑?,那么這就是最簡單的情況。此時,SOAP僅僅是傳輸事務數(shù)據(jù)的機制,而并不包含事務控制的功能。
具體的流程可以描述如下:
服務結點A完成了數(shù)據(jù)庫事務T,事務處理模塊使用我們先前制訂的XML模式將事務T表示為XML格式T(XML)。
服務結點A的SOAP Service將T(XML)包裝在SOAP
Body里面,組成SOAP消息,向交換中心發(fā)送,此時消息在交換中心中位于服務結點A的"out"消息隊列中。
交換中心獲得服務結點A的"out"消息隊列中的事務消息,并分析出與之相關的需要實施事務同步的服務結點集合(假設在這里我們僅找到一個相關的服務結點B)。
交換中心將這則事務消息T(XML)復制到服務結點B的"in"消息隊列(當然也可以不復制,而采取指針的方式,不過采取這種方式的話,在維護方面的復雜度會有稍許的提高)。
服務結點B上線之后,檢查交換中心的消息隊列,獲得事務消息,在SOAP
Service中將T(XML)從SOAP消息中剝離并交給下層的事務處理模塊。
服務結點B的事務處理模塊將T(XML)通過XML解析,轉換成內(nèi)部的事務,并實施運行。
從單條消息到多條消息
然而,并不是在任何情況下,使用一條SOAP消息就能夠傳輸一則事務的。由于SOAP消息最終是要和某一種網(wǎng)絡協(xié)議進行綁定并在網(wǎng)絡上進行傳輸?shù)?,大多?shù)網(wǎng)絡連接很難保證在一個連接內(nèi)能穩(wěn)定地傳輸大量的數(shù)據(jù),比如HTTP,我們在下載/上傳大文件的時候,經(jīng)常會發(fā)生中斷,此時我們就不得不重傳(HTTP沒有斷點續(xù)傳),重傳需要耗費同樣長的時間,同時傳輸時間越長發(fā)生錯誤的可能也越大,因此傳輸大文件如果不加以特別的措施的話,常常會變成一場噩夢。我們通常的方法,是將大文件分割成多個小塊,分別傳輸,等全部傳輸完畢后在對等方組合。由于單個文件塊比較小,傳輸穩(wěn)定性得到了提升,同時即使傳輸失敗,重傳的話也比較快。
我們將這一用于文件傳輸?shù)姆椒ǎ由斓绞聞障⒌膫鬏斨?,由于這是一個平臺級的特性,因此我們按照SOAP規(guī)范的推薦,使用SOAP Header來控制事務消息的合并執(zhí)行,同時為了提高響應率,我們的算法并不一定要等到關聯(lián)單個事務的消息全部收到才會執(zhí)行事務,我們采取了一定地提前執(zhí)行的機制,具體細節(jié),我將在下面詳細闡述。
首先我們給出transactionControl這個SOAP Header Extension的模式定義。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="transactionControl"
type="transactionControl"/>
<xs:complexType
name="transactionControl">
<xs:sequence>
<xs:element
name="simpleTransaction" type="simpleTransaction"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="simpleTransaction">
<xs:sequence>
<xs:element
name="transactionID" type="xs:string"/>
<xs:element name="begin" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element
name="commit" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element
name="rollback" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element name="part"
type="xs:integer" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
在這個模式定義中,我們看到transactionControl這個SOAP Header Extension包含了一個子元素simpleTransaction,我們在下面就使用這個子元素來描述事務消息,為是么不直接使用transactionControl元素,而要在其下再定義一層子元素,是為了以后對事務控制特性進行進一步的擴展,我們會在這基礎上實現(xiàn)兩階段提交和三階段提交等。
simpleTransaction元素包含了五個子元素:transactionID、begin、commit、rollback和part。他們的含義分別如下:
transactionID:事務的標識ID,兩個描述事務的SOAP消息當切僅當具備相同的transactionID時,我們才認為他們是一個事務的兩個組成部分。
begin:表示事務可以開始執(zhí)行。
commit:表示事務可以提交。
rollback:表示事務可以回滾。
part:這是一個整數(shù)類型的值,表示SOAP
Body中的內(nèi)容是當前事務的第幾個部分,整個事務應當按照part值所描述的順序依次執(zhí)行。
由于這五個子元素可能同時出現(xiàn)(rollback和commit不會同時出現(xiàn)),當服務結點接受到事務消息時,上述的五個子元素被解釋執(zhí)行的先后次序為:transactionID、begin、part(觸發(fā)解析SOAP
Body)、commit & rollback。他們的工作原理可描述如下:
當服務結點受到一個事務SOAP消息之后,首先解析出transactionID,如果是新的transactionID,那么在服務器端的事務池中,新建一個事務,并將transactionID賦予之。如果事務池中已經(jīng)有了這個transactionID,那么就將這個事務消息與之關聯(lián)。當完成transactionID的識別之后,如果消息中帶有begin,那么就啟動這個被關聯(lián)的事務池中的事務。如果消息中帶有part,假設part的值為n:
將當前消息的SOAP Body作為事務的第n部分存入事務的緩存控件;
檢查當前事務的緩存空間,如果發(fā)現(xiàn)已經(jīng)包含了1到m之間所有的事務部分,那么就依次執(zhí)行從1到m之間所有未執(zhí)行的事務部分。
如果消息中帶有commit,那么在緩存事務部分的時候(這一定是最后一個事務部分),對其加上標志:"這是該事務的最后一個部分"。當該部分被執(zhí)行時,整個事務將被提交。
如果消息中帶有rollback,那么對應的事務被立即回滾,然后該事務失效,如果之后仍然收到該事務空間中的消息的話,服務結點將丟棄這些消息。
例如:服務結點可能以如下次序接受到關聯(lián)同一事務的事務消息:
[part(2)], [part(4)], [begin,part(1)], [part(3)], [commit, part(6)], [part(5)]
那么服務結點的動作序列應當為:
接收到[part(2)],在事務池中創(chuàng)建一個事務空間,并緩存該事務部分,現(xiàn)在緩存為(2);
接收到[part(4)],緩存該事務部分,現(xiàn)在緩存為(2, 4);
接收到[begin,part(1)],啟動事務,緩存該事務部分,現(xiàn)在緩存為(1, 2, 4),事務1,2兩個部分被執(zhí)行;
接收到[part(3)],緩存該事務部分,現(xiàn)在緩存為(…, 3, 4),事務3,4兩個部分被執(zhí)行;
接收到[commit,
part(6)],緩存該事務部分,現(xiàn)在緩存為(…, 6),同時第6部分被置commit標志;
接收到[part(5)],緩存該事務部分,現(xiàn)在緩存為(…, 5, 6),事務5,6兩個部分被執(zhí)行,然后事務被提交。
在這一節(jié)中介紹的方法解決了在分布式的環(huán)境中,在單點數(shù)據(jù)庫中完成了事務的執(zhí)行。這個機制有效的解決了我們這個服務網(wǎng)絡應用實例的當前需求。
然而,我們考慮到,在將來整個服務網(wǎng)絡將向公眾開放,包括個人用戶和企業(yè)用戶在內(nèi)的各種用戶都可以訪問和使用服務網(wǎng)絡。雖然一開始只有一些數(shù)據(jù)查詢的事務開放給他們使用,不過隨著整個服務網(wǎng)絡的成熟,我們將會在數(shù)據(jù)中心層次上對外提供業(yè)務處理服務,而這些服務被使用時,勢必發(fā)生一些業(yè)務事務,根據(jù)整個服務網(wǎng)絡的設計原則,這些業(yè)務事務需要在整個服務網(wǎng)絡上被執(zhí)行,在這種情況下,與前面我們介紹的單個事務的重復廣播有所不同,這里發(fā)生的是一個涉及到多個服務結點的分布式事務。例如:這個事務可能同時涉及某個市民的醫(yī)療記錄和保健記錄,而這兩者分別是由兩個服務結點來管理的。前面的機制已經(jīng)無法解決這一問題,下面我們將兩階段提交協(xié)議(2PC)引入到我們的Web服務環(huán)境中來,以嘗試解決這一分布式事務的問題。
兩階段提交(Two-Phase Commit)
兩階段提交。分布式系統(tǒng)中處理用戶提交的事務時,事務管理器通常使用兩階段提交協(xié)議保證所有操作所涉及到的分布式環(huán)境中的各個數(shù)據(jù)庫中的相應數(shù)據(jù)被鎖定從而最后被正確地更新。如果因為某種原因操作不能完成,則要求統(tǒng)一執(zhí)行"回滾"操作,回到事務開始前的狀態(tài)。如果事務被成功執(zhí)行,那么所有相關的數(shù)據(jù)庫都被正確更新,此時這些更新應當被分布式環(huán)境中的所有數(shù)據(jù)庫系統(tǒng)都了解。最后解除相關數(shù)據(jù)庫重相關數(shù)據(jù)的鎖定狀態(tài),以便進行下一個事務的執(zhí)行。
以下我們描述一個擴展的兩階段提交的協(xié)議過程(這個擴展的2PC比標準的2PC多了預先準備的三個步驟,也被稱為3PC):
事務管理器部署在中央服務器上,它處于中心控制結點的位置,以事務發(fā)起者的身份開始工作,它首先在事務管理器日志中寫入一條"Prepare
Transaction"的記錄,然后將相應的事務請求發(fā)送到所有相關的服務結點(需要執(zhí)行事務的部分)上。
當每個參與事務的服務結點接收到"Prepare
Transaction",服務結點可以按照自己的負載狀況選擇是"Accept"還是"Reject",并將"Accept"或"Reject"消息發(fā)回事務管理器。
當事務管理器收到所有服務結點的響應后,如果全部都是"Accept"消息,那么繼續(xù)下一步。如果至少有一個服務結點返回的是"Reject"消息,那么這個事務將不會真正開始,事務結束。當然,在處理"Reject"消息的時候,可以有一些優(yōu)化的方法,我們可以在收到第一條"Reject"消息的時候,即時將事務結束(當然也可以選擇緩存在隊列里,等過一段時間后重試),并且丟棄以后收到的和這個事務相關的"Accept"或"Reject"消息。
當所有服務結點發(fā)回"Accept"消息后,事務管理器準備真正開始執(zhí)行事務。它在事務管理器日志中寫入一條"Begin
Transaction"的記錄,然后將相應的事務執(zhí)行內(nèi)容發(fā)送給所有相關的服務結點。
各個服務結點將此事務寫入自己的日志,然后鎖定資源以供該事務使用,當資源準備完畢后,服務結點向事務管理器所在的計算機發(fā)送"Ready"消息。
當事務管理器所在的中心控制結點接收到所有的"Ready"消息后(即參與事務的所有服務結點都必須發(fā)回"Ready"信息),它在日志上記錄"Commit
Transaction",要求該事務被提交,并通知所有相關的服務結點。如果在一定的時間內(nèi),至少有一個服務結點沒有返回"Ready"信息,那么它視該事務執(zhí)行失敗。將會在日志上記錄"Rollback
Transaction",并發(fā)送給所有服務結點,要求回滾事務,并將該事務結束。
當這些相關的服務結點接收到"Commit
Transaction"通知后,這些服務結點將自身承擔的事務部分提交(Commit),并解除對資源的鎖定,同時通知事務管理器執(zhí)行完畢。
如果服務結點接收到"Rollback
Transaction"通知后,這些服務結點將自身承擔的事務部分回滾(Rollback),并解除對資源的鎖定。
在這里,我們有兩個假設:
事務管理器總是工作正常的,否則服務結點在無限期等待事務管理器的"Commit"或"Rollback"消息時,將處于無法工作狀態(tài),因為服務結點是不能自主地選擇提交或是回滾的,否則就有可能與其他服務結點的數(shù)據(jù)不再同步。此時其他服務結點可能已經(jīng)提交或者回滾了。
當服務結點鎖定事務執(zhí)行時需要的資源,并且發(fā)送了"Ready"消息之后,我們只能認為他一定能完成事務的執(zhí)行,否則如果在提交階段發(fā)生錯誤,很可能其他結點已經(jīng)提交了,提交了的事務是無法回滾的。
在仔細地分析了兩階段提交之后,我們來擴展先前定義的transactionControl元素,為這個SOAP Header
Extension增加新的功能。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="transactionControl"
type="transactionControl"/>
<xs:complexType
name="transactionControl">
<xs:sequence>
<xs:element
name="transactionID" type="xs:string"/>
<xs:element name="simpleTransaction" type="simpleTransaction"
minOccurs="0"/>
<xs:element
name="twoPhaseCommitTransaction" type="twoPhaseCommitTransaction"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="simpleTransaction">
<xs:sequence>
<xs:element
name="begin" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element
name="commit" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element
name="rollback" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element name="part"
type="xs:integer" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="twoPhaseCommitTransaction">
<xs:sequence>
<xs:element
name="serviceNode" type="xs:string"/>
<xs:element name="prepare"
minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="request" type="xs:string" nillable="true"
minOccurs="0"/>
<xs:element name="response" type="xs:string"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element
name="begin" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="request" nillable="true"
minOccurs="0"/>
<xs:element name="part"
minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension
base="xs:integer">
<xs:attribute name="final"
type="xs:boolean"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="response" type="xs:string"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element
name="rollback" minOccurs="0"/>
<xs:element name="commit" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
simpleTransaction那部分基本上沒有什么大的變化,只是將transactionID提取到transactionControl下,以供公共使用。而twoPhaseCommit元素就是供我們描述的擴展兩階段提交協(xié)議使用。
twoPhaseCommit元素共有以下子元素:serviceNode元素、prepare元素、begin元素、rollback元素和submit元素。我們下面來分別講解這幾個元素的用途:
serviceNode元素:描述服務結點的標識,該元素的值唯一標識了一個服務結點。
prepare元素:完成"Prepare Transaction"階段的交互。事務管理器發(fā)出的"Prepare
Transaction"消息是使用prepare元素及其子元素request來表示,同時如果發(fā)往服務結點A,那么該消息中的serviceNode元素取值也應該是A。而服務結點對"Prepare
Transaction"消息的響應則是使用prepare元素及其子元素response來表示,具體的response元素的值是"accept"表示可以執(zhí)行事務,如果是"reject"則表示不能執(zhí)行事務。同樣,服務結點A發(fā)回的響應消息,則消息中的serviceNode元素取值也應該是A。
begin元素:完成"Begin Transaction"階段的交互。事務管理器發(fā)出的"Begin
Transaction"消息是使用begin元素及其子元素request來表示。事務管理器發(fā)出的描述事務內(nèi)容的消息應當使用begin元素的子元素part來表示,part中的數(shù)值為其在事務內(nèi)容消息序列中的序號,而此時SOAP
Body中的內(nèi)容就是相應的事務內(nèi)容。這一分塊傳輸?shù)臋C制與先前的simpleTransaction中描述的是類似的,其中最后一則消息分塊的part元素應當帶有值為"true"的final屬性(參照前面的模式文檔,part元素可帶有一個屬性final,
final的類型是xs:boolean)。當服務結點接收到所有的消息分塊后,即申請所有所需的資源,并使用begin元素及其子元素response來響應。如果資源申請成功,則response的值為"ready",否則則為"failure"。
rollback元素:如果某個服務結點返回的begin/response的值為"failure",那么事務管理器就需要向每個服務結點發(fā)送rollback消息。
commit元素,如果每個服務結點返回的begin/response的值都是"ready",那么事務管理器就需要向每個服務結點發(fā)送commit消息。
下面我們給出一個消息序列來解釋這些元素的使用方式,這個消息序列的應用背景是一個涉及兩個服務結點A、B的事務執(zhí)行。
未完待續(xù)
在本文章系列的第三篇中,我們借助一個服務網(wǎng)絡的案例來分析了Web服務事務性的實現(xiàn),前面我們討論了Web服務環(huán)境下的簡單的事務廣播,以及分布式事務的擴展的兩階段提交模型的實現(xiàn)。然而大家應該發(fā)現(xiàn),首先,這樣的模型僅僅適用于內(nèi)部網(wǎng)絡環(huán)境,因為其中缺乏必要的服務結點身份驗證,非法的消息可能會造成事務機制的崩潰。同時,在這里描述的事務相對而言還是短事務,而商務上對長事務的需求也是很多的。因此我們考慮了兩個方向的解決方案延伸:
安全性事務控制:所謂安全性事務控制,在我們在這個使用SOAP消息來描述事務控制的方案中,結合SOAP消息的安全擴展應當是一個比較有效的方式。Web Services Security(WS-Security)是一個SOAP Header Extension,為Web服務提供了一種保障服務安全性的語言。WS-Security通過消息完整性、消息機密性和簡單的消息認證來實現(xiàn)消息安全的目的。這些機制能夠被用來適應現(xiàn)有的大量的安全模型以及加密技術。WS-Security同時也提供了一個通用的機制用于將許可證(簽署了的信任聲明,如x509信任狀或者Kerberos tickets等)與消息關聯(lián),而不需要指定特殊的格式。我們可以嘗試使用這種技術來為事務控制提供安全性。
長事務支持:LRUOW(Long-running Unit of Work)模型是由IBM公司研究小組提出的一種擴展的事務模型。這個模型允許長時間運行的商業(yè)流程可以執(zhí)行多個事務性ACID步驟,同時保證整個處理流程的原子性和獨立性。每個LRUOW上下文創(chuàng)建一個版本空間(version space)。每個步驟都操縱版本化的對象(versioned object)。當進入一個LRUOW上下文時,對象的最初狀態(tài)與全局的版本空間相關聯(lián)。當一個LRUOW完成時,它的版本空間與全局版本空間重新協(xié)調(reconcile)。這個擴展的事務模型弱化了傳統(tǒng)事務特性,但提供模型應用者更多的適用性和靈活性。為使系統(tǒng)的并發(fā)事務不因長事務而被阻塞,這個模型不強制長時間運行的事務對訪問的對象加鎖,并允許因此引發(fā)的對象數(shù)據(jù)版本沖突由特定的應用程序方法解決。這個模型也允許單個子事務的失敗不強制整個事務的撤消,而允許應用程序采用補償事務修復失敗損失,然后讓這個事務繼續(xù)處理流程。這個模型還支持嵌套事務的提交與回滾。所以,這個擴展的事務模型可以適應企業(yè)內(nèi)部集成應用程序、以及企業(yè)之間集成Web服務的需求。我們嘗試將該模型應用到Web服務環(huán)境下去。
參考資料
- Web Service 技術/評論網(wǎng)站
- SimplePage.UDDI-China.ORG,
Web服務中文資源。
- UDDI-China.ORG,
以UDDI為主的Web服務技術網(wǎng)站。
- WebServices.ORG,
Web服務的綜合類技術網(wǎng)站。
- IBM
developerWorks/Web Service Zone, IBM的Web服務技術資源中心
- MSDN Online Web
Services Developer Resources, Microsoft的Web服務的開發(fā)者資源網(wǎng)站
- ITPapers/Web
Service, ITPapers的Web服務評論文章
- SimplePage.UDDI-China.ORG,
Web服務中文資源。
- 解決開放式應用交互和集成的Web Services系列技術標準規(guī)范
- WS-Security規(guī)范,
Microsoft, 2001
- WS-License規(guī)范,
Microsoft, 2001
- UDDI執(zhí)行白皮書,
UDDI-China.org, UDDI.org
- UDDI技術白皮書,
UDDI-China.org, UDDI.org
- UDDI程序員API規(guī)范,
UDDI-China.org, UDDI.org
- UDDI數(shù)據(jù)結構參考,
UDDI-China.org, UDDI.org
- Web
Service Description Language (WSDL) 1.0, IBM, 25 Sep 2000
- SOAP:
Simple Object Access Protocol Specification 1.1, IBM, Microsoft,
DevelopMentor, 2000
- XML Schema Part 0: Primer
, W3C, 2 May 2001
- Extensible Markup Language (XML) 1.0 (Second Edition), W3C, 6 Oct 2000
- WS-Security規(guī)范,
Microsoft, 2001
作者簡介
柴曉路: 上海得易電子商務技術有限公司(DealEasy)首席系統(tǒng)架構師、XML Web Sevices技術顧問,UDDI-China.org創(chuàng)始人,UDDI Advisory Group成員,IBM developerWorks專欄作家。2000年獲復旦大學計算機科學碩士學位,曾在國際計算機科學學術會議(ICSC)、亞太區(qū)XML技術研討會(XML Asia/Pacific'99)、中國XML技術研討會(北京)、計算機科學期刊等各類國際、國內(nèi)重要會議與期刊上發(fā)表論文多篇。專長于Web Services技術架構、基于XML的系統(tǒng)集成和數(shù)據(jù)交換應用及方法,同時對數(shù)據(jù)庫、面向對象技術及CSCW等技術比較擅長。
- 1架構Web Service:什么是Web服務?
- 2使用Visual Studio.Net建立web service
- 3Web Service初探
- 4石家莊OA信息化與知識價值鏈(BY AMT 夏敬華)
- 5我國商貿(mào)業(yè)將迎來新一輪的IT建設高潮
- 6ColdFusion MX增加對J2EE、XML和Web服務的兼容
- 7對某集團公司協(xié)同辦公系統(tǒng)未來3-5年的IT規(guī)劃建設藍圖
- 8BEA向Web服務互操作發(fā)展
- 9泛普OA軟件支持在線直接發(fā)送消息、傳送文件、音頻會話等
- 10Applying .Net to Web Services
- 11第五項修煉簡要目錄
- 12關于模型的簡單介紹!
- 13Web服務內(nèi)幕,第10部分:深入主題:可靠性和事務
- 14IBM WebSphere以最快速度部署開放的Web服務
- 15石家莊OA信息化的基本XML和RDF技術(四):問題跟蹤程序模式
- 16源天軟件為特優(yōu)仕照明實施協(xié)同辦公管理系統(tǒng)
- 17拐點之年:中國管理軟件行業(yè)2008大盤點
- 18BEA支持JAX-RPC標準
- 19Sun拒入“WS-I” 不想跟微軟IBM玩游戲
- 202009金和協(xié)同管理“破冰之旅”助企業(yè)安然渡冬
- 21創(chuàng)造性的Intranet:Factors for Corporate Knowledge Creation
- 22架構Web Service:描述與注冊,發(fā)布Web服務
- 23Building an ASP.NET Web Service
- 24協(xié)同辦公OA軟件的常用資料和規(guī)章制度
- 25Web服務設計師,第2部分:動態(tài)電子商務模式
- 26Web服務內(nèi)幕,第6部分:承擔責任--實現(xiàn)WSFL中的角色
- 27有一個綜合性學術資源檢索站點,不錯!
- 28泛普軟件如何實現(xiàn)知識庫雙機熱備
- 29Building a Distributed Web Service Using a Strongly-Typed Da
- 30BEA榮獲最佳web服務產(chǎn)品獎
成都公司:成都市成華區(qū)建設南路160號1層9號
重慶公司:重慶市江北區(qū)紅旗河溝華創(chuàng)商務大廈18樓