MySQL如何发型不乱的应对半年数十TB数据增量
文章出自:聽(tīng)云博客
? ? ? ?前段時(shí)間,Oracle官方發(fā)布了MySQL 5.7的GA版本。新版本中實(shí)現(xiàn)了真正意義的并行復(fù)制(基于Group Commit的Group Replication),而不再是基于schema的并行復(fù)制。這一特性極大的改善了特定場(chǎng)景下的主從復(fù)制延遲過(guò)高的狀況。隨著MySQL成熟度的提升,越來(lái)越多的用戶選擇使用MySQL存放自家的數(shù)據(jù),其中不乏使用MySQL來(lái)存放大量數(shù)據(jù)的。
? ? ? ?在過(guò)去的半年多時(shí)間里,聽(tīng)云業(yè)務(wù)量呈爆發(fā)式增長(zhǎng),后端的數(shù)據(jù)量由去年第一季度的幾TB增長(zhǎng)到幾十TB,業(yè)務(wù)量翻了十幾倍。后端應(yīng)用及數(shù)據(jù)庫(kù)面臨的一個(gè)突出的問(wèn)題就是頻繁的進(jìn)行擴(kuò)容來(lái)應(yīng)對(duì)前端流量的增長(zhǎng)。數(shù)據(jù)庫(kù)層面我們使用MySQL來(lái)分布式存儲(chǔ)業(yè)務(wù)數(shù)據(jù),數(shù)據(jù)庫(kù)集群的架構(gòu)也比較簡(jiǎn)單,我們使用開(kāi)源中間件Amoeba來(lái)實(shí)現(xiàn)數(shù)據(jù)的拆分和讀寫(xiě)分離。Amoeba后端有幾百個(gè)數(shù)據(jù)庫(kù)的節(jié)點(diǎn)組,每個(gè)節(jié)點(diǎn)組中都包含一對(duì)主從實(shí)例。master實(shí)例負(fù)責(zé)接受write請(qǐng)求,slave負(fù)責(zé)接受query請(qǐng)求。如下圖:
?
正確的拆分姿勢(shì)
? ? ? ?隨著可選擇的開(kāi)源中間件越來(lái)越多,好多數(shù)據(jù)量并不是很大的使用者都會(huì)過(guò)早的考慮水平拆分?jǐn)?shù)據(jù)庫(kù)。但其實(shí)過(guò)早的水平拆分未見(jiàn)得是一件有意義的事情。主要原因有兩個(gè):一個(gè)方面是水平拆分會(huì)對(duì)現(xiàn)網(wǎng)的業(yè)務(wù)造成沖擊,如果系統(tǒng)在設(shè)計(jì)之初就沒(méi)有考慮過(guò)后續(xù)要進(jìn)行拆分的話,這個(gè)沖擊就會(huì)被放大。比如業(yè)務(wù)中有大量的多表join的查詢,或者是對(duì)事務(wù)有強(qiáng)一致性的要求時(shí),水平拆分就捉襟見(jiàn)肘了。另一方面,如果過(guò)早的進(jìn)行了水平拆分,那么到達(dá)一定程度后再想要垂直進(jìn)行拆分時(shí),代價(jià)是很大的。以聽(tīng)云app為例,當(dāng)我們業(yè)務(wù)庫(kù)拆成8個(gè)分片后,有一天發(fā)現(xiàn)數(shù)據(jù)增長(zhǎng)的很快,于是決定對(duì)其進(jìn)行垂直拆分,將小時(shí)緯度和天緯度的數(shù)據(jù)拆分到一個(gè)新的實(shí)例上去,這時(shí)我們不得不同時(shí)部署8個(gè)節(jié)點(diǎn)組來(lái)將現(xiàn)有的8個(gè)分片上的小時(shí)緯度和天緯度的數(shù)據(jù)遷移出來(lái)。工作量相當(dāng)大。如果水平拆分到了64個(gè)片,那么這時(shí)要想再做垂直拆分,保證累的你不要不要的。
? ? ? ?所以更合理的路線是這樣的,首先對(duì)業(yè)務(wù)數(shù)據(jù)進(jìn)行垂直拆分,原本一個(gè)庫(kù)按業(yè)務(wù)單元垂直拆分成多個(gè)庫(kù),同時(shí)應(yīng)用中配置多個(gè)數(shù)據(jù)源或者使用中間件來(lái)訪問(wèn)拆分后的多個(gè)庫(kù),對(duì)應(yīng)用本身來(lái)說(shuō),基本沒(méi)做什么改動(dòng),但是后端存儲(chǔ)的容量和性能卻翻了好幾倍。如果某天出現(xiàn)瓶頸之后,再來(lái)考慮水平拆分的事情。
優(yōu)雅的從n到2n
?
? ? ? ?水平擴(kuò)展過(guò)程中最讓人頭疼的是數(shù)據(jù)的遷移,以上圖中遷移mod(mobile_app_id,4)=2的數(shù)據(jù)為例,最開(kāi)始的做法是先創(chuàng)建兩個(gè)新的節(jié)點(diǎn)組shared0_new和shared2,拿shared0的全備恢復(fù)到shared0_new和shared2,然后在shared0_new上刪除mod(mobile_app_id,4)=2的數(shù)據(jù),在shared2上刪除mod(mobile_app_id,4)=0的數(shù)據(jù),刪除操作完成后shared0_new、shared2與shared0做同步,同步刪除操作執(zhí)行過(guò)程中的數(shù)據(jù)增量。同步追上之后,切換amoeba的路由規(guī)則,然后下線shared0。這種方式問(wèn)題很多,首先時(shí)耗很高很高,delete完了之后并不能釋放存儲(chǔ)空間,還要optimize table,同樣也是一個(gè)漫長(zhǎng)的過(guò)程。針對(duì)大表的delete會(huì)產(chǎn)生一個(gè)很大的transaction,會(huì)在系統(tǒng)表空間中申請(qǐng)很大一塊undo,delete完成后事務(wù)提交。這個(gè)undo空間并不會(huì)釋放,而是直接給其他事務(wù)復(fù)用,這無(wú)疑會(huì)浪費(fèi)很多存儲(chǔ)空間。
? ? ? ?后來(lái)我們想到一個(gè)便捷的辦法,就是利用mysqldump的—where參數(shù),在備份數(shù)據(jù)的時(shí)候加一個(gè)mod(mobile_app_id,4)=2的參數(shù),就可以單獨(dú)備份出余數(shù)為2的數(shù)據(jù),然后拿這個(gè)邏輯備份恢復(fù)到shared2上去,高效且優(yōu)雅。
數(shù)據(jù)傾斜
? ? ? ?MySQL分布式存儲(chǔ)不可避免的一個(gè)問(wèn)題就是數(shù)據(jù)傾斜。業(yè)務(wù)在運(yùn)行一段時(shí)間之后,會(huì)發(fā)現(xiàn)少部分shared數(shù)據(jù)增量特別快,原因是該shared上面部分用戶的數(shù)據(jù)量較大。對(duì)于數(shù)據(jù)傾斜問(wèn)題我們目前的措施是將這些shared遷移到1TB存儲(chǔ)上來(lái),但這并非長(zhǎng)久之計(jì)。因此我們目前正在做一些新的嘗試,比如對(duì)Amoeba做了一下擴(kuò)展,擴(kuò)展后的Amoeba支持將某一個(gè)mobile_app_id的數(shù)據(jù)單獨(dú)指向后端一個(gè)shared節(jié)點(diǎn)組,即一個(gè)shared只存放一個(gè)用戶的數(shù)據(jù),同時(shí)采用ToKuDB存儲(chǔ)引擎來(lái)存儲(chǔ)這部分?jǐn)?shù)據(jù),ToKuDB能夠?qū)?shù)據(jù)進(jìn)行有效的壓縮,除了查詢性能稍有損耗之外,基本具備InnoDB引擎所擁有的特點(diǎn),而且在線表結(jié)構(gòu)變更比InnoDB快好幾倍不止。這些測(cè)試基本已經(jīng)進(jìn)入尾聲,很快將會(huì)應(yīng)用到生產(chǎn)環(huán)境。
分布式j(luò)oin
? ? ? ?分布式j(luò)oin在業(yè)界仍沒(méi)有完美的解決方案,好在聽(tīng)云業(yè)務(wù)在設(shè)計(jì)之初就從業(yè)務(wù)上避免了多表的join,在業(yè)務(wù)庫(kù)中,報(bào)表中的每個(gè)緯度都會(huì)有一張表與之對(duì)應(yīng),因此查詢某個(gè)緯度直接就會(huì)查詢后端的某張表,都是在每張表上做一些操作。目前比較流行的分布式j(luò)oin的解決方案主要有兩種:
? ? ? ?1、全局表的形式。舉個(gè)栗子,A表 join B表,B表分布式存儲(chǔ)在多個(gè)shared上,如果A表比較小,可以在所有的shared上都存一份A表的全量數(shù)據(jù)。那么就可以很高效的做join。看起來(lái)很美好,但是限制很多,應(yīng)用的場(chǎng)景也很有限。
? ? ? ?2、E-R形式。舉個(gè)栗子,用戶表user(id,name)和訂單表order(id,uid,detail),按用戶id分片,order表的uid引用自u(píng)ser表的id。存放訂單時(shí),首先確定該訂單對(duì)應(yīng)用戶所在的shared,然后將訂單記錄插入到用戶所在的shared上去,這樣檢索某個(gè)用戶所有的訂單時(shí),就可以避免跨庫(kù)join低效的操作。
? ? ? ?目前的開(kāi)源中間件中,MyCat對(duì)分布式j(luò)oin處理的是比較細(xì)膩的。阿里的DRDS對(duì)于分布式j(luò)oin的處理也是這樣的思路。
MySQL擅長(zhǎng)什么
? ? ? ?任何一種工具可能都只是解決某一個(gè)領(lǐng)域的問(wèn)題,肯定不是放之四海而皆準(zhǔn)的。正確的使用方式是讓工具做自己擅長(zhǎng)的事情。關(guān)系型數(shù)據(jù)庫(kù)擅長(zhǎng)的是結(jié)構(gòu)化的查詢,本身并不擅長(zhǎng)巨量數(shù)據(jù)的清洗。我們?cè)诔?015年度APP行業(yè)均值數(shù)據(jù)報(bào)表時(shí),需要將后端所有shared上的相關(guān)數(shù)據(jù)匯總起來(lái)然后做進(jìn)一步的分析,這些數(shù)據(jù)最終匯總在5張表中,每張表都有幾億條的記錄。然后對(duì)5、6個(gè)字段group by之后取某些指標(biāo)的 sum值,最初嘗試在MySQL中處理這些數(shù)據(jù),MySQL實(shí)例給出24GB的內(nèi)存,結(jié)果OOM了好幾次也沒(méi)有出結(jié)果。最后把數(shù)據(jù)拉到了hadoop集群上,使用impala引擎來(lái)匯總數(shù)據(jù),處理最大的表近7億條記錄,9min左右出結(jié)果。所以,不要有all ?in ?one的想法,要讓系統(tǒng)中的每個(gè)組件做自己擅長(zhǎng)的事情。
分布式MySQL架構(gòu)下的運(yùn)維
? ? ? ?MySQL分布式雖然解決了存儲(chǔ)和性能問(wèn)題,但是在運(yùn)維支持過(guò)程中卻帶來(lái)了一些痛點(diǎn)。
? ? ? ?1、跨分片統(tǒng)計(jì)數(shù)據(jù)。中間件是無(wú)法對(duì)后端的全量數(shù)據(jù)做查詢的,類似年度APP行業(yè)均值報(bào)表這樣的跨分片的全量數(shù)據(jù)的查詢,只能使用自動(dòng)化腳本從后端逐個(gè)shared上提取數(shù)據(jù),最終再匯總。
? ? ? ?2、DML。經(jīng)常會(huì)有變更表結(jié)構(gòu)的需求,這樣的操作大部分中間件是支持不了的,如果只有一個(gè)庫(kù)好說(shuō),當(dāng)后端幾十個(gè)shared時(shí),就比較頭疼了,目前我們并沒(méi)有很好的處理辦法,只能使用自動(dòng)化腳本批量到后端shared上執(zhí)行命令,執(zhí)行完成后,運(yùn)行一個(gè)校驗(yàn)的腳本,人工核對(duì)校驗(yàn)?zāi)_本的輸出內(nèi)容。
? ? ? ?應(yīng)對(duì)這樣的情景,發(fā)型必然會(huì)稍顯凌亂,但是目前仍舊很無(wú)奈,有必要重新設(shè)計(jì)一下我們的腳本,寫(xiě)一個(gè)輸出更加友好,完全自動(dòng)化的工具出來(lái)。
?
原文鏈接:http://blog.tingyun.com/web/article/detail/386
總結(jié)
以上是生活随笔為你收集整理的MySQL如何发型不乱的应对半年数十TB数据增量的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android入门——电话拨号器和四种点
- 下一篇: 格式化Json代码