1為什么要做服務(wù)之間的數(shù)據(jù)一致性
作為互聯(lián)網(wǎng)公司的研發(fā)工程師,微服務(wù)的架構(gòu)思想對于各位讀者朋友來說,已經(jīng)不是陌生東西。我們當(dāng)中的大多數(shù)人,或多或少經(jīng)歷過從單體應(yīng)用到微服務(wù)化的系統(tǒng)拆分和演進過程。我們按照龐大系統(tǒng)的業(yè)務(wù)功能和特征,將其從一個單體的大應(yīng)用,逐漸地拆分成很多的子系統(tǒng)的協(xié)同配合完成業(yè)務(wù)功能,甚至拆分后的某些子系統(tǒng)服務(wù),還可能再拆分出來更多的更細顆粒度的子系統(tǒng)服務(wù)。拆分后的服務(wù)之間,采用PRC調(diào)用方式的通信,也就越來越多。隨之而來的,跨系統(tǒng)服務(wù)之間的數(shù)據(jù)一致性的問題就會越來越突出了。比如電商系統(tǒng)中營銷活動系統(tǒng)的積分和優(yōu)惠券的發(fā)放和扣減,比如電商系統(tǒng)的核心下單核心鏈路上,首頁瀑布流,商詳頁,下單頁等等商品價格全鏈路一致性等等,支撐這些業(yè)務(wù)功能的實現(xiàn),往往可能需要依賴來自N個不同的業(yè)務(wù)系統(tǒng)服務(wù)提供的數(shù)據(jù)讀寫服務(wù)能力來完成。
2如何實現(xiàn)服務(wù)之間的數(shù)據(jù)一致性
說到數(shù)據(jù)一致性這個話題,我們可以想到的最常用最熟悉的解決問題的方式就是事務(wù)處理了。它存在的意義是為了保證系統(tǒng)中所有的數(shù)據(jù)都是符合預(yù)期的,并且存在關(guān)聯(lián)關(guān)系的數(shù)據(jù)之間不會產(chǎn)生矛盾,即數(shù)據(jù)狀態(tài)一致性。事務(wù)的概念,起源于數(shù)據(jù)庫,發(fā)展到今天,幾乎在每一個業(yè)務(wù)系統(tǒng)中都會涉及到。尤其在一些大型復(fù)雜的分布式系統(tǒng)中,事務(wù)的概念已經(jīng)不僅局限于數(shù)據(jù)庫,還可以延伸為一切需要保證數(shù)據(jù)一致性的應(yīng)用場景,包括但不限于數(shù)據(jù)庫、事務(wù)內(nèi)存、緩存、消息隊列、分布式存儲等等,這些都有可能會用到事務(wù)處理。 今天我們探討的主題是服務(wù)之間數(shù)據(jù)一致性問題。當(dāng)然,實際生產(chǎn)落地中,在不同業(yè)務(wù)背景下,具備可行性的方案也是非常多的,各有優(yōu)劣和適用場景。我們從中選擇一兩個具體實現(xiàn),聊一些相關(guān)的設(shè)計和實踐。
3幾個核心名詞
為了方便正在閱讀本篇文章的同學(xué)對后續(xù)內(nèi)容的閱讀和理解,我們先對文章中使用到的幾個名詞的語義做一些解釋和約定: 業(yè)務(wù)側(cè)系統(tǒng):指的是發(fā)起執(zhí)行業(yè)務(wù)操作的一方系統(tǒng)服務(wù),可以簡單理解為消費方。 平臺側(cè)系統(tǒng):指的是為發(fā)起執(zhí)行業(yè)務(wù)操作而提供基礎(chǔ)能力的一方系統(tǒng)服務(wù),可以簡單理解為服務(wù)方。 執(zhí)行業(yè)務(wù)操作:指的是對數(shù)據(jù)的讀寫操作需要依賴多個系統(tǒng)服務(wù)的協(xié)同完成,業(yè)務(wù)側(cè)系統(tǒng)發(fā)起,平臺側(cè)系統(tǒng)執(zhí)行最終的數(shù)據(jù)讀寫操作。這樣場景中就普遍存在著服務(wù)之間的數(shù)據(jù)一致性問題(備注 :業(yè)務(wù)側(cè)系統(tǒng)和平臺側(cè)系統(tǒng)是一個邏輯概念,并非一定要存在具體的應(yīng)用服務(wù)與之對應(yīng))。 業(yè)務(wù)操作標(biāo)識:指的是業(yè)務(wù)操作應(yīng)該歸屬的業(yè)務(wù)類型或者業(yè)務(wù)場景的標(biāo)識,它是平臺側(cè)系統(tǒng)創(chuàng)建并且統(tǒng)一管理的,然后發(fā)放給業(yè)務(wù)側(cè)系統(tǒng),在業(yè)務(wù)側(cè)系統(tǒng)的服務(wù)調(diào)用平臺側(cè)系統(tǒng)提供服務(wù)能力的身份信息。業(yè)務(wù)標(biāo)識可以設(shè)計為單層結(jié)構(gòu),也可以設(shè)計為多層結(jié)構(gòu),符合當(dāng)前系統(tǒng)和業(yè)務(wù)的需求即可。 業(yè)務(wù)操作唯一ID:指的是某個具體業(yè)務(wù)操作在某一次或者多次重復(fù)執(zhí)行的唯一性標(biāo)識。生產(chǎn)實踐中,它一般是由業(yè)務(wù)側(cè)系統(tǒng)的服務(wù)自定義實現(xiàn)和管理的,也可以是基于平臺側(cè)系統(tǒng)提供有約束性質(zhì)和方便管理的規(guī)則限制下,再由業(yè)務(wù)側(cè)系統(tǒng)的服務(wù)自定義實現(xiàn),后者是比較推薦的方式。 業(yè)務(wù)操作記錄表:指的是記錄業(yè)務(wù)操作的日志流水表。生產(chǎn)實踐中,一般是由業(yè)務(wù)側(cè)系統(tǒng)的服務(wù)創(chuàng)建并且管理。
4方案一:業(yè)務(wù)側(cè)系統(tǒng)保證最終一致性
4.1 核心思想
通過業(yè)務(wù)側(cè)系統(tǒng)的服務(wù)保證數(shù)據(jù)的最終一致性,其核心思想就是業(yè)務(wù)側(cè)系統(tǒng)記錄下來每一次具體業(yè)務(wù)操作的執(zhí)行流水日志信息,并且對沒有全部成功的變更結(jié)果,觸發(fā)執(zhí)行數(shù)據(jù)一致性的校驗核對工作。
4.2 設(shè)計原則
平臺側(cè)系統(tǒng)服務(wù),提供支持執(zhí)行業(yè)務(wù)操作的基礎(chǔ)服務(wù)能力的接口。特別強調(diào)一點,這里是需要根據(jù)業(yè)務(wù)操作標(biāo)識和業(yè)務(wù)操作唯一ID來實現(xiàn)接口的冪等設(shè)計。為什么我們有了唯一ID,同時還是需要有業(yè)務(wù)操作標(biāo)識?因為在實際的生產(chǎn)實踐中,在各種內(nèi)因和外因的背景下,需要兼顧系統(tǒng)的穩(wěn)定性和業(yè)務(wù)迭代的靈活性,很難做到絕對的全局性唯一ID的生成。更多時候,只需要在某個業(yè)務(wù)側(cè)系統(tǒng)的內(nèi)部,保證全局唯一性即可,這也是符合實際情況的系統(tǒng)設(shè)計。類似的解決問題的思路,在其他的系統(tǒng)設(shè)計場景,也是有非常高的借鑒價值的。
平臺側(cè)系統(tǒng)服務(wù),提供執(zhí)行業(yè)務(wù)操作后的結(jié)果查詢接口,支持根據(jù)業(yè)務(wù)操作標(biāo)識和業(yè)務(wù)操作的唯一性ID查詢能力。
業(yè)務(wù)操作記錄表,支持記錄和識別業(yè)務(wù)操作的標(biāo)識和每次執(zhí)行的唯一ID。
業(yè)務(wù)側(cè)系統(tǒng)服務(wù),觸發(fā)對業(yè)務(wù)操作記錄表的數(shù)據(jù)一致性的檢查核對工作,執(zhí)行核對的方式,比如實時的同步檢查核對、準(zhǔn)實時的異步檢查核對、定時任務(wù)的異步檢查核對等等,為了保證自己和平臺側(cè)系統(tǒng)的數(shù)據(jù)最終一致性。
4.3 流程圖
4.3.1 數(shù)據(jù)一致性的校驗核對同步執(zhí)行流程
4.3.2 數(shù)據(jù)一致性的校驗核對異步核對鏈路
5方案二:平臺側(cè)系統(tǒng)保證最終一致性
5.1 核心思想
通過平臺側(cè)系統(tǒng)的服務(wù)保證數(shù)據(jù)的最終一致性,核心思想是平臺側(cè)系統(tǒng)的每一次的數(shù)據(jù)變更,都主動地尋找業(yè)務(wù)側(cè)系統(tǒng),來確認(rèn)本次數(shù)據(jù)變更結(jié)果是否符合預(yù)期。
5.2 設(shè)計的基本原則:
平臺側(cè)系統(tǒng),提供支持業(yè)務(wù)操作執(zhí)行的基礎(chǔ)服務(wù)能力的接口,需要根據(jù)業(yè)務(wù)操作標(biāo)識和唯一ID做冪等設(shè)計。它和方案一的一致性原則類似,省略不再贅述。 平臺側(cè)系統(tǒng),提供業(yè)務(wù)操作的執(zhí)行結(jié)果確認(rèn)的回調(diào)SPI,可以方便業(yè)務(wù)側(cè)系統(tǒng)來實現(xiàn),根據(jù)業(yè)務(wù)操作標(biāo)識和業(yè)務(wù)操作的唯一ID。 業(yè)務(wù)側(cè)系統(tǒng),提供根據(jù)業(yè)務(wù)操作標(biāo)識和業(yè)務(wù)操作的唯一ID,來判斷兩邊的數(shù)據(jù)是否具備一致性的回調(diào)實現(xiàn)。
5.3 流程圖
5.3.1 數(shù)據(jù)一致性的校驗核對同步核對鏈路
5.3.2 數(shù)據(jù)一致性的校驗核對異步核對鏈路
6實踐過程中一些經(jīng)驗分享
這一部分,我將會對平臺側(cè)系統(tǒng)和業(yè)務(wù)側(cè)系統(tǒng)的接口設(shè)計的部分細節(jié),做一些簡單的擴展闡述。希望為大家后續(xù)的研發(fā)工作提供一些思路。后續(xù)的文章中,將會針對其中一些具體的解決方案,做更詳細的闡述。 首先,接口冪等性設(shè)計,將從如下角度進行闡述: 數(shù)據(jù)結(jié)構(gòu),狀態(tài)存儲,異常處理,返回結(jié)果唯一等等角度做一些總結(jié)分享。
6.1 數(shù)據(jù)結(jié)構(gòu)設(shè)計
接口冪等性設(shè)計,是基于業(yè)務(wù)操作的標(biāo)識(這里是稱之為Tag)和業(yè)務(wù)操作的唯一ID來實現(xiàn)的。業(yè)務(wù)操作標(biāo)識的設(shè)計,可以是單層的設(shè)計,也可以是多層的設(shè)計。其中,多層的設(shè)計是為了滿足業(yè)務(wù)側(cè)系統(tǒng)的存在復(fù)雜并且多業(yè)務(wù)場景的訴求。業(yè)務(wù)操作的唯一ID的生成方式,可以是沒有任何業(yè)務(wù)含義的自增趨勢的不可重復(fù)的ID,比如MySQL的自增主鍵ID,分布式ID生成器等等方式,也可以是業(yè)務(wù)側(cè)系統(tǒng)的某些特定的業(yè)務(wù)字段 ,比如用戶的userId,訂單的orderId,商品的spuId,skuId等等。在實際實踐中,后者是我們比較推薦的常用方式,可以實現(xiàn)在不增加系統(tǒng)復(fù)雜度和額外依賴資源的同時,又可以和業(yè)務(wù)側(cè)系統(tǒng)達到高度的契合。
6.2 狀態(tài)存儲設(shè)計
在一般情況下,建議把MySQL存儲當(dāng)做我們首選的存儲,MySQL提供非常完善的數(shù)據(jù)一致性保證能力,最簡單的方式是基于數(shù)據(jù)庫的聯(lián)合唯一索引設(shè)計,多次層Tag + 唯一ID的業(yè)務(wù)唯一鍵。但是也是有缺陷的,比如MySQL自身的性能瓶頸和昂貴的存儲成本。性能上的瓶頸,可以通過訪問MySQL的冪等校驗之前,增加訪問Redis的冪等校驗,校驗不通過拋出異常,在MySQL冪等校驗通過以后,異步刷數(shù)據(jù)到Redis中,這樣保證Redis校驗通過的同時MySQL校驗一定是通過的。我們可以接受Redis的冪等校驗的不準(zhǔn)確性,僅僅是期望它成為流量漏斗的上層,為MySQL承擔(dān)起流量過濾作用,當(dāng)然你可以有其他的更多的方案來做這件事,甚至組合起來使用。也可以增加分庫分表的策略,來解決MySQL的性能瓶頸。在MySQL的存儲成本是相對比較高的,我們可以對歷史的數(shù)據(jù)做歸檔處理,只保留一部分的熱數(shù)據(jù),原則上保持單表的數(shù)據(jù)行數(shù)在500w~1000w之間,同時也可以有能支持一定量的歷史數(shù)量查詢。同時這個過程也需要考慮無鎖處理問題和MySQL空間碎片的問題等等。
6.3 異常處理設(shè)計
第一步,明確導(dǎo)致發(fā)生異常的原因有哪些?一般可以歸為幾個分類,網(wǎng)路異常,數(shù)據(jù)格式錯誤,業(yè)務(wù)邏輯異常。第二步,針對特定類型的問題,我們做出相應(yīng)處理方案。比如我們重試機制,控制重試頻次,重試周期的衰減時間執(zhí)行控制,處理數(shù)據(jù)處理的終態(tài)的異常數(shù)據(jù)的兜底處理機制等等方式。
6.4 返回結(jié)果唯一
我需要保證接口的返回的數(shù)據(jù),再多次重復(fù)調(diào)用執(zhí)行,依舊保證完全相同。我們可以基于狀態(tài)機的流轉(zhuǎn)控制,返回相同的狀態(tài)碼,也可以對一些核心業(yè)務(wù)參數(shù)做核對校驗,如果不通過返回特定的異常碼等等。 此外,平臺側(cè)系統(tǒng)的提供給基礎(chǔ)能力接口的設(shè)計要求我們研發(fā)同學(xué)思考和考慮的更多,比如一致性延遲問題,狀態(tài)機的設(shè)計,并發(fā)問題處理,接口不可用解決等等。
6.5 延遲問題的容忍度
能否在業(yè)務(wù)側(cè)系統(tǒng)服務(wù)期望的時間點,完成數(shù)據(jù)一致性的校驗核對工作?若有延遲,延遲是多少?尤其是極端場景下的延遲是多少? 案例:如果使用定時任務(wù),做數(shù)據(jù)一致性校驗核對工作。比如一個周期(假設(shè)1min),還有很多數(shù)據(jù)未完成核對工作,剩余多少,以及對業(yè)務(wù)側(cè)系統(tǒng)的影響。解決思路:1. 評估和設(shè)計一個合理的周期大??;2. 選擇全量核對和增量核對的選擇;3. 增加核對的掃描的數(shù)據(jù)范圍的策略;4. 增量核對確保不丟失未核對過的數(shù)據(jù),等等。 案例:如果使用MQ消息,我們可能面臨的問題是消息堆積,消息丟失等等場景MQ問題帶來的數(shù)據(jù)不一致問題。 案例:如果使用同步等待方式,是可以將數(shù)據(jù)一致性的延遲降低為0,但是系統(tǒng)吞吐能力和可用性等等,都是無法保證,這也是選擇權(quán)衡的結(jié)果。
6.6 基于狀態(tài)機的設(shè)計
基于狀態(tài)機的設(shè)計中,一定是有初始態(tài)和終態(tài)的,代表數(shù)據(jù)的核對工作,有始有終。至于中間態(tài),可以有多個中間態(tài),也可以是僅有一個中間態(tài),這個和實際的需求和背景相關(guān)聯(lián)的,可以靈活地控制。其中的終態(tài),一般情況下都不會只有一種,而是有兩大類,一種是成功的終態(tài)表示數(shù)據(jù)實現(xiàn)最終一致性,一種是失敗的終態(tài)表示不因為不可抗拒的因素導(dǎo)致的數(shù)據(jù)不一致產(chǎn)生。失敗的終態(tài),也是可以設(shè)計出多種狀態(tài),根據(jù)實際需要來設(shè)計。比如多次重試從初始態(tài)到終態(tài)的耗時和處于失敗態(tài)的數(shù)據(jù)核對檢測工作的占比,一定程度上代表著業(yè)務(wù)側(cè)系統(tǒng)對數(shù)據(jù)一致性延遲的容忍度。這應(yīng)該是我們必須關(guān)注的核心指標(biāo)信息。
6.7 并發(fā)問題
我們在創(chuàng)建一個初始化態(tài)的流水日志記錄的時候,是一個MySQL的insert操作(假設(shè)你選擇了MySQL作為存儲),需要避免創(chuàng)建多條的業(yè)務(wù)操作唯一ID的記錄。最簡單粗暴的方式,依賴DB的聯(lián)合唯一索引是可以實現(xiàn)的。但是需要考慮在并發(fā)比較多的時候,帶來的性能和吞吐問題,甚至導(dǎo)致創(chuàng)建初始化態(tài)就失敗的問題。 對于相同數(shù)據(jù)并發(fā)寫的問題,我們成功執(zhí)行一條insert語句,大多數(shù)情況可以滿足我們業(yè)務(wù)側(cè)系統(tǒng)的預(yù)期。我們可以采用加鎖,排隊等待,分組等待排隊等等手段,限制類似場景的并發(fā)數(shù)來解決。這種方式,隨著業(yè)務(wù)的發(fā)展擴張,可能會面臨系統(tǒng)的吞吐量不足以支撐業(yè)務(wù)的問題。 解決上述的吞吐量下降的問題,我們可能又會想到采用MQ的方式來削峰填谷,因為實際生產(chǎn)實踐中,并發(fā)寫問題的往往都是一個特點 瞬時性發(fā)生的系統(tǒng)尖刺。采用MQ的方式,可以保證平臺側(cè)系統(tǒng)創(chuàng)建初始化態(tài)的流水日志的系統(tǒng)吞吐量。 在以上的基礎(chǔ)之上,我們還是可以采用隔離拆分的方式,比如服務(wù)接口拆分層面的隔離,MQ的topic拆分的隔離等等,配合不同的限流熔斷等等系統(tǒng)保護策略的方式以及不同的系統(tǒng)資源傾斜等等,解決平臺側(cè)系統(tǒng)的性能問題。
6.8 需要解決不可用
熔斷限流,資源隔離,多元化的降級策略等等,這些是大家都非常熟悉的系統(tǒng)可用性保障的手段,這部分相關(guān)的內(nèi)容,就不再展開敘述了。
6.9 需要提供可視化和可觀測
完善告警機制,比如異常狀態(tài)告警,超出閾值告警等等,讓相關(guān)的業(yè)務(wù)側(cè)系統(tǒng)和平臺側(cè)系統(tǒng)同學(xué)可以快速感知到問題并且介入解決問題。 建設(shè)監(jiān)控大盤,比如 MySQL,Redis,MQ,以及數(shù)據(jù)核對工作的狀態(tài)的監(jiān)控等等,都是需要我們?nèi)ヒ徊揭徊浇ㄔO(shè)起來的。 定位和排查問題的工具,拆分后的系統(tǒng),其系統(tǒng)的復(fù)雜度是指數(shù)增長的,這個方面也是非常重要的。
7總結(jié)
在本篇文章中,闡述了兩種處理數(shù)據(jù)一致性問題的解決方案,從核心思想,設(shè)計原則,系統(tǒng)交互流程等等做了詳細的闡述,比對兩種方案,各有優(yōu)劣和各自的適用場景。方案一,業(yè)務(wù)側(cè)系統(tǒng)來保證數(shù)據(jù)的一致性,更適用于對數(shù)據(jù)的一致性有相對比較強的耦合依賴關(guān)系的業(yè)務(wù)場景,需要依賴業(yè)務(wù)操作的執(zhí)行結(jié)果做出判斷,執(zhí)行不同后續(xù)業(yè)務(wù)邏輯分支的執(zhí)行。案例: 同一個商品在不同修改商品信息(變更不同的字段,變更不同表的字段)的入口觸發(fā)異步更新C端緩存的單品維度的商品全量緩存數(shù)據(jù)構(gòu)建,變更的事務(wù)是在成功完成提交以后,方可執(zhí)行本次變更對應(yīng)的后續(xù)緩存構(gòu)建。方案二,平臺側(cè)系統(tǒng)來保證數(shù)據(jù)的一致性,更適用于業(yè)務(wù)側(cè)系統(tǒng),關(guān)注點是數(shù)據(jù)的最終執(zhí)行結(jié)果的業(yè)務(wù)場景,案例: 不同業(yè)務(wù)場景入口的庫存扣減和庫存回滾執(zhí)行結(jié)果。最后,提到在生產(chǎn)實踐過程中一些經(jīng)驗和解決方案的總結(jié)分享,每個點都是值得繼續(xù)深入探討。
*文/kof wang
-
接口
+關(guān)注
關(guān)注
33文章
8691瀏覽量
151919 -
互聯(lián)網(wǎng)
+關(guān)注
關(guān)注
54文章
11185瀏覽量
103868 -
數(shù)據(jù)一致性
+關(guān)注
關(guān)注
0文章
5瀏覽量
1451 -
微服務(wù)架構(gòu)
+關(guān)注
關(guān)注
0文章
25瀏覽量
2979
原文標(biāo)題:微服務(wù)架構(gòu)中的數(shù)據(jù)一致性:解決方案與實踐
文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
串行數(shù)據(jù)一致性測試和驗證測量基礎(chǔ)知識
微服務(wù)架構(gòu)下分布式事務(wù)解決方案 —— 阿里GTS
一行代碼,保障分布式事務(wù)一致性—GTS:微服務(wù)架構(gòu)下分布式事務(wù)解決方案
Redis緩存和MySQL數(shù)據(jù)不一致原因和解決方案
如何解決stm32 H7 DMA串口發(fā)送數(shù)據(jù)一致性問題?
VxWorks中主備數(shù)據(jù)一致性功能組件的設(shè)計與實現(xiàn)
VxWorks中主備數(shù)據(jù)一致性功能組件的設(shè)計與實現(xiàn)
VxWorks中主備數(shù)據(jù)一致性功能組件的設(shè)計與實現(xiàn)
P2P平臺上的數(shù)據(jù)一致性研究
串行數(shù)據(jù)一致性及驗證基礎(chǔ)指南
電能質(zhì)量監(jiān)測數(shù)據(jù)一致性定義及檢測方法_邱麗羚
分布式系統(tǒng)的CAP和數(shù)據(jù)一致性模型
如何保障MySQL和Redis的數(shù)據(jù)一致性
深入理解數(shù)據(jù)備份的關(guān)鍵原則:應(yīng)用一致性與崩潰一致性的區(qū)別
![深入理解<b class='flag-5'>數(shù)據(jù)</b>備份的關(guān)鍵原則:應(yīng)用<b class='flag-5'>一致性</b>與崩潰<b class='flag-5'>一致性</b>的區(qū)別](https://file1.elecfans.com/web2/M00/C4/A2/wKgaomXueUOAUC9kAAUkG4ifnAc542.png)
評論