原標題:技術分享: 數據冷熱分離
隨著業務的發展,數據庫增長的很快。老板不明白其中道理,但作為數據庫的維護者,卻看的膽顫心驚。
終于,數據庫慢慢的接近數瓶頸點,管理員也越來越焦慮。
使用分區表吧,不行。就如上面所說,有些挖祖墳的請求,會加載一些很久之前的數據,分區表并不能解決問題。
明顯要對數據進行一下切割,進行冷熱分離了。
大體的結構如上圖。我們有一個數據路由,負責根據時間維度區分數據,定位到相應的數據庫中進行查詢。
熱庫和冷庫,可能是異構的。
解決思路
問題已經進行了轉化。我們接下來的目標,變成了怎么根據時間維度,構建熱數據和冷數據的分離。
目前使用最多的數據庫是mysql,我們也從它說起。
其實,冷熱分離的兩份數據,查詢“最近時間”的數據,是沒什么差別的。唯一不同的是,熱庫,會定時的刪除舊的數據。
雙寫
雙寫是最簡單,但是又最不靠譜的方案。結構如下圖。
但是注意,操作步驟1、2,涉及到分布式事務,需要同時保證兩個庫的寫入成功。
這就讓事情變的麻煩了一些。作為一個吃過無數次事務問題的虧的人,不會重蹈這樣的覆轍。
所以,這種方案,直接pass。
走消息
細心的同學應該發現了上圖的優化點,通過引入一個叫做消息隊列的東西,就可以把分布式事務這座大山給繞過去,只保證最終一致性即可。
多么美好的設想。理想很豐滿,現實很骨感。由于冷熱分離涉及到非常多的數據表,需要修改不可預知的業務代碼,遭到了大家的一致反對。
此方案無疾而終。
直接看圖,變了兩根線而已。
使用binlog
有的同學可能已經憋不住了:為什么不用binlog?接下來我們就談下這種方案。
不可否認,這是種非常優雅的方式。數據只需要寫入熱庫就可以了,通過數據訂閱的方式,增量的將數據寫入到冷庫。
但是等等。我們的定時任務,刪除數據的時候,同樣也要產生binlog。如何區別數據的刪除,是定時任務產生的,還是正常的業務產生?
還好,xjjdog知曉一個非常隱秘的方式去操作。
對對對,就是下面的過程。
set session sql_log_bin=0;//optset session sql_log_bin=1;
binlog可以設置session級別的,也就是在此session中操作的語句,并不會產生binlog。
這樣,我們在定時任務執行時,先關閉binlog,然后,執行刪除語句,然后,重新恢復binlog。這些刪除的數據,就不會通過canal同步到冷庫中了。
萬萬沒想到
mmp?
為什么不支持呢?為什么呢?容我小心翼翼的猜想一下。你的rds啊,有可能在和別人在共用一個實例呢。
其實,除了rds的限制,此方案還存在一個bug。比如熱庫有冷熱分離的時候。想想為甚么吧。
標記清除
得了,xjjdog只能曲線救國了。用最2的方式完成這個操蛋的功能。
標記清除。這四個醒目的大字,讓人不由自主的想到jvm的垃圾回收算法。
原理其實也類似,步驟也是一分為二。
第一、標記階段
給每一張數據表,都加一個叫做mark2Del字段。然后,通過定時,標記所有要過期(也就是要放入冷庫的數據)。
第二、清除階段
在下一次定時來臨時,將上次標記要刪除的數據,逐條搬遷到冷庫。搬遷完畢后,進行下一輪標記。
此方案非常簡單,但有個致命弱點。由于所有的庫表,都是老表,都需要增加一個叫做mark2Del的字段,甚是麻煩。
然而,上面的介紹,只是解決了數據的刪除,并沒有解決數據的同步。
最終方案
結合以上的描述,以及環境的限制。我們選擇了使用binlog+標記清除的方式。
標記清除負責刪除數據。
binlog負責增量同步數據。只是,在這個同步邏輯中,多了一個判斷,如果mark2Del的值被設置成了true,則忽略此binlog。
也就是說,我們強行給每條刪除的記錄,追加了一個判斷標志。
這樣,系統終于跑起來了。
End
上文描述的,是mysql到mysql之間的冷熱分離。
但如果,我想要做一個分層的數據倉庫。
第一層,是熱庫。
第二層,是冷庫。
第三層,是存檔庫,可能是druid這種大數據存儲。
該如何設計?
本文不做過多介紹。架構的難點不在結果,而在于過程。
你看起來很挫的方案,總有它背后的故事,嘗試著去理解,大有裨益。
除非它是真的挫。不過,這不也是你的機會么?返回搜狐,查看更多
責任編輯: