在本地調(diào)用時(shí),清單3所示的服務(wù)接口可能能夠正常工作。不過(guò),如果服務(wù)是在遠(yuǎn)程位置向使用者提供的,則該服務(wù)在常見(jiàn)使用場(chǎng)景中的性能可能會(huì)很差。例如,在使用服務(wù)檢索數(shù)據(jù)來(lái)填充顯示書(shū)的目錄項(xiàng)的屏幕時(shí),將有必要進(jìn)行多個(gè)獨(dú)立的遠(yuǎn)程調(diào)用,以檢索書(shū)名、作者和出版日期。進(jìn)行這些調(diào)用可能會(huì)有很大的性能損失。遠(yuǎn)程服務(wù)應(yīng)提供粗粒度的操作,以在單個(gè)調(diào)用中檢索關(guān)于某本書(shū)的所有信息。
可遠(yuǎn)程調(diào)用的服務(wù)的這個(gè)設(shè)計(jì)原則得到了廣泛的認(rèn)可;我們?cè)诖颂帍?qiáng)調(diào)此原則的目的在于說(shuō)明被封裝的服務(wù)調(diào)用細(xì)節(jié)可能給我們?nèi)绾芜x擇設(shè)計(jì)方法帶來(lái)很大的影響。我們認(rèn)為,同步調(diào)用和異步調(diào)用之間的選擇也可能對(duì)服務(wù)接口設(shè)計(jì)有類似的影響。
這就引入了一個(gè)重要的問(wèn)題:設(shè)計(jì)服務(wù)時(shí),什么決定了所使用的調(diào)用方式?服務(wù)設(shè)計(jì)人員是否可以自由選擇本地調(diào)用和遠(yuǎn)程調(diào)用、同步調(diào)用和異步調(diào)用?我們建議 SOA 應(yīng)對(duì)這方面進(jìn)行說(shuō)明。我們提出此建議有兩個(gè)原因。首先,我們希望通過(guò)確保一致性提高易用性;編排流程時(shí),服務(wù)最好具有可預(yù)測(cè)的特征。其次,我們希望通過(guò)將使用者與提供者分離來(lái)提高靈活性。通過(guò)鼓勵(lì)進(jìn)行遠(yuǎn)程調(diào)用,我們可以進(jìn)行位置、平臺(tái)和編程語(yǔ)言分離。通過(guò)鼓勵(lì)進(jìn)行異步調(diào)用,我們可以分離使用者和提供者的可用性特征。
如果SOA要具有描述性,是否應(yīng)聲明所有服務(wù)都應(yīng)設(shè)計(jì)為允許遠(yuǎn)程、異步調(diào)用?我們建議對(duì)此描述性采用更為細(xì)粒度的方法?赡艿姆⻊(wù)類型包括提供業(yè)務(wù)相關(guān)較多的操作,如PlaceOrder,也包括技術(shù)性側(cè)重較多的操作,如CheckUserInRole。SOA完全應(yīng)該對(duì)不同的服務(wù)類別進(jìn)行不同的描述。我們預(yù)期將更多地調(diào)用與業(yè)務(wù)相關(guān)的操作,而技術(shù)操作完全可能采用本地調(diào)用的方式。
服務(wù)具有無(wú)狀態(tài)接口
我們?cè)诜⻊?wù)應(yīng)設(shè)計(jì)為可重用中提到,應(yīng)該將服務(wù)設(shè)計(jì)為可伸縮且可部署到高可用性基礎(chǔ)結(jié)構(gòu)中。此總體原則的一個(gè)推論就是,服務(wù)不應(yīng)為有狀態(tài)型的。即,它們不應(yīng)依賴于使用者和提供者間長(zhǎng)期存在的關(guān)系,操作調(diào)用也不應(yīng)隱式地依賴于前一個(gè)調(diào)用。為了說(shuō)明這一點(diǎn),我們以下面的電話轉(zhuǎn)換為例:
清單4. 有狀態(tài)轉(zhuǎn)換
Q:What is Dave’s account balance?
A: It’s £320
Q:What’s his credit limit?
A:It’s £2,000
此示例演示了轉(zhuǎn)換的兩個(gè)有狀態(tài)方面。第二個(gè)問(wèn)題通過(guò)使用“his”引用第一個(gè)問(wèn)題。這個(gè)示例中的操作依賴于轉(zhuǎn)換上下文,F(xiàn)在讓我們考慮一下所提供的應(yīng)答。請(qǐng)注意,響應(yīng)中沒(méi)有上下文信息。應(yīng)當(dāng)只有在詢問(wèn)者知道所詢問(wèn)的問(wèn)題時(shí),這個(gè)應(yīng)答才有意義。在此示例中,要求使用者維護(hù)對(duì)話狀態(tài),以便解釋所得到的應(yīng)答。這兩個(gè)有狀態(tài)關(guān)系(連續(xù)的調(diào)用之間和請(qǐng)求與響應(yīng)之間的關(guān)系)都與SOA服務(wù)設(shè)計(jì)有關(guān)。
首先,我們考慮一下依賴于前一操作建立的上下文的操作。假如這是一個(gè)與呼叫中心的交互。只要與同一個(gè)操作人員對(duì)話,對(duì)話就可以有效地結(jié)束。但我們假設(shè)呼叫被中斷了,如下所示:
清單5. 被中斷的有狀態(tài)轉(zhuǎn)換
Q:What is Dave’s account balance?
Operator 1: It’s £320
An interruption occurs, and the caller talks to a different operator.
Q:What’s his credit limit?
Operator 2: Who?
中斷導(dǎo)致上下文丟失,因此第二個(gè)問(wèn)題是沒(méi)有意義的。就這個(gè)電話對(duì)話而言,我們可以通過(guò)重新建立上下文而抵消中斷帶來(lái)的后果:“我在問(wèn)Dave的銀行帳戶的信息,您能告訴我他的信用額度嗎?”不過(guò),在可擴(kuò)展服務(wù)調(diào)用領(lǐng)域,有狀態(tài)對(duì)話通常更為麻煩,在此領(lǐng)域中,重新建立上下文可能在技術(shù)上不可行,或者可能帶來(lái)很大的性能開(kāi)銷。
通常,構(gòu)建可伸縮的可靠基礎(chǔ)結(jié)構(gòu)與允許有狀態(tài)交互之間有緊密的關(guān)系。創(chuàng)建支持有狀態(tài)的服務(wù)調(diào)用的SOA基礎(chǔ)結(jié)構(gòu)在技術(shù)上可行。可以使用的技術(shù)包括:
·使用Http Cookie維護(hù)會(huì)話上下文
·使用有狀態(tài)會(huì)話EJB;Bean的句柄在SOAP Header中傳遞
不過(guò),我們必須仔細(xì)考慮最終基礎(chǔ)結(jié)構(gòu)的可伸縮性和可靠性。是否要求使用關(guān)聯(lián)性?即,相同的使用者發(fā)出的連續(xù)請(qǐng)求是否必須交付到相同的提供者實(shí)例?要求使用關(guān)聯(lián)性是一種有狀態(tài)性與可伸縮性及可靠性沖突的情況。如果基礎(chǔ)結(jié)構(gòu)可以隨意將請(qǐng)求提交到多個(gè)提供者實(shí)例中的一個(gè),就可簡(jiǎn)化負(fù)載平衡,而各個(gè)提供者實(shí)例的可靠性要求就可緩和。
如果沒(méi)有關(guān)聯(lián)性需求,且允許基礎(chǔ)結(jié)構(gòu)將一個(gè)使用者的連續(xù)請(qǐng)求交付到不同的提供者實(shí)例,則任何會(huì)話狀態(tài)必須對(duì)所有提供者實(shí)例可用。應(yīng)用服務(wù)器基礎(chǔ)結(jié)構(gòu)提供會(huì)話復(fù)制機(jī)制。此類機(jī)制可以用于提供會(huì)話狀態(tài),但使用它們會(huì)有性能損失。而且,我們的Web開(kāi)發(fā)經(jīng)驗(yàn)表明,如果沒(méi)有可靠的指南,開(kāi)發(fā)人員將可以隨意使用會(huì)話狀態(tài);過(guò)度使用HTTP會(huì)話通常是導(dǎo)致性能低下的常見(jiàn)原因。請(qǐng)參閱“Performance Analysis for Java Web Sites”(作者:joines、Willenborg和Hygh,第59頁(yè)—60頁(yè),Addison-Wesley ISBN 0201844540)。
我們強(qiáng)烈建議,服務(wù)應(yīng)設(shè)計(jì)為可避免維護(hù)會(huì)話上下文的需求。
現(xiàn)在,讓我們考慮一下對(duì)話的其他有狀態(tài)方面以及請(qǐng)求和響應(yīng)間的關(guān)系。我們是否要采用上面的電話對(duì)話方式進(jìn)行服務(wù)設(shè)計(jì),依賴會(huì)話上下文來(lái)解釋響應(yīng)“What is Dave’s credit limit?”——“£320”——然后我們將對(duì)SOA基礎(chǔ)結(jié)構(gòu)再次進(jìn)行約束。
基礎(chǔ)結(jié)構(gòu)必須適應(yīng)各種可能性,如某些使用者無(wú)法在臨時(shí)停機(jī)的情況下保留其會(huì)話狀態(tài)。
我們可以通過(guò)將服務(wù)設(shè)計(jì)為在響應(yīng)中包含合適的關(guān)聯(lián)信息,從而避免會(huì)話狀態(tài)的需求,例如以下的響應(yīng):
清單6. 包含關(guān)聯(lián)信息的對(duì)話
Q: What is Dave’s credit limit?
A: Dave’s credit limit is £2000
該響應(yīng)既標(biāo)識(shí)人員又提供具體的數(shù)據(jù)。當(dāng)包裝遺留系統(tǒng)時(shí),通常由適配器負(fù)責(zé)提供此類關(guān)聯(lián)信息,F(xiàn)有同步API完全有可能不提供關(guān)聯(lián)數(shù)據(jù)。在響應(yīng)中包含關(guān)聯(lián)信息之所以是很好的做法,有很多原因。首先,它簡(jiǎn)化了彈性可伸縮解決方案的構(gòu)造,還能提供很大的診斷幫助,且在不可能向原始請(qǐng)求程序交付錯(cuò)誤響應(yīng)時(shí)非常重要。未交付的消息可能放置在錯(cuò)誤隊(duì)列上,每個(gè)此類消息的解釋都要求使用上下文信息。
總之,仔細(xì)地進(jìn)行服務(wù)設(shè)計(jì)可以避免對(duì)狀態(tài)對(duì)話的需求,從而簡(jiǎn)化可靠的可伸縮 SOA 基礎(chǔ)結(jié)構(gòu)的實(shí)現(xiàn)。
服務(wù)應(yīng)使用狀態(tài)事務(wù)建模
前面給出了一個(gè)總的建議,以避免依賴對(duì)話狀態(tài),但我們應(yīng)當(dāng)記住,有用的計(jì)算機(jī)系統(tǒng)通常將為有狀態(tài)的;通常反映了業(yè)務(wù)對(duì)象的生命周期。
例如,考慮購(gòu)物中的一個(gè)訂單的生命周期:創(chuàng)建訂單。從用戶的角度來(lái)看,創(chuàng)建了一個(gè)空的購(gòu)物車。用戶將隨后向訂單添加物品,即將其放入購(gòu)物車中。最后提交訂單,然后訂單將被傳送給配送部門(mén)。圖1顯示了對(duì)此生命周期建模的簡(jiǎn)化狀態(tài)轉(zhuǎn)換圖。
圖1. 訂單生命周期狀態(tài)轉(zhuǎn)換
該模型說(shuō)明了一些有狀態(tài)的行為。例如,我們看到,在處于Open狀態(tài)時(shí)可以向訂單添加行式項(xiàng)目,但在提交后就不能了。
讓我們考慮以下 Order 服務(wù)的設(shè)計(jì)。我們可以采用如清單7所示的接口。
清單7. Order服務(wù)設(shè)計(jì)
OrderService {
void addLineItemToOrder(int orderId, int productId, int quantity)
void assignOrderToPacker(int packerId)
int createOrder(int customerId) // returns id of new order
int packItemForOrder(int orderId, int quantity) // returns quantity left to ship
boolean shipOrder(int orderId) // returns whether all order is now shipped
void submitOrder(int orderId)
// ... query operations elided ...
我們要考慮此接口的易用性。(更現(xiàn)實(shí)一些,我們應(yīng)該考慮那些具有更多方法的完整接口,如用于列出和刪除行式項(xiàng)目的方法。)如果沒(méi)有狀態(tài)圖供參考,即使查看我們的這個(gè)小示例,也非常難于分清方法應(yīng)該按照何種順序進(jìn)行調(diào)用。因此我們認(rèn)為,服務(wù)設(shè)計(jì)人員必須進(jìn)行一定的工作,以簡(jiǎn)化使用者的任務(wù)。我們提供了一些可能的技術(shù)。
首先,考慮操作和參數(shù)的名稱。我們上面的示例中的名稱是經(jīng)過(guò)細(xì)心選擇的,并進(jìn)行一定的努力,以推導(dǎo)出方法的可能調(diào)用順序。請(qǐng)比較清單8和清單9中的示例,這兩個(gè)代碼片段幾乎完全一樣,只是操作和參數(shù)的名稱不同。
清單8. 不合理選擇的操作和參數(shù)名稱
ZettuylService {
int wibble(int wibId, int wobId, String which);
int wobble(int quibId);
boolean wrubble(int wibId);
void quibble(int widId)
void quash(int wibId)
Stuff[] getStuff(int wibId );
void quite(int wibId);
Things[] getThings(int wibId);
void hinge(int wibId, intwobId);
int henge(int wibId , Stuff someStuff)
}
清單9. 合理選擇的操作和參數(shù)名稱
ExpenseService {
int approveClaimItem(int claimid, int itemid, String comment);
int createClaim(String userId);
boolean auditClaim(int claimid);
void approveClaim(claimid)
void returnClaim(claimid)
ClaimItemDetails[] getClaimItems(int claimid );
void payClaim(int claimid);
ClaimErrors[] validateClaim(int claimid);
void removeClaimItem(int claimid, int itemid);
int addClaimItem(int claimid, ClaimItemDetails details)
}
清單8中的名稱都是難以理解的。而清單9中選擇的名稱說(shuō)明了服務(wù)的目的,并可以減少很多操作應(yīng)按特定順序調(diào)用的情況。例如,createClaim()將在approveClaim()前使用,而后者又將在payClaim()前使用。因此,正如我們?cè)谇懊娴拿⻊?wù)時(shí)應(yīng)以最大化易用性為目標(biāo)所指出的,名稱的選擇對(duì)易用性影響非常大。
其次,前面的Order的狀態(tài)轉(zhuǎn)換圖可清楚說(shuō)明訂單的有狀態(tài)行為。該圖提供了有用的說(shuō)明信息,顯示了訂單的狀態(tài)以及每個(gè)狀態(tài)中相應(yīng)的操作。
增加易用性的第二項(xiàng)技術(shù)是,要記住并非所有記錄的值都可以通過(guò)服務(wù)接口定義實(shí)現(xiàn)最佳的交付。記錄良好的WSDL文件很有價(jià)值,但一起提供的關(guān)系圖和示例也有很大的價(jià)值。
增加易用性的另一項(xiàng)技術(shù)是,創(chuàng)建反映業(yè)務(wù)對(duì)象生命周期的狀態(tài)的服務(wù)接口。在我們費(fèi)用申領(lǐng)示例中,每筆費(fèi)用申領(lǐng)的生命周期都包含四個(gè)狀態(tài),如圖2中所示。
圖2. expense對(duì)象的四個(gè)狀態(tài)
這些狀態(tài)之所以重要,有兩個(gè)原因。第一,每個(gè)狀態(tài)基本上都與不同的系統(tǒng)用戶相關(guān)。例如,當(dāng)費(fèi)用申領(lǐng)處于構(gòu)建(building)狀態(tài)時(shí),主要系統(tǒng)用戶是輸入費(fèi)用申領(lǐng)詳細(xì)信息的申領(lǐng)人,而在審核(auditing)狀態(tài)中,則是由具有批準(zhǔn)權(quán)利的人對(duì)費(fèi)用申領(lǐng)進(jìn)行檢查。
第二,主要狀態(tài)之間的轉(zhuǎn)換通常反映了不同IT系統(tǒng)之間的數(shù)據(jù)流。例如,在構(gòu)建(building)狀態(tài)期間,可以在用戶的工作站上使用一個(gè)瘦客戶端應(yīng)用程序來(lái)捕獲費(fèi)用申領(lǐng)。提交后,費(fèi)用申領(lǐng)將傳遞給費(fèi)用申領(lǐng)處理系統(tǒng),而當(dāng)?shù)玫脚鷾?zhǔn)后,費(fèi)用申領(lǐng)將傳遞給另外一個(gè)系統(tǒng),即支付系統(tǒng)。在傳遞過(guò)程中,我們需要提到的是,如果實(shí)現(xiàn)的確要將數(shù)據(jù)從一個(gè)系統(tǒng)傳遞到另一個(gè)系統(tǒng),則需要尤為注意負(fù)責(zé)在系統(tǒng)之間進(jìn)行傳輸?shù)牟僮鳎ㄔ谖覀兊氖纠袨閟ubmitClaim()和approveClaim())。它們的實(shí)現(xiàn)將需要對(duì)兩個(gè)系統(tǒng)進(jìn)行更新,而這樣很容易喪失兩個(gè)系統(tǒng)中任意一個(gè)的可用性。這些方法的實(shí)現(xiàn)將可以通過(guò)使用異步排隊(duì)機(jī)制得到改善。
由于業(yè)務(wù)對(duì)象狀態(tài)常常能同時(shí)反映業(yè)務(wù)和技術(shù)兩方面的內(nèi)容,因此完全可以將原始ExpenseClaimService拆分為適應(yīng)每個(gè)狀態(tài)的多個(gè)服務(wù)。我們可以得到如清單10中所示的服務(wù)。
清單10. 根據(jù)狀態(tài)劃分服務(wù)
ClaimEntryService {
createClaim(String userId);
ClaimItemDetails[] getClaimItems(int );.
ClaimErrors[] validateClaim(int claimid);
void removeClaimItem(int claimid, int itemid);
int addClaimItem(int claimid, ClaimItemDetails details)
int submitClaim(int claimid);
}
ClaimApprovalService {
int approveClaimItem(int claimid, int itemid, String comment);
void approveClaim(claimid)
void returnClaim(claimid)
ClaimItemDetails[] getClaimItems(int );.
ClaimErrors[] validateClaim(int claimid);
}
ClaimPaymentService {
void payClaim(int claimid);
}
通過(guò)這種方式,能更方便地理解每個(gè)服務(wù)。而且,將接口這樣劃分將可能非常適合服務(wù)(或服務(wù)集)的開(kāi)發(fā)、部署、維護(hù)和使用方式。這些服務(wù)很可能針對(duì)不同的使用者,可以由獨(dú)立的開(kāi)發(fā)團(tuán)隊(duì)進(jìn)行開(kāi)發(fā),可以分開(kāi)部署,因而具有分離的版本周期。換句話說(shuō),通過(guò)將重點(diǎn)放在對(duì)象生命周期上,我們就可以建立具有恰當(dāng)粒度的服務(wù)。
服務(wù)操作設(shè)計(jì)原則
前面我們討論了服務(wù)的總體設(shè)計(jì)方面的問(wèn)題,接下來(lái)就要討論一下各個(gè)服務(wù)操作的設(shè)計(jì)了。
操作表示業(yè)務(wù)動(dòng)作。
我們已經(jīng)指出,總的原則是,我們應(yīng)該優(yōu)先對(duì)服務(wù)和操作使用業(yè)務(wù)領(lǐng)域的名稱,使用動(dòng)詞作為操作名稱。對(duì)于操作,我們將這個(gè)建議進(jìn)一步深化:應(yīng)當(dāng)使用具體的業(yè)務(wù)含義而不是泛型操作對(duì)操作進(jìn)行定義。例如,不要使用泛泛的updateCustomerDetails操作,而要?jiǎng)?chuàng)建ChangeCustomerAddress、RecordCustomerMarriage和AddalternativeCustomerContactNumber之類的操作。此方法具有以下好處:
·操作與具體業(yè)務(wù)場(chǎng)景對(duì)應(yīng)。此類場(chǎng)景可能不僅是簡(jiǎn)單的更新數(shù)據(jù)庫(kù)中的記錄。例如,更改地址或婚姻狀況可以要求生成正式的文檔,而將要求系統(tǒng)記錄該文檔的詳細(xì)信息——或掃描版本。如果使用不太具體的操作(如updateCustomerDetails),則較難實(shí)現(xiàn)此類業(yè)務(wù)場(chǎng)景。
·各個(gè)操作接口將非常簡(jiǎn)單,且易于理解,從而提高了易用性。
·每個(gè)操作的更新單元得到了清楚的定義(在我們的示例中為地址、婚姻狀況和電話號(hào)碼)。在實(shí)現(xiàn)具有高并發(fā)性要求的系統(tǒng)時(shí),我們可以基于操作的要求采用更細(xì)粒度的鎖定策略,從而減少資源爭(zhēng)用。
操作應(yīng)采用粗粒度參數(shù)
在討論操作參數(shù)時(shí),同樣要面對(duì)粒度的問(wèn)題。請(qǐng)比較清單11和清單12中所示的createNewCustomer操作的兩個(gè)接口。
清單11. 采用細(xì)粒度參數(shù)的createNewCustomer操作接口
int createNewCustomer(String familyName,
String givenName,
String initials,
int age
String address1
String address2
String postcode
// ...
)
清單12. 采用單個(gè)粗粒度參數(shù)的createNewCustomer操作接口
int createNewCustomer( CustomerDetails newDetails)
清單11顯示了一個(gè)具有很多細(xì)粒度參數(shù)的操作。而在清單12中的操作則采用結(jié)構(gòu)化類型作為單個(gè)粗粒度參數(shù)。我們之所以建議使用粗粒度參數(shù),有兩個(gè)原因。首先,它們提供了創(chuàng)建靈活操作的機(jī)會(huì),支持在不干擾現(xiàn)有使用者的情況下提供新版本的操作。其次,具有大量類型相似的參數(shù)的操作易于在從第三代語(yǔ)言代碼進(jìn)行調(diào)用時(shí)出現(xiàn)轉(zhuǎn)換錯(cuò)誤。相反,當(dāng)數(shù)據(jù)放置在所使用的結(jié)構(gòu)化類型的顯式方法(如setGivenName()和setInitials())中時(shí),此方法出錯(cuò)的幾率更小。
操作設(shè)計(jì)應(yīng)考慮并發(fā)性
傳統(tǒng)的事務(wù)型編程模型(如Entity EntERPrise Java Bean(Entity Bean)所支持的編程模型)允許實(shí)現(xiàn)數(shù)據(jù)庫(kù)更新,因此其數(shù)據(jù)庫(kù)鎖定方式如清單13中所示。
清單13. 事務(wù)型編程模型
Begin Transaction
Retrieve data from database - locking record
Modify values
update database record with modified values
Commit Transaction - unlocking record
請(qǐng)注意,數(shù)據(jù)庫(kù)鎖定從第1行檢索時(shí)一直保持到第5行的提交操作。這樣以一定的延遲確保了正確的并發(fā)行為。如果我們希望設(shè)計(jì)一個(gè)提供數(shù)據(jù)庫(kù)更新功能的服務(wù),則可以提供與清單8中的第2行和第4行的檢索和寫(xiě)入操作對(duì)應(yīng)的操作。不過(guò),我們強(qiáng)烈建議,不要在高度分離且可能異步的SOA基礎(chǔ)結(jié)構(gòu)中的連續(xù)調(diào)用間保持鎖定。我們建議采用樂(lè)觀鎖定策略,將并發(fā)控制的責(zé)任委派給相應(yīng)的應(yīng)用程序邏輯。
樂(lè)觀鎖定策略中的更新請(qǐng)求可以解釋為“以下是基于記錄XYZ的V版本的一些記錄更新。請(qǐng)僅在從我讀取該記錄后沒(méi)有人進(jìn)行修改的情況下進(jìn)行更改!
以下是為清單12所示的同一個(gè)模型使用了數(shù)據(jù)庫(kù)觸發(fā)器和修訂計(jì)數(shù)器的樂(lè)觀鎖定實(shí)現(xiàn)。該實(shí)現(xiàn)要求執(zhí)行以下步驟:
·向要使用樂(lè)觀鎖定的表中添加一個(gè)額外的整數(shù)列;該列保存修訂計(jì)數(shù)器。
·向數(shù)據(jù)庫(kù)添加觸發(fā)器,以便對(duì)該表中的記錄的每個(gè)更新都會(huì)導(dǎo)致修訂計(jì)數(shù)器遞增。
·所有檢索操作均會(huì)返回包含修訂計(jì)數(shù)器的數(shù)據(jù)項(xiàng)。
·所有更新操作都必須包含從檢索獲得的修訂計(jì)數(shù)器。
·更新操作實(shí)現(xiàn)必須對(duì)數(shù)據(jù)庫(kù)記錄進(jìn)行限定的更新操作,如“如果修訂計(jì)數(shù)器等于...則更新記錄...”如果其間對(duì)記錄進(jìn)行了任何修改,此更新操作將失敗——在其間,如果出現(xiàn)了更新,則會(huì)觸發(fā)更新觸發(fā)器,因此會(huì)修改修訂計(jì)數(shù)器。
·如果由于其他使用者在其間進(jìn)行了更新而導(dǎo)致更新失敗,則將向使用者報(bào)告一個(gè)特定的錯(cuò)誤。
請(qǐng)注意,此實(shí)現(xiàn)在更新時(shí)要求使用者提供正確的修訂計(jì)數(shù)器;進(jìn)行糾正的責(zé)任分散到數(shù)據(jù)庫(kù)、提供者和使用者三者身上。另外,還請(qǐng)注意,此實(shí)現(xiàn)設(shè)計(jì)真的非常樂(lè)觀;如果爭(zhēng)用的概率很低,就能很好地工作。如果可能出現(xiàn)更新沖突,則重試的性能開(kāi)銷將非常大。另外,還需要一些其他可能的樂(lè)觀鎖定策略和詳細(xì)設(shè)計(jì),以制定合適的并發(fā)方案。
考慮到管理并發(fā)更新的相對(duì)復(fù)雜性,我們提出一個(gè)相關(guān)的建議:盡可能使用無(wú)狀態(tài)語(yǔ)義。例如,與實(shí)現(xiàn)等效的“Retrieve record”-“Write record”兩個(gè)操作(使用者會(huì)在檢索和寫(xiě)入操作間使值遞增)相比,可能實(shí)現(xiàn)具有良好并發(fā)行為的單個(gè)操作“Increment balance by X”更為容易。
結(jié)束語(yǔ)
本文的主要目的是強(qiáng)調(diào)在面向服務(wù)的體系結(jié)構(gòu)中服務(wù)設(shè)計(jì)的重要性。我們并不認(rèn)為文中包含了全部設(shè)計(jì)原則。而是希望通過(guò)這些原則能夠說(shuō)明,每個(gè)SOA都需要慎重地為其企業(yè)確定一組恰當(dāng)?shù)脑瓌t,并隨后確定每個(gè)服務(wù)創(chuàng)建人員都能遵循這些原則。
關(guān)于作者
David Artus是IBM Software Services for WebSphere團(tuán)隊(duì)的成員,在英國(guó)IBM Hursley Lab工作。他從1999年就開(kāi)始提供WebSphere咨詢和指導(dǎo)服務(wù)。在1999年加入IBM之前,David曾從事過(guò)多個(gè)行業(yè)的工作,包括投資金融、旅游和IT咨詢。他所感興趣的領(lǐng)域包括分布式系統(tǒng)的設(shè)計(jì)、對(duì)象技術(shù)和面向服務(wù)的體系結(jié)構(gòu)。
轉(zhuǎn)載請(qǐng)注明出處:拓步ERP資訊網(wǎng)http://www.oesoe.com/
本文標(biāo)題:實(shí)現(xiàn)SOA服務(wù)設(shè)計(jì)原則是什么?(下)
本文網(wǎng)址:http://www.oesoe.com/html/support/1112153780.html