海量数据的分库分表技术演进,最佳实践
每個(gè)優(yōu)秀的程序員和架構(gòu)師都應(yīng)該掌握分庫(kù)分表,移動(dòng)互聯(lián)網(wǎng)時(shí)代,海量的用戶每天產(chǎn)生海量的數(shù)量
- 用戶表
- 訂單表
- 交易流水表
以支付寶用戶為例,8億;微信用戶更是10億。訂單表更夸張,比如美團(tuán)外賣,每天都是幾千萬的訂單。淘寶的歷史訂單總量應(yīng)該百億,甚至千億級(jí)別,這些海量數(shù)據(jù)遠(yuǎn)不是一張表能Hold住的。事實(shí)上MySQL單表可以存儲(chǔ)10億級(jí)數(shù)據(jù),只是這時(shí)候性能比較差,業(yè)界公認(rèn)MySQL單表容量在1KW以下是最佳狀態(tài),因?yàn)檫@時(shí)它的BTREE索引樹高在3~5之間。
既然一張表無法搞定,那么就想辦法將數(shù)據(jù)放到多個(gè)地方,目前比較普遍的方案有3個(gè):
說明:只分庫(kù),或者只分表,或者分庫(kù)分表融合方案都統(tǒng)一認(rèn)為是分庫(kù)分表方案,因?yàn)榉謳?kù),或者分表只是一種特殊的分庫(kù)分表而已。NoSQL比較具有代表性的是MongoDB,es。NewSQL比較具有代表性的是TiDB。
?
Why Not NoSQL/NewSQL?
首先,為什么不選擇第三種方案NoSQL/NewSQL,我認(rèn)為主要是RDBMS有以下幾個(gè)優(yōu)點(diǎn): ?
- RDBMS生態(tài)完善; ? ?
- RDBMS絕對(duì)穩(wěn)定; ? ?
- RDBMS的事務(wù)特性;
NoSQL/NewSQL作為新生兒,在我們把可靠性當(dāng)做首要考察對(duì)象時(shí),它是無法與RDBMS相提并論的。RDBMS發(fā)展幾十年,只要有軟件的地方,它都是核心存儲(chǔ)的首選。
目前絕大部分公司的核心數(shù)據(jù)都是:以RDBMS存儲(chǔ)為主,NoSQL/NewSQL存儲(chǔ)為輔!互聯(lián)網(wǎng)公司又以MySQL為主,國(guó)企&銀行等不差錢的企業(yè)以O(shè)racle/DB2為主!NoSQL/NewSQL宣傳的無論多牛逼,就現(xiàn)在各大公司對(duì)它的定位,都是RDBMS的補(bǔ)充,而不是取而代之!
?
Why Not 分區(qū)?
我們?cè)倏捶謪^(qū)表方案。了解這個(gè)方案之前,先了解它的原理:
分區(qū)表是由多個(gè)相關(guān)的底層表實(shí)現(xiàn),這些底層表也是由句柄對(duì)象表示,所以我們也可以直接訪問各個(gè)分區(qū),存儲(chǔ)引擎管理分區(qū)的各個(gè)底層表和管理普通表一樣(所有的底層表都必須使用相同的存儲(chǔ)引擎),分區(qū)表的索引只是在各個(gè)底層表上各自加上一個(gè)相同的索引,從存儲(chǔ)引擎的角度來看,底層表和一個(gè)普通表沒有任何不同,存儲(chǔ)引擎也無須知道這是一個(gè)普通表還是一個(gè)分區(qū)表的一部分。
事實(shí)上,這個(gè)方案也不錯(cuò),它對(duì)用戶屏蔽了sharding的細(xì)節(jié),即使查詢條件沒有sharding column,它也能正常工作(只是這時(shí)候性能一般)。不過它的缺點(diǎn)很明顯:很多的資源都受到單機(jī)的限制,例如連接數(shù),網(wǎng)絡(luò)吞吐等!雖然每個(gè)分區(qū)可以獨(dú)立存儲(chǔ),但是分區(qū)表的總?cè)肟谶€是一個(gè)MySQL實(shí)例。從而導(dǎo)致它的并發(fā)能力非常一般,遠(yuǎn)遠(yuǎn)達(dá)不到互聯(lián)網(wǎng)高并發(fā)的要求!
至于網(wǎng)上提到的一些其他缺點(diǎn)比如:無法使用外鍵,不支持全文索引。我認(rèn)為這都不算缺點(diǎn),21世紀(jì)的項(xiàng)目如果還是使用外鍵和數(shù)據(jù)庫(kù)的全文索引,我都懶得吐槽了!
所以,如果使用分區(qū)表,你的業(yè)務(wù)應(yīng)該具備如下兩個(gè)特點(diǎn):
?
Why 分庫(kù)分表?
最后要介紹的就是目前互聯(lián)網(wǎng)行業(yè)處理海量數(shù)據(jù)的通用方法:分庫(kù)分表。
雖然大家都是采用分庫(kù)分表方案來處理海量核心數(shù)據(jù),但是還沒有一個(gè)一統(tǒng)江湖的中間件,筆者這里列舉一些有一定知名度的分庫(kù)分表中間件:
- 阿里的TDDL,DRDS和cobar,
- 開源社區(qū)的sharding-jdbc(3.x已經(jīng)更名為sharding-sphere);
- 民間組織的MyCAT;
- 360的Atlas;
- 美團(tuán)的zebra;
備注:sharding-jdbc的作者張亮大神原來在當(dāng)當(dāng),現(xiàn)在在京東金融。但是sharding-jdbc的版權(quán)屬于開源社區(qū),不是公司的,也不是張亮個(gè)人的!
其他比如網(wǎng)易,58,京東等公司都有自研的中間件。總之各自為戰(zhàn),也可以說是百花齊放。
但是這么多的分庫(kù)分表中間件全部可以歸結(jié)為兩大類型:
- CLIENT模式;
- PROXY模式;
CLIENT模式代表有阿里的TDDL,開源社區(qū)的sharding-jdbc(sharding-jdbc的3.x版本即sharding-sphere已經(jīng)支持了proxy模式)。架構(gòu)如下:
PROXY模式代表有阿里的cobar,民間組織的MyCAT。架構(gòu)如下:
但是,無論是CLIENT模式,還是PROXY模式。幾個(gè)核心的步驟是一樣的:SQL解析,重寫,路由,執(zhí)行,結(jié)果歸并。
筆者比較傾向于CLIENT模式,架構(gòu)簡(jiǎn)單,性能損耗較小,運(yùn)維成本低。
接下來,以幾個(gè)常見的大表為案例,說明分庫(kù)分表如何落地!
?
實(shí)戰(zhàn)案例
分庫(kù)分表第一步也是最重要的一步,即sharding column的選取,sharding column選擇的好壞將直接決定整個(gè)分庫(kù)分表方案最終是否成功。而sharding column的選取跟業(yè)務(wù)強(qiáng)相關(guān),筆者認(rèn)為選擇sharding column的方法最主要分析你的API流量,優(yōu)先考慮流量大的API,將流量比較大的API對(duì)應(yīng)的SQL提取出來,將這些SQL共同的條件作為sharding column。例如一般的OLTP系統(tǒng)都是對(duì)用戶提供服務(wù),這些API對(duì)應(yīng)的SQL都有條件用戶ID,那么,用戶ID就是非常好的sharding column。
這里列舉分庫(kù)分表的幾種主要處理思路:
再以幾張實(shí)際表為例,說明如何分庫(kù)分表。
訂單表
訂單表幾個(gè)核心字段一般如下:
以阿里訂單系統(tǒng)為例(參考《企業(yè)IT架構(gòu)轉(zhuǎn)型之道:阿里巴巴中臺(tái)戰(zhàn)略思想與架構(gòu)實(shí)現(xiàn)》),它選擇了三個(gè)column作為三個(gè)獨(dú)立的sharding column,即:orderid,userid,merchantcode。userid和merchantcode就是買家ID和賣家ID,因?yàn)榘⒗锏挠唵蜗到y(tǒng)中買家和賣家的查詢流量都比較大,并且查詢對(duì)實(shí)時(shí)性要求都很高。而根據(jù)orderid進(jìn)行分庫(kù)分表,應(yīng)該是根據(jù)order_id的查詢也比較多。
這里還有一點(diǎn)需要提及,多個(gè)sharding-column的分庫(kù)分表是冗余全量還是只冗余關(guān)系索引表,需要我們自己權(quán)衡。
冗余全量的情況如下--每個(gè)sharding列對(duì)應(yīng)的表的數(shù)據(jù)都是全量的,這樣做的優(yōu)點(diǎn)是不需要二次查詢,性能更好,缺點(diǎn)是比較浪費(fèi)存儲(chǔ)空間(淺綠色字段就是sharding-column):
冗余關(guān)系索引表的情況如下--只有一個(gè)sharding column的分庫(kù)分表的數(shù)據(jù)是全量的,其他分庫(kù)分表只是與這個(gè)sharding column的關(guān)系表,這樣做的優(yōu)點(diǎn)是節(jié)省空間,缺點(diǎn)是除了第一個(gè)sharding column的查詢,其他sharding column的查詢都需要二次查詢,這三張表的關(guān)系如下圖所示(淺綠色字段就是sharding column):
冗余全量表PK.冗余關(guān)系表
總結(jié):選擇冗余全量表還是索引關(guān)系表,這是一種架構(gòu)上的trade off,兩者的優(yōu)缺點(diǎn)明顯,阿里的訂單表是冗余全量表。
用戶表
用戶表幾個(gè)核心字段一般如下:
一般用戶登錄場(chǎng)景既可以通過mobileno,又可以通過email,還可以通過username進(jìn)行登錄。但是一些用戶相關(guān)的API,又都包含userid,那么可能需要根據(jù)這4個(gè)column都進(jìn)行分庫(kù)分表,即4個(gè)列都是sharding-column。
賬戶表
賬戶表幾個(gè)核心字段一般如下:
與賬戶表相關(guān)的API,一般條件都有accountno,所以以accountno作為sharding-column即可。
復(fù)雜查詢
上面提到的都是條件中有sharding column的SQL執(zhí)行。但是,總有一些查詢條件是不包含sharding column的,同時(shí),我們也不可能為了這些請(qǐng)求量并不高的查詢,無限制的冗余分庫(kù)分表。那么這些條件中沒有sharding column的SQL怎么處理?以sharding-jdbc為例,有多少個(gè)分庫(kù)分表,就要并發(fā)路由到多少個(gè)分庫(kù)分表中執(zhí)行,然后對(duì)結(jié)果進(jìn)行合并。具體如何合并,可以看筆者sharding-jdbc系列文章,有分析源碼講解合并原理。
這種條件查詢相對(duì)于有sharding column的條件查詢性能很明顯會(huì)下降很多。如果有幾十個(gè),甚至上百個(gè)分庫(kù)分表,只要某個(gè)表的執(zhí)行由于某些因素變慢,就會(huì)導(dǎo)致整個(gè)SQL的執(zhí)行響應(yīng)變慢,這非常符合木桶理論。
更有甚者,那些運(yùn)營(yíng)系統(tǒng)中的模糊條件查詢,或者上十個(gè)條件篩選。這種情況下,即使單表都不好創(chuàng)建索引,更不要說分庫(kù)分表的情況下。那么怎么辦呢?這個(gè)時(shí)候大名鼎鼎的elasticsearch,即es就派上用場(chǎng)了。將分庫(kù)分表所有數(shù)據(jù)全量冗余到es中,將那些復(fù)雜的查詢交給es處理。
淘寶我的所有訂單頁(yè)面如下,篩選條件有多個(gè),且商品標(biāo)題可以模糊匹配,這即使是單表都解決不了的問題(索引滿足不了這種場(chǎng)景),更不要說分庫(kù)分表了:
所以,以訂單表為例,整個(gè)架構(gòu)如下:
具體情況具體分析:多sharding column不到萬不得已的情況下最好不要使用,成本較大,上面提到的用戶表筆者就不太建議使用。因?yàn)橛脩舯碛幸粋€(gè)很大的特點(diǎn)就是它的上限是肯定的,即使全球70億人全是你的用戶,這點(diǎn)數(shù)據(jù)量也不大,所以筆者更建議采用單sharding column + es的模式簡(jiǎn)化架構(gòu)。
es+HBase簡(jiǎn)要
這里需要提前說明的是,solr+HBase結(jié)合的方案在社區(qū)中出現(xiàn)的頻率可能更高,本篇文章為了保持一致性,所有全文索引方案選型都是es。至于es+HBase和solr+HBase孰優(yōu)孰劣,或者說es和solr孰優(yōu)孰劣,不是本文需要討論的范疇,事實(shí)上也沒有太多討論的意義。es和solr本就是兩個(gè)非常優(yōu)秀且旗鼓相當(dāng)?shù)闹虚g件。最近幾年es更火爆:
如果拋開選型過程中所有歷史包袱,單論es+HBase和solr+HBase的優(yōu)劣,很明顯后者是更好的選擇。solr+HBase高度集成,引入索引服務(wù)后我們最關(guān)心,也是最重要的索引一致性問題,solr+HBase已經(jīng)有了非常成熟的解決方案一一Lily HBase Indexer。
延伸閱讀
阿里云上的云數(shù)據(jù)庫(kù)HBase版也是借助solr實(shí)現(xiàn)全文索引,有興趣的同學(xué)可以戳鏈接了解更多:https://help.aliyun.com/product/49055.html?spm=5176.124785.631202.con1.603452c0cz7bj2。
es+HBase原理
剛剛討論到上面的以MySQL為核心,分庫(kù)分表+es的方案,隨著數(shù)據(jù)量越來越大,雖然分庫(kù)分表可以繼續(xù)成倍擴(kuò)容,但是這時(shí)候壓力又落到了es這里,這個(gè)架構(gòu)也會(huì)慢慢暴露出問題!
一般訂單表,積分明細(xì)表等需要分庫(kù)分表的核心表都會(huì)有好幾十列,甚至上百列(假設(shè)有50列),但是整個(gè)表真正需要參與條件索引的可能就不到10個(gè)條件(假設(shè)有10列)。這時(shí)候把50個(gè)列所有字段的數(shù)據(jù)全量索引到es中,對(duì)es集群有很大的壓力,后面的es分片故障恢復(fù)也會(huì)需要很長(zhǎng)的時(shí)間。
這個(gè)時(shí)候我們可以考慮減少es的壓力,讓es集群有限的資源盡可能保存條件檢索時(shí)最需要的最有價(jià)值的數(shù)據(jù),即只把可能參與條件檢索的字段索引到es中,這樣整個(gè)es集群壓力減少到原來的1/5(核心表50個(gè)字段,只有10個(gè)字段參與條件),而50個(gè)字段的全量數(shù)據(jù)保存到HBase中,這就是經(jīng)典的es+HBase組合方案,即索引與數(shù)據(jù)存儲(chǔ)隔離的方案。
Hadoop體系下的HBase存儲(chǔ)能力我們都知道是海量的,而且根據(jù)它的rowkey查詢性能那叫一個(gè)快如閃電。而es的多條件檢索能力非常強(qiáng)大。這個(gè)方案把es和HBase的優(yōu)點(diǎn)發(fā)揮的淋漓盡致,同時(shí)又規(guī)避了它們的缺點(diǎn),可以說是一個(gè)揚(yáng)長(zhǎng)避短的最佳實(shí)踐。
它們之間的交互大概是這樣的:先根據(jù)用戶輸入的條件去es查詢獲取符合過濾條件的rowkey值,然后用rowkey值去HBase查詢,后面這一查詢步驟的時(shí)間幾乎可以忽略,因?yàn)檫@是HBase最擅長(zhǎng)的場(chǎng)景,交互圖如下所示:
HBase檢索能力擴(kuò)展
圖片來源于HBase技術(shù)社區(qū)-HBase應(yīng)用實(shí)踐專場(chǎng)-HBase for Solr
?
總結(jié)
最后,對(duì)幾種方案總結(jié)如下(sharding column簡(jiǎn)稱為sc):
| 適用場(chǎng)景 | 單一 | 一般 | 比較廣泛 | 非常廣泛 |
| 查詢及時(shí)性 | 及時(shí) | 及時(shí) | 比較及時(shí) | 比較及時(shí) |
| 存儲(chǔ)能力 | 一般 | 一般 | 較大 | 海量 |
| 代碼成本 | 很小 | 較大 | 一般 | 一般 |
| 架構(gòu)復(fù)雜度 | 簡(jiǎn)單 | 一般 | 較難 | 非常復(fù)雜 |
總之,對(duì)于海量數(shù)據(jù),且有一定的并發(fā)量的分庫(kù)分表,絕不是引入某一個(gè)分庫(kù)分表中間件就能解決問題,而是一項(xiàng)系統(tǒng)的工程。需要分析整個(gè)表相關(guān)的業(yè)務(wù),讓合適的中間件做它最擅長(zhǎng)的事情。例如有sharding column的查詢走分庫(kù)分表,一些模糊查詢,或者多個(gè)不固定條件篩選則走es,海量存儲(chǔ)則交給HBase。
做了這么多事情后,后面還會(huì)有很多的工作要做,比如數(shù)據(jù)同步的一致性問題,還有運(yùn)行一段時(shí)間后,某些表的數(shù)據(jù)量慢慢達(dá)到單表瓶頸,這時(shí)候還需要做冷數(shù)據(jù)遷移。總之,分庫(kù)分表是一項(xiàng)非常復(fù)雜的系統(tǒng)工程。任何海量數(shù)據(jù)的處理,都不是簡(jiǎn)單的事情,做好戰(zhàn)斗的準(zhǔn)備!
總結(jié)
以上是生活随笔為你收集整理的海量数据的分库分表技术演进,最佳实践的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 工作是属于公司的,而职业生涯却是属于你自
- 下一篇: 假笨说-协助美团kafka团队定位到的一