日志對(duì)許多應(yīng)用程序來說是都是一個(gè)重要的組成部分,至少存在兩種類型的日志: 一般信息的和 關(guān)鍵業(yè)務(wù)的。
一般信息日志主要用來跟蹤應(yīng)用程序的步驟和操作。根據(jù)日志信息的用途,它對(duì)應(yīng)用程序的操作有著不同的影響。例如,如果日志記錄只是用來進(jìn)行統(tǒng)計(jì)分析,少數(shù)幾次失敗的日志操作將是可以接受的。然而,如果日志是用來審計(jì),那么遺失日志記錄將是不可接受的,這就要用到第二種類型的日志:關(guān)鍵業(yè)務(wù)日志。
在這種情形下,根據(jù)業(yè)務(wù)的相關(guān)程度,日志的輸出將影響到系統(tǒng)的其它部分,換句話說,其它應(yīng)用程序?qū)⒆x取關(guān)鍵業(yè)務(wù)日志并應(yīng)用到它們的商業(yè)邏輯中。這種類型的日志將像其它的一些業(yè)務(wù)操作一樣被謹(jǐn)慎處理。這類日志的一個(gè)例子就是金融系統(tǒng)的日志,那些記錄財(cái)務(wù)事務(wù)信息的日志可用來進(jìn)行興趣統(tǒng)計(jì)、稅費(fèi)計(jì)算或僅僅是用來滿足法律要求,如可跟蹤性。
不幸的是,在目前系統(tǒng)在,一些重要的日志消息,(可能是一般信息日志或關(guān)鍵業(yè)務(wù)日志),很少被認(rèn)真處理。原因在與日志操作經(jīng)常被當(dāng)作一種輔助操作,日志資源被當(dāng)作一種只寫的設(shè)備,只滿足快速和廉價(jià)即可。
基于日志的自身內(nèi)在特性,Web 服務(wù)是實(shí)現(xiàn)日志的很好的選擇。因?yàn)閷?duì)業(yè)務(wù)關(guān)鍵日志敏感的企業(yè)同樣會(huì)對(duì)一個(gè)企業(yè)范圍內(nèi)所有應(yīng)用程序都能夠使用的日志服務(wù)感興趣,并且Web服務(wù)還提供了日志記錄及其生命周期的集中管理能力。
在本文中,我們將提出一種企業(yè)范圍的日志 Web 服務(wù)架構(gòu),它重點(diǎn)解決分布式系統(tǒng) 2 個(gè)關(guān)鍵設(shè)計(jì)方面: 可靠性和容錯(cuò)性和 事務(wù)語義支持的日志。
日志的容錯(cuò)性和可靠性
在本節(jié)我們將基于 WS-Reliability 標(biāo)準(zhǔn)討論與日志有關(guān)的 Web 服務(wù)可靠性問題,并提出一個(gè)可靠的日志 Web 服務(wù)架構(gòu)方案。
可靠日志的需求
在討論技術(shù)細(xì)節(jié)之前,我們首先定義可靠性以及日志 Web 服務(wù)需要實(shí)現(xiàn)的可靠性需求
從一個(gè)用戶的角度出發(fā),可靠性經(jīng)常是一種需求,下面兩段引文對(duì)什么是可靠性給出了很好的定義:
- 根據(jù)文獻(xiàn) 分布式系統(tǒng)-概念和設(shè)計(jì)(請(qǐng)參閱 參考資料),一個(gè)計(jì)算機(jī)系統(tǒng)的可靠性是對(duì)系統(tǒng)的行為偏離它最初的設(shè)計(jì)行為(即根據(jù)正確行為的定義)的可能性大小的度量,它包括在沒有任何個(gè)別的錯(cuò)誤操作的前提下發(fā)生的系統(tǒng)中止。可通過設(shè)計(jì)系統(tǒng)來發(fā)現(xiàn)系統(tǒng)偏離(或錯(cuò)誤)并從中恢復(fù)來提高系統(tǒng)可靠性。
- 可靠性的第二個(gè)定義源于文獻(xiàn) 分布式系統(tǒng)-原理和示例(請(qǐng)參閱 參考資料) ,它指系統(tǒng)在不發(fā)生故障的前提下連續(xù)運(yùn)行。一個(gè)高可靠系統(tǒng)是指系統(tǒng)在無故障前提下一個(gè)相當(dāng)長(zhǎng)的時(shí)間周期內(nèi)可以最大可能的持續(xù)不間斷工作。.
這兩個(gè)定義從根本上說明,你希望建立的日志 Web 服務(wù)是在一個(gè)相對(duì)較長(zhǎng)的時(shí)間范圍內(nèi)可以不間斷工作,且具有發(fā)現(xiàn)故障并從中恢復(fù)的能力。
日志需求記住上面的定義,則不難確定一個(gè)可靠日志 Web 服務(wù)的可靠性需求。下面的列表描述了一個(gè)可靠日志 Web 服務(wù)所必須實(shí)現(xiàn)的需求:
- 實(shí)現(xiàn)可靠的消息傳遞:未來的設(shè)計(jì)技術(shù)方案必須保證提交到日志 Web 服務(wù)日志消息能夠傳遞到服務(wù)器端且被處理。
- 除去重復(fù)消息:日志 Web 服務(wù)除了必須保證消息被提交外,還要確保即使一條消息被提交多次,在服務(wù)器端也只處理一次。
- 確保消息次序:協(xié)議和設(shè)計(jì)技術(shù)方案必須保證提交到 Web 服務(wù)的日志消息按照它們的發(fā)送時(shí)的次序在服務(wù)器端處理。
- 日志客戶端和 Web 服務(wù)容錯(cuò)性:日志客戶端和 Web 服務(wù)需要能夠發(fā)現(xiàn)錯(cuò)誤并能夠從錯(cuò)誤中恢復(fù)。
這意味著,要實(shí)現(xiàn)一個(gè)可靠日志 Web 服務(wù),未來的技術(shù)方案必須保證消息傳遞到服務(wù)器端并按照正確的順序處理一次(且僅處理一次)。另外,方案必須保證提交的日志信息必須是可持續(xù)化的,即使服務(wù)器或客戶端崩潰等特殊時(shí)刻。
高層架構(gòu)
在詳細(xì)討論之前,我們還必須明確幾個(gè)定義。在本節(jié),我們?yōu)槿罩?Web 服務(wù)提出了高層架構(gòu),研究架構(gòu)體系內(nèi)的組件,并定義整節(jié)中使用的通用術(shù)語。
圖 1 顯示了組成日志方案的高層組件,并定義了日志客戶端與 Web 服務(wù)進(jìn)行交互的兩個(gè)場(chǎng)景。
圖 1: 日志場(chǎng)景
圖 1的上半部分顯示了最基本的場(chǎng)景。 這里,日志客戶端與日志 Web 服務(wù)直接進(jìn)行交互。
圖 1 下半部分顯示如下場(chǎng)景: 日志客戶端并不直接與日志 Web 服務(wù)進(jìn)行交互,日志信息被傳遞到一系列稱為跳轉(zhuǎn)的中間服務(wù)。不管是日志客戶端的直接通信組件還是日志 Web 服務(wù)來作為跳轉(zhuǎn),都需要保持透明。
本文將不對(duì)跳轉(zhuǎn)進(jìn)行單獨(dú)討論,但從架構(gòu)的觀點(diǎn)來看,如果與日志客戶端交互,那么它就像一個(gè)日志 Web 服務(wù),如果與日志 Web 服務(wù)交互,那么就是一個(gè)日志客戶端。
組件在上一節(jié)我們研究了主要組件-日志客戶端和日志 Web 服務(wù)。在本節(jié)我們將從架構(gòu)的角度對(duì)日志 Web 服務(wù)進(jìn)行詳細(xì)研究。
圖 2: 基本日志服務(wù)架構(gòu)
圖 2 中的高層視圖并沒有給出太多的技術(shù)細(xì)節(jié),只是用來說明組成日志 Web 服務(wù)的 2 個(gè)主要組件。
簡(jiǎn)單地,日志 Web 服務(wù)從總體上可以分為 2 部分:
- 日志客戶端:組件封裝了一個(gè)可靠日志客戶端,應(yīng)用程序通過提供的 API 可以使用它。組件可以從應(yīng)用程序中接收日志信息并通過可靠的方式提交到日志服務(wù)器。在本文中這一組件通常被稱作 客戶端或 日志客戶端.
- 日志服務(wù)器:此組件是應(yīng)用程序的核心部分,它為日志客戶端提供了一個(gè)進(jìn)行可靠日志的 Web 服務(wù)。日志服務(wù)器接收日志信息并采用可靠的方式進(jìn)行處理,在本文中這一組件通常被稱作 服務(wù)器或 日志服務(wù)器.
應(yīng)用程序是 圖 2 中的第 3 個(gè)組件. 應(yīng)用程序并不屬于日志 Web 服務(wù),由于它使用 Web 服務(wù),因此它在本文上下文中也很重要。
在整篇文章中,這一組件被稱為 商業(yè)應(yīng)用程序.
WS-Reliability 標(biāo)準(zhǔn)
作為討論的基礎(chǔ),我們對(duì) WS-Reliability(請(qǐng)參閱 參考資料)進(jìn)行概述,并討論了它的關(guān)鍵元素和機(jī)制。 然而,你會(huì)發(fā)現(xiàn), WS-Reliability 標(biāo)準(zhǔn)很好地覆蓋了協(xié)議層上關(guān)于可靠性的問題,但并沒有涉及到應(yīng)用層上的可靠性問題,而這些問題正是本文中著重討論的,以此來彌補(bǔ)協(xié)議層與應(yīng)用層之間的差距。
WS-Reliability 標(biāo)準(zhǔn)的目標(biāo)
WS-Reliability 標(biāo)準(zhǔn)的目的在于通過定義客戶機(jī)服務(wù)器之間的通信機(jī)制,使得 Web 服務(wù)滿足如下要求:
- 提供可靠消息傳遞( 至少一次語義)
- 除去重復(fù)消息( 至多一次語義)
- 確保消息次序
WS-Reliability 定義的消息關(guān)鍵元素
WS-Reliability 提出了一種基于消息/確認(rèn)(message/acknowledgment)模型的可靠性解決方案。這意味著每個(gè)消息發(fā)送者在發(fā)送一條消息后都會(huì)等待從服務(wù)器返回的一條回應(yīng)消息-確認(rèn)。
圖 3: WS-Reliability 中的日志消息/確認(rèn)模型
圖 3顯示了 WS-Reliability 規(guī)范中定義的一個(gè)消息場(chǎng)景。這里我們使用消息來取代 日志消息。 WS-Reliability 并不是特定日志消息而是適用于通用消息。但從我們的角度重發(fā),我們只考慮日志應(yīng)用程序。 #p#副標(biāo)題#e#
一個(gè)日志客戶端發(fā)送一條日志消息給 Web 服務(wù), Web 服務(wù)接收到日志消息后,如果有必要的話除去重復(fù)的消息,然后對(duì)消息進(jìn)行處理。一旦處理完畢,它將發(fā)送一條確認(rèn)消息給客戶端。
由于這篇文章不是用來專門討論 WS-Reliability 標(biāo)準(zhǔn),因此,我們不會(huì)討論整個(gè)標(biāo)準(zhǔn),但將會(huì)討論其中的幾個(gè)關(guān)鍵元素,特別是與可靠日志服務(wù)相關(guān)的特性元素。
首先,日志請(qǐng)求消息中包含的關(guān)鍵元素如下所示:
- Message-ID: 這是在消息發(fā)送前被指派的序號(hào)。通過這種方式, Web 服務(wù)在一條消息被重復(fù)提交多次的情況下能夠避免重復(fù)處理,同時(shí)還能夠保證消息之間正確的次序。
- Ack-Requested: 這一元素允許客戶端來決定對(duì)于發(fā)送的消息是否需要確認(rèn)。對(duì)于一個(gè)可靠的日志 Web 服務(wù),這一屬性標(biāo)志必須為真。
- Duplicate-Elimination: 根據(jù)這一屬性,客戶端可以決定服務(wù)器是否需要進(jìn)行去除重復(fù)消息的處理。對(duì)于一個(gè)可靠的日志 Web 服務(wù),這一屬性標(biāo)志必須為真。
確認(rèn)消息中唯一一個(gè)重要的元素是字段 Ref-To-Message-ID 。 這一字段包含了確認(rèn)消息所回應(yīng)的日志消息的序號(hào)(Message-ID)。
從上面列出的幾個(gè)元素你可以看到, WS-Reliability 規(guī)范覆蓋了 “可靠日志的需求”一節(jié)中提出的 3 個(gè)需求。上述特性提供了可靠日志在協(xié)議層的解決方案,但并沒有提供應(yīng)用層的解決方案,如可靠日志第 4 個(gè)需求,但它為解決應(yīng)用層的問題提供了基礎(chǔ)。
在下面一節(jié),我們列出了在應(yīng)用層可能發(fā)生的錯(cuò)誤,并提出了一個(gè)可以解決這些錯(cuò)誤問題的解決方案。
日志在應(yīng)用層的可靠性問題
為舉出應(yīng)用層的可靠性問題,讓我們重溫回顧一下 圖 3中的日志場(chǎng)景:
- 客戶端對(duì)服務(wù)器發(fā)出日志請(qǐng)求
- 服務(wù)器接受到日志請(qǐng)求
- 服務(wù)器序列化日志請(qǐng)求
- 服務(wù)器發(fā)送確認(rèn)給客戶端
- 客戶端接收到服務(wù)器發(fā)送的請(qǐng)求信息
上面的流程整體上提供了一種可靠消息傳遞機(jī)制:一個(gè)客戶端發(fā)送一條日志請(qǐng)求,服務(wù)器在完成消息存儲(chǔ)之后發(fā)送一條確認(rèn)信息。但上述流程并不是意外安全的,因?yàn)樵谙率銮樾蜗律鲜隽鞒虒⒈淮蚱疲S之而來的便是沒有確認(rèn)消息返回到客戶端:
- 如果客戶機(jī)無法定位服務(wù)器怎么辦?
- 如果請(qǐng)求消息丟失怎么辦?
- 在存儲(chǔ)或尚未存儲(chǔ)日志信息的情形下,服務(wù)器崩潰怎么辦?
- 如果確認(rèn)消息丟失怎么辦?
- 如果客戶機(jī)崩潰怎么辦?
在上述每一種情況下,你都必須保證日志消息被存儲(chǔ)且客戶端接收到確認(rèn)消息。在某些條件下要確保這一點(diǎn)可能會(huì)很困難。下面我們將對(duì)上述情況進(jìn)行詳細(xì)討論
客戶機(jī)無法定位服務(wù)器
如果客戶端不能夠定位服務(wù)器,則將導(dǎo)致日志服務(wù)失敗。但這個(gè)問題客戶端可以進(jìn)行控制,因此,服務(wù)器端或協(xié)議層不需要特別的機(jī)制來處理這一狀況。
如上所述,日志信息在被日志客戶端提交到服務(wù)器端后絕不能夠丟失。如果客戶端不能夠定位服務(wù)器,將出現(xiàn)下面兩種情形:
- 服務(wù)器暫時(shí)無法連接。
- 服務(wù)器永久無法連接,或至少看起來如此。
設(shè)計(jì)一個(gè)基本的假設(shè)是:服務(wù)器的連接狀況對(duì)于業(yè)務(wù)應(yīng)用程序盡可能透明。
在第一種情形下,日志客戶端能夠針對(duì)服務(wù)器無效的狀況對(duì)業(yè)務(wù)應(yīng)用程序保持透明。日志客戶端將從業(yè)務(wù)應(yīng)用程序接收的日志信息重復(fù)(使用同一個(gè)序號(hào))發(fā)送,如果客戶端遇到的是服務(wù)器的瞬間故障,一旦服務(wù)器功能回復(fù),它將馬上處理日志信息。
如果在 n 次嘗試后仍無法連接服務(wù)器,客戶端有理由認(rèn)為服務(wù)器永久無法連接,因此需要將這一狀況報(bào)告給調(diào)用日志客戶端的業(yè)務(wù)應(yīng)用程序。
請(qǐng)求信息丟失
在某些情形下客戶端和服務(wù)器之間的消息可能會(huì)丟失,如傳輸層上的包或當(dāng)一個(gè)消息在一個(gè)跳轉(zhuǎn)鏈上進(jìn)行傳輸時(shí),其中的一個(gè)跳轉(zhuǎn)突然崩潰。
做為一個(gè)設(shè)計(jì)特色,消息確認(rèn)使得客戶端能夠確定請(qǐng)求信息是否丟失。如果請(qǐng)求信息在發(fā)送到服務(wù)器的途中丟失,或者服務(wù)器在處理請(qǐng)求信息之前崩潰,那么客戶端不會(huì)接收到請(qǐng)求消息。
為了避免客戶端與服務(wù)器間的臨時(shí)連接超時(shí)的影響,客戶端將重復(fù)發(fā)送 n 次消息,如果這種連接超時(shí)依舊存在,客戶端在重復(fù)發(fā)送了 n 次后將停止重復(fù)發(fā)送日志信息并向調(diào)用客戶端的業(yè)務(wù)應(yīng)用程序報(bào)告這一錯(cuò)誤。
服務(wù)器故障
如果服務(wù)器發(fā)生故障,客戶端將從服務(wù)器得不到確認(rèn)信息,將有可能發(fā)生兩種情形:
- 服務(wù)器在接收到信息之后但在存儲(chǔ)信息之前崩潰。
- 服務(wù)器在存儲(chǔ)信息之后但在發(fā)送響應(yīng)信息之前崩潰。
在上述兩種情形下,你都希望客戶端能夠重新發(fā)送日志信息給服務(wù)器而且這些信息不會(huì)被服務(wù)器多次處理。就像你希望任何服務(wù)器上的故障對(duì)客戶端都是透明的一樣。
在第一種情況下,由于消息尚未被處理,客戶端只需要簡(jiǎn)單的提交信息,而服務(wù)器端不需要采取任何特殊行為。
下面考慮第二種情形,你會(huì)注意到當(dāng)?shù)谝淮伟l(fā)送的消息被再次提交,則日志消息將會(huì)被處理 2 次,因?yàn)檫@條日志信息已經(jīng)被記錄了。因此,客戶端必須能夠保證在服務(wù)器不會(huì)第二次處理消息的前提下重復(fù)提交信息。為解決這個(gè)問題,服務(wù)器必須包含一個(gè)狀態(tài)變量來標(biāo)識(shí)提交的消息已經(jīng)被處理但確認(rèn)消息尚未發(fā)出這一狀態(tài)。
在協(xié)議層,架構(gòu)方案為解決這一問題提出消息序號(hào),或在 WS-Reliability 被稱為的 Message-ID ,根據(jù)消息序號(hào)和服務(wù)器端的存儲(chǔ)日志,服務(wù)器能夠鑒別處重復(fù)提交的日志消息。
根據(jù)這個(gè)架構(gòu),你可以看出日志 Web 服務(wù)根據(jù)需要進(jìn)行工作,不會(huì)將已經(jīng)提交的信息進(jìn)行重復(fù)處理。一個(gè)日志客戶端提交信息給服務(wù)器。服務(wù)器接收到信息,然后檢查存儲(chǔ)日志來判斷這條信息是否在之前已被處理。如果尚未被處理,換句話說,存儲(chǔ)日志中不存在對(duì)應(yīng)的條目,服務(wù)器將處理日志信息,如果處理成功,在返回確認(rèn)消息之前,將在存儲(chǔ)日志中創(chuàng)建一個(gè)條目。如果消息已經(jīng)被處理,換句話說,存儲(chǔ)日志中存在對(duì)應(yīng)的條目,則服務(wù)器將不會(huì)處理消息而是立即返回確認(rèn)信息。
需要注意是,要使架構(gòu)能夠正確工作,包含存儲(chǔ)日志的文件系統(tǒng)絕對(duì)不能夠溢出。
確認(rèn)消息丟失
像日志消息一樣,確認(rèn)消息由于某些原因也會(huì)丟失,同樣,客戶端無法確切知道哪里發(fā)生了錯(cuò)誤。然而,像上面提到的,通過使得服務(wù)器具有容錯(cuò)性,客戶端可以簡(jiǎn)單的重新發(fā)送日志消息來等待確認(rèn)信息的到達(dá)。
為將暫時(shí)錯(cuò)誤與永久錯(cuò)誤區(qū)分開,客戶端可以采用與上面所述的同樣的策略。客戶端發(fā)送 n 次日志信息。如果在發(fā)送 n 次信息后仍舊沒有接收到確認(rèn)消息,客戶端有理由認(rèn)為系統(tǒng)遇到永久性故障,它可將這一故障信息返回給調(diào)用者或業(yè)務(wù)應(yīng)用程序。
客戶端崩潰
對(duì)于可靠日志來說,日志客戶端將是一個(gè)業(yè)務(wù)應(yīng)用程序的主要組成部分。業(yè)務(wù)應(yīng)用程序的許多操作或任意操作都伴隨著日志操作。由于日志客戶端的同步特性,如果日志應(yīng)用程序運(yùn)行失敗則業(yè)務(wù)應(yīng)用程序同樣也會(huì)失敗。
提出的架構(gòu)
組件
根據(jù)上節(jié)中討論的內(nèi)容,我們提出如 圖 4 所示的架構(gòu).
圖 4: 日志客戶端和服務(wù)器架構(gòu)
客戶端提供了一組 API,業(yè)務(wù)應(yīng)用程序通過它能夠訪問日志客戶端。控制器包含日志客戶端的業(yè)務(wù)邏輯。在客戶端的底層,你將發(fā)現(xiàn)客戶端使用的實(shí)現(xiàn)了傳輸協(xié)議的通信 API。
服務(wù)器包含一組通信 API 用來與客戶端進(jìn)行通信,一個(gè)存儲(chǔ)日志用來保存狀態(tài),還有一個(gè)日志消息倉庫。為實(shí)現(xiàn)上一節(jié)所講的業(yè)務(wù)規(guī)則,通過一個(gè)控制器組件將服務(wù)器內(nèi)的所有組件緊緊聯(lián)系在一起。
日志需求與體系結(jié)構(gòu)的關(guān)系
在對(duì)本節(jié)進(jìn)行總結(jié)之前,讓我們看一下體系架構(gòu)是如何滿足前面所述的日志需求的
- 實(shí)現(xiàn)可靠的消息傳遞:請(qǐng)求/確認(rèn)協(xié)議使得客戶端能夠判斷消息是否傳遞到客戶端。
- 除去重復(fù)消息:由于服務(wù)器包含一個(gè)狀態(tài)變量,因此重復(fù)的日志消息能夠被除去。
- 確保消息次序:由于日志客戶端的同步特性,如果沒有接收到前一條日志消息的確認(rèn)信息,日志客戶端將不會(huì)發(fā)送新的日志消息,日志消息將按照正確的順序依次處理。
消息編號(hào)
在所提出的架構(gòu)中還有一個(gè)重要但尚未進(jìn)行討論的設(shè)計(jì)特征,那就是消息編號(hào)。對(duì)于所提出的架構(gòu)來講,實(shí)現(xiàn)消息編號(hào)的一個(gè)最佳方法便是將 HTTP 會(huì)話 ID 與發(fā)送消息的時(shí)間戳進(jìn)行組合。時(shí)間戳的保證了不同的日志消息具有唯一的序號(hào)。根據(jù) HTTP 會(huì)話 ID ,服務(wù)器能夠區(qū)分出哪一條消息是來自哪一個(gè)客戶端,這一點(diǎn)對(duì)于重復(fù)消息的去除和并發(fā)的客戶端間的區(qū)別至關(guān)重要。
事務(wù)語義支持的日志
一個(gè)事務(wù)性的運(yùn)行環(huán)境確保一個(gè)應(yīng)用程序的原子性、一致性、孤立性和持久性。這使得并行運(yùn)行的應(yīng)用程序在訪問共享資源時(shí)得到保護(hù),避免由于資源沖突而產(chǎn)生的資源沖突甚至崩潰。如果一個(gè)應(yīng)用程序發(fā)生崩潰,那么他的所有操作將會(huì)被回退(原子性),如果一個(gè)應(yīng)用程序成功,那么他的所有操作將被保證成功(持久性)。事務(wù)系統(tǒng)能夠確保資源保持一致性,即使資源被同時(shí)訪問(一致性)。事務(wù)系統(tǒng)同樣能夠保證應(yīng)用程序的運(yùn)行可以不管其它應(yīng)用程序的運(yùn)行情況,就像它自己在單獨(dú)運(yùn)行一樣(獨(dú)立性)。
日志對(duì)許多應(yīng)用程序來說是都是一個(gè)重要的組成部分,至少存在兩種類型的日志。 一般信息日志主要用來跟蹤應(yīng)用程序的步驟和操作。根據(jù)日志信息的用途,它對(duì)應(yīng)用程序的操作有著或輕或重的影響。例如, 如果日志記錄只是用來進(jìn)行統(tǒng)計(jì)分析,少數(shù)幾次失敗的日志操作將是可以接受的。然而,如果日志是用來審計(jì), 那么遺失日志記錄將是不可接受的。
另外一種日志稱為關(guān)鍵業(yè)務(wù)日志。它將影響到應(yīng)用程序中與業(yè)務(wù)相關(guān)的其它部分。其它應(yīng)用程序?qū)⒆x取關(guān)鍵業(yè)務(wù)日志并應(yīng)用到它們的商業(yè)邏輯中。這種類型的日志將像其它的一些業(yè)務(wù)操作一樣來被謹(jǐn)慎處理。例如一個(gè)財(cái)務(wù)日志記錄,里面記錄財(cái)務(wù)轉(zhuǎn)帳信息,而且這一日志被用來進(jìn)行投資興趣分析或納稅憑證。
在本文中,我們定義了一個(gè)事務(wù)語法支持的日志服務(wù),重點(diǎn)解決原子性語法。者并不意味者我們強(qiáng)制所有的日志行為做作為原子事務(wù)的一部分,而是根據(jù)日志信息是否事務(wù)敏感,我們可以給應(yīng)用程序提供相應(yīng)的事務(wù)語法支持。
事務(wù)性執(zhí)行
如果有幾個(gè)應(yīng)用程序在并行運(yùn)行,它們中的每一個(gè)都要執(zhí)行一系列連續(xù)的操作,那么整個(gè)系統(tǒng)的執(zhí)行過程就包括按照一定次序執(zhí)行的、來自不同應(yīng)用程序的不同操作。如果這些應(yīng)用程序訪問共享數(shù)據(jù),它們就將導(dǎo)致破壞一致性的潛在沖突的產(chǎn)生。數(shù)據(jù)庫系統(tǒng)中的一致性概念和預(yù)測(cè)鎖定(請(qǐng)參閱 參考資料)對(duì)并發(fā)環(huán)境中的一致性問題給出了明確定義。數(shù)據(jù)庫系統(tǒng)的并發(fā)控制和復(fù)原(請(qǐng)參閱 參考資料)給出了防止系統(tǒng)產(chǎn)生不一致問題的正確操作的屬性。
原子性
原子性可能是一個(gè)成功事務(wù)執(zhí)行的最基本屬性。一個(gè)事務(wù)執(zhí)行被稱為一個(gè)原子是指它的所有更新操作要么全部成功,要么全部失敗,這一點(diǎn)通常被稱為 all-or-nothing 屬性。如果你假設(shè)一個(gè)事務(wù)總是一個(gè)一致性的工作單元,整個(gè)系統(tǒng)的所有更新都被執(zhí)行,很顯然系統(tǒng)仍能夠保持一致性。當(dāng)一個(gè)事務(wù)執(zhí)行已經(jīng)開始執(zhí)行但尚未完成,只有一部分更新操作被實(shí)際執(zhí)行,你就不能假定整個(gè)系統(tǒng)的狀態(tài)仍舊是一致的。你只有在系統(tǒng)的所有操作都被執(zhí)行或都不被執(zhí)行時(shí),才能假設(shè)整個(gè)系統(tǒng)是一致的。
作為事務(wù)的基本屬性,原子性被各種系統(tǒng)實(shí)現(xiàn)。在分布式系統(tǒng)中,原子性還表明一個(gè)事務(wù)應(yīng)該在參與事務(wù)的所有節(jié)點(diǎn)中全部執(zhí)行成功或全部失敗。為確保這一點(diǎn),兩步提交協(xié)議(請(qǐng)參閱 參考資料中的 分布式數(shù)據(jù)庫原理)被提出且在各種系統(tǒng)中實(shí)現(xiàn)。#p#副標(biāo)題#e#
原子性日志操作
你可以將日志操作分為以下 3 類:
- 不涉及事務(wù)原子性的日志操作。一個(gè)日志操作的失敗不會(huì)導(dǎo)致整個(gè)事務(wù)的失敗,并且即使在事務(wù)被中止的情況下日志操作仍舊可以成功。這類日志操作不需要消耗事務(wù)管理資源,也不需要日志服務(wù)支持事務(wù)
- 可視為其它更新一樣參與原子事務(wù)的日志操作。如果操作失敗,整個(gè)事務(wù)過程需要回滾,并且只有在整個(gè)事務(wù)執(zhí)行成功的前提下,日志操作才視為成功執(zhí)行。
- 半事務(wù)原子性的日志操作。只有當(dāng)事務(wù)提交的時(shí)候日志操作才會(huì)成功,但日志操作的失敗并不會(huì)導(dǎo)致事務(wù)被中止。在那種情況下,一些日志記錄將會(huì)丟失,但日志存儲(chǔ)并不會(huì)因?yàn)楸恢兄沟氖聞?wù)的記錄而被“污染”。換句話說,并不存在臟寫的記錄。這種操作類型是在原子性和事務(wù)帶來的巨大代價(jià)之間的折中。因?yàn)槿绻罩静僮魇。]有正常的事務(wù)操作受到影響,但如果事務(wù)失敗,日志消息卻會(huì)受到影響。
對(duì)于分布式計(jì)算來說, Web 服務(wù)是一個(gè)相對(duì)較新的消息基礎(chǔ)設(shè)施。 Web 服務(wù)的事務(wù)性還沒有得到相應(yīng)的重視。最近, Web 服務(wù)組織就分布式事務(wù)如何與 Web 服務(wù)架構(gòu)相協(xié)調(diào)提出 2 個(gè)草案 (商業(yè)事務(wù)和 Web 服務(wù)事務(wù) -- 請(qǐng)參閱 參考資料)。這里我們不對(duì)這兩個(gè)草案進(jìn)行比較,相反,我們主要討論 WS-Transaction 規(guī)范,因?yàn)樗且粋€(gè)更有發(fā)展前景的方案,但我希望你將這兩個(gè)草案都閱讀一下來形成你自己的觀點(diǎn)。WS-Transaction 規(guī)范在分布式事務(wù)的參與者間定義了一個(gè)兩階段提交協(xié)議來支持事務(wù)原子性。
WS-Transaction
WS-Transaction 規(guī)范應(yīng)用于基于 Web 服務(wù)的分布式系統(tǒng)。應(yīng)用程序之間、應(yīng)用程序與系統(tǒng)服務(wù)之間以及系統(tǒng)服務(wù)之間都是通過 Web 服務(wù)進(jìn)行通信。規(guī)范以 Web 服務(wù)描述語言描述了原子性事務(wù)協(xié)議。協(xié)議內(nèi)容如下:
- 完成: 應(yīng)用利用此協(xié)議來初始化分布式事務(wù)提交循環(huán)。
- 兩階段提交: 首先參與分布式事務(wù)的應(yīng)用程序必須延緩自身的更新。當(dāng)完成指令被請(qǐng)求,一個(gè)協(xié)調(diào)器將向所有的事務(wù)參與應(yīng)用程序發(fā)出一個(gè) Prepare 消息。在接收到 Prepare 消息后,每個(gè)應(yīng)用程序根據(jù)被延緩的更新是否可以提交來返回 Prepared 消息或 Aborted 消息。如果事務(wù)的所有參與者返回的都是 Prepare 消息,則它們將得到一個(gè)提交指令,這將導(dǎo)致所有的更新被提交,否則它們將得到一個(gè)放棄消息,所有被延緩的更新將被放棄。
- 階段 0: 一旦一個(gè)兩步提交循環(huán)開始,應(yīng)用程序除了 Prepare 、Commit 和 Abort 指令外,不再執(zhí)行任何操作。假設(shè)一個(gè)在緩存中包含若干更新的服務(wù)最終需要將更新存儲(chǔ)到數(shù)據(jù)庫中,那么它將需要調(diào)用一個(gè)數(shù)據(jù)庫服務(wù)。由于應(yīng)用程序在接收到 Prepare 指令后將禁止調(diào)用數(shù)據(jù)庫服務(wù),那么服務(wù)如何在 Commit 之前存儲(chǔ)數(shù)據(jù)呢?這將通過階段 0 協(xié)議來實(shí)現(xiàn)。在開始 Commit 循環(huán)之前,協(xié)調(diào)器將給參與者發(fā)送一個(gè)階段 0 消息。
- 結(jié)果通知: 一些不屬于分布式事務(wù)的應(yīng)用程序僅僅想知道事務(wù)執(zhí)行結(jié)果:提交還是放棄。它們可以通過結(jié)果同志協(xié)議獲取這一信息。
WS-Transaction 規(guī)范建立在另外一個(gè)協(xié)議 WS-Coordination(請(qǐng)參閱 參考資料)之上. 上述 2 個(gè)協(xié)議都是以協(xié)議協(xié)調(diào)器和協(xié)議使用者之間的 Web 服務(wù)接口的形式來實(shí)現(xiàn)的。因此,存在必然存在兩階段提交協(xié)調(diào)服務(wù)和兩階段提交使用服務(wù),階段 0 協(xié)調(diào)服務(wù)和階段 0 使用服務(wù)等等。這些協(xié)調(diào)服務(wù)和參與服務(wù)在 WS-Transaction 規(guī)范中通過 Web 服務(wù)描述語言( WSDL)以端口類型的形式來描述。
事務(wù)支持的日志服務(wù)架構(gòu)
圖 5: 事務(wù)支持的日志服務(wù)架構(gòu)
圖 5 展示了一些參與節(jié)點(diǎn)和協(xié)議以及它們之間必要的交互。我們假定有 2 個(gè)應(yīng)用程序節(jié)點(diǎn)( Appl1 和 Appl2 ),一個(gè)數(shù)據(jù)庫節(jié)點(diǎn)( DB ),和一個(gè)包含日志服務(wù)的節(jié)點(diǎn)( LogService )。
節(jié)點(diǎn)及其服務(wù)
- Appl1 是一個(gè)初始應(yīng)用程序,它希望完成分布式事務(wù),因此它向協(xié)調(diào)器注冊(cè)事務(wù)的完成協(xié)議。因此它將參與服務(wù)提供給完成協(xié)議( P-C )并使用協(xié)調(diào)器的服務(wù)來使用完成協(xié)議。它同樣可以使用日志服務(wù)節(jié)點(diǎn)上的日志服務(wù)( Logging ),發(fā)送不同事務(wù)原子級(jí)別的日志信息。另外,它還向節(jié)點(diǎn) Appl2 發(fā)送應(yīng)用程序信息,向數(shù)據(jù)庫節(jié)點(diǎn) DB 發(fā)送數(shù)據(jù)庫請(qǐng)求。
- Appl2 被 Appl1 初始化并為 Appl1 工作。它在本地內(nèi)存中緩存了許多更新,并希望最終將這些更新輸送到數(shù)據(jù)庫中,因此它通過協(xié)調(diào)器注冊(cè)階段 0 協(xié)議,因此必須將提供參與服務(wù)給階段 0 協(xié)議 ( P-pz )。
- DB 是數(shù)據(jù)庫節(jié)點(diǎn),它負(fù)責(zé)接收應(yīng)用程序的更新,因此它作為一個(gè)參與者來注冊(cè)兩階段提交協(xié)議。因此它必須提供參與服務(wù)( P-2pc )。
- LogService 是一個(gè)日志服務(wù)節(jié)點(diǎn)。它負(fù)責(zé)接收日志服務(wù),每一個(gè)日志消息可能具有不同的事務(wù)原子級(jí)別。如果某個(gè)日志消息是事務(wù)原子性或半事務(wù)原子性,日志服務(wù)必須作為一個(gè)參與者來注冊(cè)兩階段提交協(xié)議,這樣她就必須提供參與服務(wù)給兩階段提交協(xié)議( P-2pc )。根據(jù)不同的緩存策略,它可能還需要注冊(cè)階段 0 協(xié)議來將日志消息存儲(chǔ)到數(shù)據(jù)庫中在事務(wù)完成之前。
- Coordinator 是一個(gè) WS-transaction 協(xié)調(diào)節(jié)點(diǎn),它提供如下協(xié)調(diào)服務(wù):完成協(xié)議、階段 0 協(xié)議、兩階段提交協(xié)議、C-c、 C-pz、 和 C-2pc。
消息順序
由于篇幅限制,我們這里對(duì)參與者與協(xié)調(diào)器之間的協(xié)議注冊(cè)消息不加討論,你可以在 WS-Coordination 規(guī)范(參見 參考資料)中獲取更多相關(guān)信息。在隨后的討論中,我們假定每一個(gè)節(jié)點(diǎn)對(duì)于它使用的協(xié)議都已經(jīng)成功的注冊(cè)了協(xié)調(diào)器。
必須說明的是,對(duì)于 WS-Transaction 定義的每一條消息,都同時(shí)還包含一個(gè)事務(wù)協(xié)調(diào)上下文。因?yàn)楫?dāng)消息通過 Web 服務(wù)環(huán)境傳輸時(shí),事務(wù)協(xié)調(diào)上下文被包含在 SOAP 頭中,規(guī)范中的上下文具有可擴(kuò)展性,你可以通過一個(gè)代表日志消息所需的事務(wù)原子性級(jí)別的元素來對(duì)它進(jìn)行擴(kuò)展。這個(gè)指定的級(jí)別可以是空、半原子性和原子性。需要注意得是,任何消息都包含事務(wù)協(xié)調(diào)上下文,不管是應(yīng)用程序間的消息還是應(yīng)用程序發(fā)送給數(shù)據(jù)庫的消息。
- 應(yīng)用程序與應(yīng)用程序間存在消息,應(yīng)用程序與數(shù)據(jù)庫服務(wù)間存在消息,應(yīng)用程序到日志服務(wù)間存在消息。每一個(gè)日志消息在事務(wù)協(xié)調(diào)上下文都包含指定的事務(wù)原子性級(jí)別信息。日志服務(wù)器總是檢查這一信息。如果指定的級(jí)別是原子性或半原子性,日志服務(wù)不會(huì)將日志消息馬上進(jìn)行持續(xù)化處理,相反,它將這些日志信息保存在安全的地方,在提交過程中再將這些信息取回。如果事務(wù)原子性級(jí)別是空,日志消息將被立即寫入永久性日志媒體中。
- 節(jié)點(diǎn) Appl1, 初始化應(yīng)用程序,決定完成工作,因此調(diào)用協(xié)調(diào)器的完成服務(wù) (C-c)。
- 在初始化兩階段提交循環(huán)之前,協(xié)調(diào)器調(diào)用 Appl2 的階段 0 參與服務(wù)。作為對(duì)此消息的響應(yīng), Appl2 通過數(shù)據(jù)庫服務(wù)寫入緩存的更新并將這一階段 0 的成功報(bào)告給協(xié)調(diào)器。如果 Appl2 沒能夠完成階段 0 ,協(xié)調(diào)器將會(huì)取消整個(gè)事務(wù)。
- 如果階段 0 成功,協(xié)調(diào)器將開始兩階段提交循環(huán):
- 協(xié)調(diào)器調(diào)用 LogService 和數(shù)據(jù)庫服務(wù)器的 Prepare 操作。日志服務(wù)器檢查日志服務(wù)是否準(zhǔn)備好將所有事務(wù)原子性(不是半事務(wù)原子性)的日志消息持久化,如果檢查失敗,將向協(xié)調(diào)器報(bào)告 Abort 信息,否則報(bào)告 Prepared 信息。向協(xié)調(diào)器發(fā)送 Prepared 消息就好比作個(gè)可以提交的承諾,因此事務(wù)原子性的日志消息必須預(yù)先存儲(chǔ)到穩(wěn)定的存儲(chǔ)器,這樣 隨后的提交即使日志服務(wù)在期間崩潰仍舊可以完成。
- 如果每個(gè)參與者報(bào)告 Prepared,協(xié)調(diào)器將向每一個(gè)參與者發(fā)送 Commit 消息。然后日志服務(wù)器持久化所有事務(wù)原子性和半原子性的日志消息。如果持久化順利完成,則向協(xié)調(diào)器報(bào)告 Commit。
協(xié)調(diào)上下文
在 WS-Transaction 規(guī)范中協(xié)調(diào)上下文被定義為一個(gè)事務(wù)相關(guān)的頭信息的容器, 清單 1 給出了 SOAP 頭中的協(xié)調(diào)上下文的結(jié)構(gòu)。上下文結(jié)構(gòu)包含一個(gè)元素 , , 指定上下文的類型,它是一個(gè) WS-Transaction URL。它說明這一協(xié)調(diào)器上下文包含一個(gè) WS-Transaction 協(xié)議消息 。在上下文內(nèi)部,我們引入新的元素 , ,其中的命名空間是假定的,元素的值是日志信息指定的事務(wù)原子性級(jí)別,它可以是空、原子性或半原子性。
清單 1
|
結(jié)束語
這篇文章指出日志是現(xiàn)代業(yè)務(wù)應(yīng)用程序中的一個(gè)重要部分,需要像應(yīng)用程序中其它的與業(yè)務(wù)相關(guān)的部分一樣謹(jǐn)慎處理。如果業(yè)務(wù)需要日志作為企業(yè)及其處理流程的一部分,那么一個(gè)集中的日志服務(wù)便應(yīng)需而生,因此日志 Web 服務(wù)是一個(gè)理想的選擇。


