JavaWeb開發設計(一)一致性方案設計

2021-09-06 21:34:31 字數 3031 閱讀 6416

目錄

1、引子

2、系統一致性方案

3、介面一致性方案

4、對賬

以下都是個人經驗總結,水平所限,難免有誤,歡迎指正。

一致性就是保持資料一致,在分布式系統中,可以理解為多個節點中資料的值是一致的。

要保證資料一致性,就需要對可能由服務超時、高併發甚至bug引起的問題事先考慮,建立合適的一致性模型,確保和上下游保持一致,並在各個服務異常節點,做好資料記錄以便進行核對和補償。

在做一致性設計的時候,如果考慮系統的資料一致性,那麼就要認為系統外部都是不可靠的;如果考慮介面的資料一致性,那麼就要認為其他介面都是不可靠的,基於此才能更全面地處理各種異常。這裡說的不可靠,指的是網路服務或持久化服務不可靠。

下面從整個系統的資料一致性和服務介面的資料一致性兩個角度,談一談一致性方案。

從單個應用設計的角度看,一致性包括兩個方面,乙個是應用本身資料一致性,乙個是和上下游應用的資料一致性。

應用本身資料的一致性,包括集群(如果有)中所有機器資料一致性和單機內資料一致性,由於系統中的業務資料一般放在資料庫或快取,都是與應用機器分離的,因此一般不存在集群資料一致性問題,且集群的管理一般業務系統的技術設計上不考慮。對於單機內資料一致性,分為單個服務資料一致性,以及業務資料一致性。單個服務的資料一致性,一般通過資料庫事務保證,達到準實時一致;而業務資料的一致性,則需要通過對賬指令碼來核對,一般提供弱一致性保證。

和上下游應用的資料一致性,從應用提供服務的角度來看,每個應用保證向下一致,對上負責。也就是說,每個服務保證服務內部資料一致性以及和下游系統一致性,給上游的結果可能是業務受理、業務成功、業務失敗、業務處理中或超時。那麼如何保證和下游資料一致呢?有明確結果的情況沒什麼好說,主要是超時情況的處理,這就要分場景了:如果是實時性要求高的場景,那麼超時狀態做業務失敗處理返回給上游,並向下游發起請求撤銷(回滾);如果實時性要求不高,那麼可以立刻發起重試,或狀態置為處理中,非同步重試,直到得到明確結果返回給上游。

**如下:

從服務介面角度看,乙個介面的實現如何保證一致性,首先要保證介面本身涉及資料的一致性,其次外部依賴系統與本應用的資料一致性,另外要保證併發情況下的資料一致性。實現方案最基本的就是:介面支援冪等、內部事務處理、對外進行重試和補償。

根據業務上對介面實時性要求,可以粗略分為兩種介面設計方案,一種處理實時性要求較低的介面,也就是弱實時介面,很多是可以非同步處理的;一種處理實時性要求高的請求,也就是強實時介面,一般都是同步介面。下面分別介紹兩種介面的實現方案。

這裡對外部依賴系統和服務做個說明:

1)如果外部依賴的介面不支援冪等,那麼不能直接重試,需要先做查詢,再重試;

2)如果呼叫外部超時,那麼根據具體場景,要麼重試直到成功,要麼做取消請求的補償;

3.1 弱實時介面設計

弱實時介面針對的場景是呼叫方只關注受理結果,而不關注直接處理結果,甚至當認為訊息中介軟體基本可靠的情況下,受理結果也可以不關注,只通過資料對賬來確認服務執行成功就行了。

設計思路是用樂觀鎖(cas+version)支援冪等,在拋異常時,無論本地異常或外部異常,都拋異常中止執行,再然後非同步重試。弱實時介面往往可以非同步執行,因此完全可以放在訊息佇列,單執行緒執行,不需要考慮併發問題,所以用樂觀鎖較好。

以乙個簡單的調賬的介面為例進行說明,介面服務處理流程圖如下:

請求處理共4步:

1)落一條基礎資料,資料狀態為處理中,如果失敗則直接拋異常。

