寫失敗資料寫入成功 細聊冗餘表資料一致性

2021-10-14 18:21:22 字數 4192 閱讀 2444

**:

細聊冗餘表資料一致性_w3cschool​www.w3cschool.cn

網際網路很多業務場景的資料量很大,此時資料庫架構要進行水平切分,水平切分會有乙個patition key,通過patition key的查詢能夠直接定位到庫,但是非patition key上的查詢可能就需要掃瞄多個庫了。

例如訂單表,業務上對使用者和商家都有訂單查詢需求:

order(oid, info_detail)

t(buyer_id, seller_id, oid)

如果用buyer_id來分庫,seller_id的查詢就需要掃瞄多庫。

如果用seller_id來分庫,buyer_id的查詢就需要掃瞄多庫。這類需求,為了做到高吞吐量低延時的查詢,往往使用「資料冗餘」的方式來實現,就是文章標題裡說的「冗餘表」

t1(buyer_id, seller_id, oid)

t2(seller_id, buyer_id, oid)

同乙個資料,冗餘兩份,乙份以buyer_id來分庫,滿足買家的查詢需求;

乙份以seller_id來分庫,滿足賣家的查詢需求。二、冗餘表的實現方案

【方法一:服務同步寫】

顧名思義,由服務層同步寫冗餘資料,如上圖1-4流程:

(1)業務方呼叫服務,新增資料

(2)服務先插入t1資料

(3)服務再插入t2資料

(4)服務返回業務方新增資料成功優點

(1)不複雜,服務層由單次寫,變兩次寫

(2)資料一致性相對較高(因為雙寫成功才返回)缺點

(1)請求的處理時間增加(要插入次,時間加倍)

(2)資料仍可能不一致,例如第二步寫入t1完成後服務重啟,則資料不會寫入t2

如果系統對處理時間比較敏感,引出常用的第二種方案【方法二:服務非同步寫】

資料的雙寫並不再由服務來完成,服務層非同步發出乙個訊息,通過訊息匯流排傳送給乙個專門的資料復**務來寫入冗餘資料,如上圖1-6流程:

(1)業務方呼叫服務,新增資料

(2)服務先插入t1資料

(3)服務向訊息匯流排傳送乙個非同步訊息(發出即可,不用等返回,通常很快就能完成)

(4)服務返回業務方新增資料成功

(5)訊息匯流排將訊息投遞給資料同步中心

(6)資料同步中心插入t2資料優點

(1)請求處理時間短(只插入1次)缺點

(1)系統的複雜性增加了,多引入了乙個元件(訊息匯流排)和乙個服務(專用的資料復**務)

(2)因為返回業務線資料插入成功時,資料還不一定插入到t2中,因此資料有乙個不一致時間視窗(這個視窗很短,最終是一致的)

(3)在訊息匯流排丟失訊息時,冗餘表資料會不一致

如果想解除「資料冗餘」對系統的耦合,引出常用的第三種方案【方法三:線下非同步寫】

資料的雙寫不再由服務層來完成,而是由線下的乙個服務或者任務來完成,如上圖1-6流程:

(1)業務方呼叫服務,新增資料

(2)服務先插入t1資料

(3)服務返回業務方新增資料成功

(4)資料會被寫入到資料庫的log中

(5)線下服務或者任務讀取資料庫的log

(6)線下服務或者任務插入t2資料優點

(1)資料雙寫與業務完全解耦

(2)請求處理時間短(只插入1次)缺點

(1)返回業務線資料插入成功時,資料還不一定插入到t2中,因此資料有乙個不一致時間視窗(這個視窗很短,最終是一致的)

(2)資料的一致性依賴於線下服務或者任務的可靠性

上述三種方案各有優缺點,但不管哪種方案,都會面臨「究竟先寫t1還是先寫t2」的問題?這該怎麼辦呢?三、究竟先寫正表還是反表

對於乙個不能保證事務性的操作,一定涉及「哪個任務先做,哪個任務後做」的問題,解決這個問題的方向是:【如果出現不一致】,誰先做對業務的影響較小,就誰先執行。

以上文的訂單生成業務為例,buyer和seller冗餘表都需要插入資料:

t1(buyer_id, seller_id, oid)

t2(seller_id, buyer_id, oid)

使用者下單時,如果「先插入buyer表t1,再插入seller冗餘表t2」,當第一步成功、第二步失敗時,出現的業務影響是「買家能看到自己的訂單,賣家看不到推送的訂單」

