
mongodb單表億級數(shù)據(jù)的拆分方案
拆表是一種常見的解決單表數(shù)據(jù)庫瓶頸的方案,在實際的應(yīng)用場景中能夠部分解決單表的寫壓力和讀壓力,但是也會帶來一些更復(fù)雜的影響:
- 聚合查詢變得困難
- 拆分的鍵一旦選定,更改會非常困難
- 拆表的過程要保證線上業(yè)務(wù)不受影響,操作復(fù)雜度高
因此,表的拆分一定要選在恰當(dāng)?shù)臅r候進行,過早,付出很大代價也并不會帶來性能的提升,過晚,數(shù)據(jù)量龐大,操作難度加大。
在本次實施的拆分方案中,數(shù)據(jù)特點是:
- 單表過億
- 業(yè)務(wù)數(shù)據(jù)是用戶對資源的收藏,結(jié)構(gòu)比較單一
- 只做單向(用戶—>數(shù)據(jù))查找,不要求反向(數(shù)據(jù)—>用戶)查找
- 數(shù)據(jù)處于實時變更狀態(tài)(新增、刪除、查詢等操作并存)
如何選擇拆分鍵
本例中,拆分的鍵就是用戶 id,且每個用戶關(guān)聯(lián)的資源數(shù)據(jù)最大不會過萬。
如何保證拆分的過程中不影響用戶的操作?
本例中,表中的數(shù)據(jù)基本上只有如下操作
- 用戶新增一條數(shù)據(jù)
- 用戶刪除一條數(shù)據(jù)
- 用戶查詢數(shù)據(jù)(有翻頁)
拆表的基本原理就是對選擇的鍵進行 hash 生成每個鍵所屬的表空間名,也就是說,在任意時刻,任意用戶的數(shù)據(jù)只有以下三種狀態(tài)
1.全部在舊表中
2.部分在新表,部分在舊表
3.全部在新表中
數(shù)據(jù)拆分的具體工作是要離線進行的,為了能保證用戶數(shù)據(jù)在這樣三種狀態(tài)之下依然具有像單表中一樣的一致性,需要業(yè)務(wù)層在處理當(dāng)前用戶數(shù)據(jù)時判斷用戶是否在遷移中,只有處于遷移狀態(tài)之下,用戶數(shù)據(jù)才需要特別處理。
遷移狀態(tài)如何判斷?
當(dāng)用戶數(shù)據(jù)處于遷移狀態(tài),為了保證用戶數(shù)據(jù)全部可用,即要做到不跨表翻頁,我們做了如下決定:一旦開始遷移,用戶的全部數(shù)據(jù)就會載入到一個特殊區(qū)域(這里我們用了 redis,后面再討論這樣處理可能帶來的問題)且保存為有序集數(shù)據(jù)。
如果用戶處于遷移狀態(tài),則用戶的數(shù)據(jù)一定存在于這個區(qū)域,暫且給此區(qū)域命名為 on_progress。
遷移狀態(tài)下如何保證用戶數(shù)據(jù)的正確性?
當(dāng)用戶處于遷移狀態(tài),用戶新增一條數(shù)據(jù),則在新表、on_progress 、舊表中各寫入新增數(shù)據(jù),用戶刪除一條數(shù)據(jù),則在新表、on_progress、舊表中同時刪除該數(shù)據(jù)。
這樣做的目的是什么?
處于遷移狀態(tài)下的用戶,on_progress 中保存了其所有數(shù)據(jù),可以進行翻頁操作,on_progress 中的所有數(shù)據(jù)會在離線狀態(tài)下不斷寫入新表中,遷移完成之后,舊表中的數(shù)據(jù)將被刪除,on_progress 中數(shù)據(jù)也將被清除,這樣用戶數(shù)據(jù)全部進入新表中,后續(xù)的所有操作將只在新表上進行。
on_progress 中的數(shù)據(jù)在不斷寫入新表的過程中,是按照由新—>舊或由舊—>新的順序進行,在這個過程中:
用戶刪除一條數(shù)據(jù)
1)有可能該條數(shù)據(jù)已經(jīng)寫入新表中,所以刪除操作要在新表中執(zhí)行。
2)on_progress 中的數(shù)據(jù)要始終和用戶所有的操作同步來保證數(shù)據(jù)的正確性和一致性,因而刪除操作也要在 on_progress 中執(zhí)行。
3)如果發(fā)生意外導(dǎo)致 on_progress 不可用,為維護數(shù)據(jù)的一致性,刪除操作也需要在舊表中進行。
用戶新增一條數(shù)據(jù)
1)on_progress 中的數(shù)據(jù)要始終和用戶所有的操作同步來保證數(shù)據(jù)的正確性和一致性,因而 on_progress 需要寫入一條數(shù)據(jù)。
2)在某些邊界條件下,on_progress (假如數(shù)據(jù)由舊—>新寫入新表) 中的數(shù)據(jù)遷移完成但還未被刪除,用戶恰巧寫入一條數(shù)據(jù),此時用戶仍處于遷移狀態(tài)中,但是離線的遷移操作已經(jīng)認(rèn)為遷移停止了,因而此時新增數(shù)據(jù)需要進入新表才能保證數(shù)據(jù)最終是正確的。
3)如果發(fā)生意外導(dǎo)致 on_progress 不可用,為維護數(shù)據(jù)的一致性,新增操作也需要在舊表中進行。
on_progress 的選擇
在這個方案的實施中,on_progress 用了 redis 的有序集,鍵就是用戶的 id,只要檢測到用戶 id 的存在就認(rèn)為該用戶處于遷移狀態(tài)中。
遷移完成之后,先刪除舊表中的數(shù)據(jù),然后再刪除 on_progress 中有序集。
判斷用戶遷移狀態(tài)
1.只要用戶處于 redis 中,則此時一定是遷移中或遷移完成
2.只在舊表中找到用戶數(shù)據(jù),則該用戶一定還沒有開始遷移
3.只在新表中找到用戶數(shù)據(jù),用戶已經(jīng)遷移成功
需要注意的是,選用 redis 可能帶來的問題是 redis 宕機會導(dǎo)致遷移中的數(shù)據(jù)無法恢復(fù)(redis 未開持久化操作或其他原因?qū)е聰?shù)據(jù)不能恢復(fù)),只要用戶在舊表中有數(shù)據(jù)存在,則用戶刪除數(shù)據(jù)的操作一定也要在舊表中執(zhí)行,再次恢復(fù)遷移時,清除舊表數(shù)據(jù),直接載入舊表中的數(shù)據(jù)到 on_progress。
[超站]友情鏈接:
四季很好,只要有你,文娛排行榜:https://www.yaopaiming.com/
關(guān)注數(shù)據(jù)與安全,洞悉企業(yè)級服務(wù)市場:https://www.ijiandao.com/

隨時掌握互聯(lián)網(wǎng)精彩
- 1 看總書記關(guān)心的清潔能源這樣發(fā)電 7904797
- 2 央視曝光直播間“高端四件套”貓膩 7808694
- 3 以總理:絕不會有巴勒斯坦國 等著瞧 7711998
- 4 長春航空展這些“首次”不要錯過 7619343
- 5 租客長租15年不到1年就被勸退 7521975
- 6 浙江大學(xué)教授被留置 持股市值31億 7427456
- 7 9月23日晚8點將上演“龍收尾”天象 7330158
- 8 馬斯克特朗普鬧掰后首次同框 7234312
- 9 風(fēng)王“樺加沙”體型超整個廣東省 7143767
- 10 美國軍工巨頭主動曝光戰(zhàn)機 7048864