2)調外部賬,如果超時或失敗則拋異常。

3)調內部賬,如果超時或失敗則拋異常。

4)執行本地事務,落本地業務資料,如果失敗則拋異常。

做幾點說明:

1)介面是冪等的,且以上4步每一步都是冪等的,如果外部介面不支援冪等,那麼就查詢重試。

2)由於介面冪等,請求和重試是呼叫同乙個介面。

3)根據異常碼決定是直接重試還是先處理再重試,很多場景是不需要區分超時和業務失敗,可以直接重試的。

4)先調外部賬再調內部賬是因為三方包相對於二方包風險更高,如果外部賬失敗了,就沒必要調內部賬了。

3.2 強實時介面設計

強實時介面針對的場景是呼叫方需要直接拿到明確結果,無論是成功、失敗,還是外部超時,這種介面往往也有rt要求。

設計思路仍然可以考慮用樂觀鎖(如果存在大量寫操作,服務失敗概率會很高,那麼可以考慮用悲觀鎖),只是如果服務內部或依賴服務失敗或超時時,儲存失敗資訊,直接返回業務失敗;根據儲存的失敗資訊,對失敗資訊進行補償。

仍以調賬服務為例,流程如下:

可見強實時介面和弱實時介面的服務處理流程是一樣的,區別在於:

1)如果服務失敗或依賴服務失敗,則直接返回業務失敗,而不是非同步重試。(此處有時也可以直接重試,可以解決很多由於超時導致的異常,但如果服務都超時了,那麼對強實時性要求介面來說,也就算是失敗了)

2)對失敗的記錄,要做失敗補償,這要求下游服務提供補償介面。如調外部賬成功,而調內部賬失敗,則需要做失敗補償,補調外部賬逆向操作。

3)高併發場景下的介面設計,另外開篇敘述,方案上會複雜很多。

3.3 小結

當然強弱實時性都是相對的,實際方案需要根據場景靈活處理,比如對於強實時場景,雖然依賴的某些服務可能暫時失敗,但提供最終成功的保證,也可以只呼叫不處理,對於呼叫記錄另外再非同步處理。

對於資料一致性,即使介面設計很好,還是可能會出現業務資料不一致的情況,如不同的業務模組之間的關聯資料對不平,不同應用之間的關聯資料對不平,和外部機構由於延時處理等原因導致資料對不平等。

保證資料一致性的兜底方案就是對賬,這個對賬就包括了應用內部關聯模組的資料核對、關聯應用的資料核對、關聯合作方的資料核對等,如資金流的賬務核對就包括了賬賬核對(賬務系統和會計、清算系統)、賬證核對(業務系統和賬務系統)、賬實核對(賬務系統和銀行核對)、業務財務核對等。

強一致性 弱一致性 最終一致性

這種方式在es等分布式系統中也有體現,可以設定主shard提交即返回成功,或者需要replica shard提交成功再返回。提到分布式架構就一定繞不開 一致性 問題,而 一致性 其實又包含了資料一致性和事務一致性兩種情況,本文主要討論資料一致性 事務一致性指acid 複製是導致出現資料一致性問題的唯...

快取設計 一致性優化

一致性是指資料庫和快取裡的資料是一樣的,如果出現兩者不一樣,就說出現了一致性問題。一致性優化是指怎麼消除一致性問題,或者出現了一致性問題怎麼去發現並解決。如果資料庫和快取不一致,會導致系統出現bug,尤其是一些關鍵性的資料,比如餘額。所以在一些不能容忍不一致的場景,是一定要消除不一致的問題。為什麼會...

session一致性架構設計

什麼是session?由於http協議是無狀態的協議,因此它不會去記住上一次瀏覽器訪問伺服器時的資訊。同乙個使用者的兩次操作,與兩個不同使用者的操作,對它來說是一樣的。這樣雖然滿足了網際網路web應用的海量訪問的需求,但是對於現今類似電商的應用來說,是需要實現登入以及身份驗證需求的,但是無狀態的ht...