相反,如果「先插入seller表t2,再插入buyer冗餘表t1」,當第一步成功、第二步失敗時,出現的業務影響是「賣家能看到推送的訂單,賣家看不到自己的訂單」

由於這個生成訂單的動作是買家發起的,買家如果看不到訂單,會覺得非常奇怪,並且無法支付以推動訂單狀態的流轉,此時即使賣家看到有人下單也是沒有意義的。

因此,在此例中,應該先插入buyer表t1,再插入seller表t2。

however,記住結論:【如果出現不一致】,誰先做對業務的影響較小,就誰先執行。四、如何保證資料的一致性

從二節和第三節的討論可以看到,不管哪種方案,因為兩步操作不能保證原子性,總有出現資料不一致的可能,那如何解決呢?

【方法一:線下掃面正反冗餘表全部資料】

如上圖所示,線下啟動乙個離線的掃瞄工具,不停的比對正表t1和反表t2,如果發現資料不一致,就進行補償修復。優點

(1)比較簡單,開發代價小

(2)線上服務無需修改,修復工具與線上服務解耦缺點

(1)掃瞄效率低,會掃瞄大量的「已經能夠保證一致」的資料

(2)由於掃瞄的資料量大,掃瞄一輪的時間比較長,即資料如果不一致,不一致的時間視窗比較長

有沒有只掃瞄「可能存在不一致可能性」的資料,而不是每次掃瞄全部資料,以提高效率的優化方法呢?【方法二:線下掃瞄增量資料】

每次只掃瞄增量的日誌資料,就能夠極大提高效率,縮短資料不一致的時間視窗,如上圖1-4流程所示:

(1)寫入正表t1

(2)第一步成功後,寫入日誌log1

(3)寫入反表t2

(4)第二步成功後,寫入日誌log2

當然,我們還是需要乙個離線的掃瞄工具,不停的比對日誌log1和日誌log2,如果發現資料不一致,就進行補償修復優點

(1)雖比方法一複雜,但仍然是比較簡單的

(2)資料掃瞄效率高,只掃瞄增量資料缺點

(1)線上服務略有修改(代價不高,多寫了2條日誌)

(2)雖然比方法一更實時,但時效性還是不高,不一致視窗取決於掃瞄的週期

有沒有實時檢測一致性並進行修復的方法呢?

【方法三:實時線上「訊息對」檢測】

這次不是寫日誌了,而是向訊息匯流排傳送訊息,如上圖1-4流程所示:

(1)寫入正表t1

(2)第一步成功後,傳送訊息msg1

(3)寫入反表t2

(4)第二步成功後,傳送訊息msg2

這次不是需要乙個週期掃瞄的離線工具了,而是乙個實時訂閱訊息的服務不停的收訊息。

假設正常情況下,msg1和msg2的接收時間應該在3s以內,如果檢測服務在收到msg1後沒有收到msg2,就嘗試檢測資料的一致性,不一致時進行補償修復優點

(1)效率高

(2)實時性高缺點

(1)方案比較複雜,上線引入了訊息匯流排這個元件

(2)線下多了乙個訂閱匯流排的檢測服務

however,技術方案本身就是乙個投入產出比的折衷,可以根據業務對一致性的需求程度決定使用哪一種方法。我這邊有過好友資料正反表的業務,使用的就是方法二。

資料冗餘一致性優化

通過patition key的查詢能夠直接定位到庫,但是非patition key上的查詢可能就需要掃瞄多個庫了。1 4流程 1 業務方呼叫服務,新增資料 2 服務先插入 t1資料 3 服務再插入 t2資料 4 服務返回業務方新增資料成功 1 不複雜,服務層由單次寫,變兩次寫 2 資料一致性相對較高...

持久化資料 快取資料雙寫一致性

快取中資料更新一般有兩個入口,快取未過期,資料庫資料有變動主動更新至快取 關於資料一致性 需要將髒資料的存在時間範圍放在可控範圍內 併發 因為無事務,無法保證雙寫的一致性 多資料來源 如果拿著乙份資料分別向持久層和快取執行執行更新,在時序無法保證時會出現交叉覆蓋的情況 互斥 快取的初始化 查詢資料 ...

表間資料是否一致的檢查 資料比對

資料庫 twt001 資料表 a,b 參考文章 sql中的case when用法 sql中的case when用法 case函式不同於decode函式。在case函式中,可以使用between,like,is null,in,exists等等。比如說使用in,exists,可以進行子查詢,從而實現更...