WebService的事務處理

由於這個問題討論起來內容比較多一些,因此另開一個話題。
 
    若是你只是要解決兩個系統之間的事務同步問題,能夠採用判斷服務是否成功的辦法來解決,即:
    
    * A系統開始本身的事務,處理本身的數據,而後。。。
    * 在提交以前調用B系統的服務。
    * B系統開始本身的事務B,在事務中處理數據,再提交事務。
    * B系統把本身事務的提交成功與否的信息作爲返回值回饋A系統。
    * A系統根據B的事務成功狀況決定本身的事務是否提交或是回滾。
 
    可是,在繼續深刻討論這個問題以前,先反問一個引申的問題:當分佈式系統之間,要進行事務控制的子系統不是兩個,而是N個時,若是進行事務控制?
 
    分佈式事務一直都是很難解決的問題。在面向DCOM的分佈式應用中,有一種分佈帶事務支持策略,大致的思路是採用兩段式事務提交的辦法,第一次提交是預提交,預提交以後是能夠回滾的。第二次提交是永久性的提交,提交以後就不能夠回滾。而且,若是預提交成功,第二次提交也必然成功,系統必須能夠保證這一點。
 
    這樣,當每一個系統都支持這種兩段式提交以後,就能夠採用這樣的事務管理:一個控制角色向每一個分佈系統提出執行要求,並要求完成第一次事務提交。當每一個系統的第一次提交都成功時,則要求全部系統完成最後的永久提交,可知此次的永久提交是確定能夠完成的,所以不需要再擔憂此次提交是否成功。
    若是第一次提交中,有某些應用出現失敗,則要求全部的應用都回滾事務。
    一些數據庫軟件自己就支持事務嵌套,如sqlserver等,不幸的是,咱們的主力數據庫informix不支持。
    爲了簡化這種分佈式事務管理,有一些中間件產品能夠採用,用得比較普遍的是MS DTS.
 
    你可能已經看出來了,這樣的事務控制策略雖然能夠在分佈式環境下知足事務的ACID要求,可是它對各個分佈組件是有要求的,在基於COM, remoting,JRMI一類技術的分佈式應用程序中,這個沒有問題。可是在採用web service的場景中,這是有問題的。
 
    問題1. web service是一種以鬆耦合爲指導思想的集成方式,通常狀況下,主張採用無狀態方法。
    webservice主張兩次調用之間沒有上下文關係,即一次調用與其餘以前和以後的調用都沒有關係,一次提交即完成一次完整的處理。可是分佈式事務卻要求各方要在兩次對話之間保持對話狀態,以便於知道本次永久性提交時,要對以前「哪個」已經被預提交成功的事務執行最後的提交。
    當遇到這個問題時,咱們必需要再多問本身一個問題:咱們已經選擇了正確的集成技術嗎?若是多個系統之間有如此緊密的事務耦合關係時,我很懷疑它們其實就是同一個應用系統。同一個應用系統中,應該有相同的平臺,相同的進程空間,相同的數據模型以及數據源。這種狀況下,採用web service是一種錯誤的選擇,web service應該用於不一樣平臺、不一樣應用、不一樣的數據模型的系統集成。即使是的確須要在同一個應用系統中因爲某些緣由而實現模塊間的分佈式構造,也應該採用同一技術平臺內的遠過程訪問技術,它們能一般比web service能提供更好的耦合性支持。
 
    好吧,假設你通過思考以後,對上述問題的回答是「是」:咱們確實必需要在異構的、多平臺的、原本應該是低耦合系統之間實現分佈式事務控制。那麼,webservice還有用處嗎?
    謝天謝地,web service雖然主張交互之間採無狀態方式,可是它並非禁止採用有狀態的交互。WEB SERVICE仍是一種web技術,而web技術中的狀態保存多是最先被解決的問題之一了。在全部的web開發技術平臺中,都有session機制,不管這些Session是經過IP,cookies, hidden input來實現,仍是url sessionid來實現的,反正都有辦法實現,請參閱所用平臺的session支持機制就能夠了。退一萬步,你也能夠經過在服務器中維護一個應用程序級的事務池來實現,未最後提交的事務對象都放在裏面,每個事務對象都給定一個惟一個的標誌ID來識別,造成一個字典對象池。若是啓動事務成功,則把此事務的ID返回給調用者執有,作第二段提交時,把事務的ID作爲參數提交就是了。(隨便提一下,用這種方法時,千萬不能把對象的指針、句柄、引用什麼的平臺相關的值交給客戶方,倒不是懼怕安全問題,而是這些值在分佈系統中是沒有意義的,上次返回的指針沒準早被垃圾收集機挪到其餘地方去了)
 
    不管如何,webservice在通訊層上是一種無鏈接的協議,每兩次調用之間,tcp鏈接是斷開的,所以,一但採用session機制來管理上下文,你就必須爲這些session的生命期負責。試想,若是一個事務上下文已經開啓,而此時客戶方系統卻忽然當機了,這時會出什麼事情?在同一個應用程序域中,客戶方的當機會讓鏈接中斷,服務器當即就會中斷並回退事務,可是在webservice裏,狀態管理機沒法當即感受到此事務的調用方已經失去控制,只能在必定的時間以後,才發現:「噫?這個事務已經N長時間沒有人訪問了!快快回退!」在ASP.net裏,默認的狀態超時時長大概是20分鐘,JSP也差很少,阻塞了20分鐘的事務對數據源是什麼影響可想而止!所以,必須考慮合適的狀態時長與事務隔離級別,以減少對數據源的性能影響。       
 
    問題2. web service的「反模式」方法論使得沒法在系統之間統一出共同的抽象接口。
    web service是一種「反模式」的系統架構思想,即不是通常的由先建模並抽象接口開始,再由各個分佈系統實現接口的系統構造方式,而是反過來:系統可能早已經完成,如今的問題是兩個系統間的信息交互做用,所以交互的接口規格是根據須要,把系統數據模型去範式化後挑挑撿撿而定的。
    所以,webservice中不支持接口抽象,即:你沒法定義一個各個系統都必須實現的抽象事務接口,而後由各個系統實現這個接口的多態,最後在承擔事務控制器的應用中調用統一事務接口以調度分佈事務。雖然這樣的接口模型在不少面向對象的開發平臺中的遠過程調用技術中所支持,可是如同以前說過的,web service是一種用於集成的鬆耦合的反模式方法論,而不是爲緊耦合系統中的分佈式對象而設計的。
    因此,雖然有點討人煩,可是我又一次忍不住想問我已經問過的那個問題:咱們真得用對了技術嗎?若是多個系統之間須要如此級別的接口耦合性,我真得愈來愈懷疑它們其實就是同一個應用系統了。
    假設你的回答仍是「是,他們真得不是同一個系統,他們是異構平臺的,異構數據的!」好吧,那麼繼續。讓咱們採用web service來完成集成,可是你必須忘記你的OOP思想,老老實實地編碼,用枯燥的、重複的代碼把全部的系統的事務都控制在一塊兒,別想用對象抽象的概念來省一點事。
    真的嗎?
    若是把事務控制器獨立出來如何?假設咱們創建一個專用於分佈式服務控制的應用,而用WEB SERVICE的方式公佈接口, 容許其餘應用程序經過向這個事務控制器註冊本身的兩段式事務開啓、提交和回退的web service接口。而後,當有客戶想啓動分佈事務時,就能夠向這個事務控制器發起分佈式事務請求,選擇事務各方,啓動一個分佈式,最後向事務控制器,而非是各個事務方直接發起提交請求,這樣事務控制的多態就能夠在事務控制服務器中實現,雖然實現可能仍是經過查表等方式實現,而非平臺級的抽象方法,可是對於事務客戶來說,這樣一個服務器就是多態的實現部分。
    若是真得比MS更快更好地實現這樣一個web service作接口,面向異構系統的分佈式事務控制器,NASDAQ也許會有你的一席之地吧!
 
    問題3. 異構平臺不必定都支持兩段事務提交模式。
    web service面向的是徹底異構平臺的集成,那麼顯然不能期望每一個平臺都能支持兩段時提交事務模式。可是,標準就是標準,協議就是協議,標準就是用來讓你們遵照的,若是一個平臺原本不支持兩段式事務,那麼爲了能支持分佈式事務,它就必須改造以實現兩段式事務提交。
    怎麼改造是各個應用系統內部的事情,爲了本文討論的全整性,也在這裏稍微涉及一下。
    首選的方式是經過數據緩存的方式來實現。不少OO系統中,都採用了所謂的N層架構,即把業務對象與關係表模型分離開來,業務對象位於系統內存或是緩存中,由運行時的對象容器管理,容器根據必定的策略,把緩存中業務對象向數據庫這樣的久永介質中保存,或是從數據庫中加載所須要的業務對象,在保存和加載過程當中,將完成對象到表數據的轉換,或是相反。 web

    通常的N層結構的中間件產品中,都會提供兩個級別的事務,即面向緩存中對象的事務控制和麪向持久化過程的事務,能夠考慮簡單地將此兩個事務級別對應的分佈事務中的兩段事務提交。可是,這種方式必須冒必定的風險,如對象容器級的事務成功,而數據庫事務提交時出現失敗,此時將會致使的數據不一致的風險,儘管這個概率並不很大。 sql

    在使用數據容器的狀況下,也能夠用保存對象的歷史狀態來實現事務的手工回退。由於在業務對象層與持久化層相分離以後,持久化層在數據更新時並無複雜的邏輯,只是一些被羅列的、業務意義無關的數據更新序列。若是能夠保持對象的狀態歷史,那麼就能夠在須要的時候將對象的狀態恢復到舊的舊版上。實際上,在一些出色的中間件平臺中,這個機制已經實現得很是完善了。(能夠參閱Graphtalk平臺的對象持久化管理,簡直是天才!) 數據庫

    另外一種笨辦法是經過數據邏輯來實現兩段事務提交,例如在要求第一次提交時,即真正提交,在第二次提交時固定什麼也不作,而返回正常。若是要求回退,那麼就經過數據邏輯或是業務邏輯來更新數據爲舊狀態。這種實現方式絕對是很使人頭痛的。 緩存

    不過,幸好咱們不是在爲一個通用的數據庫設計兩段事務機制。要知道,面向服務的事務處理並非如同數據庫級別的事務那樣,在事務的期間數據的操做有無窮的可能性。一般咱們一個服務就是一個功能,其數據操做過程當中,數據的變化方式是可預知的,所以恢復數據的狀態也是一個個具體而固定的過程,只要咱們針對每個服務操做設計數據恢復機能就是了。 安全

    最後,若是這些都不可能實現的話——大於50%的可能性,由於時間、成本、技術等緣由,這些都實現不了,那麼只能靠兩個字了:妥協。 服務器

相關文章
相關標籤/搜索