一文搞定MySQL的分區(qū)技術(shù)、NoSQL、NewSQL、基于MySQL的分表分庫
分表分庫
上文講到,查詢分離的方案存在三大不足,其中一個就是:當主數(shù)據(jù)量越來越大時,寫操作會越來越緩慢。這個問題該如何解決呢?可以考慮分表分庫。
這里先介紹一下真實的業(yè)務場景,而后依次介紹拆分存儲時如何進行技術(shù)選型、分表分庫的實現(xiàn)思路是什么,以及分表分庫存在哪些不足。
接下來進入業(yè)務場景介紹。
業(yè)務場景:億級訂單數(shù)據(jù)如何實現(xiàn)快速讀寫
這次項目的對象是電商系統(tǒng)。該系統(tǒng)中大數(shù)據(jù)量的實體有兩個:用戶和訂單。每個實體涵蓋的數(shù)據(jù)量見表3-1。

表3-1 數(shù)據(jù)量
某天,領(lǐng)導召集IT部門人員開會,說:“根據(jù)市場推廣的趨勢,我們的訂單很快就會上億,每天會有100萬的新訂單。不要問我這個數(shù)據(jù)怎么出來的,總之,領(lǐng)導交代,讓IT部門提前做好技術(shù)準備,以防到時候系統(tǒng)撐不住”。
那時候同事們內(nèi)心是這樣想的:“又聽市場吹牛吧”。領(lǐng)導看了同事們的表情,也知道大家在想什么,他說:“我知道你們不相信,我也不相信。但是現(xiàn)在領(lǐng)導給大家任務了,要求系統(tǒng)可以支持上億訂單和每日百萬新訂單,服務器可以采購?!?/span>
做這個規(guī)劃之前,存儲訂單的數(shù)據(jù)庫表是一個單庫單表??梢灶A見,在不久的將來數(shù)據(jù)庫的I/O和CPU就可能支撐不住,因為訂單系統(tǒng)原來就不是很快。
然后項目組做了簡單的功能,插入一些測試數(shù)據(jù),訂單量到2000萬的時候,響應時長就不可接受了。為了使系統(tǒng)能承受這種日百萬級新訂單的壓力,項目組探討過很多解決方案,最終決定使用分表分庫:先將訂單表拆分,再進行分布存儲。
原來的訂單表就是一個sale數(shù)據(jù)庫里面的一張order表,之后就會創(chuàng)建多個order數(shù)據(jù)庫order1,order2,order3,order4,……,每個數(shù)據(jù)庫里面又有多張訂單表t_order_1,t_order_2,t_order_3,……。
當 然 , 訂 單 子 表 也 是 多 張 :t_order_item_1 , t_order_item_2 ,t_order_item_3,……。
訂單數(shù)據(jù)根據(jù)一定的規(guī)律分布存儲在不同order庫里的不同order表中。
其實項目組并不是一開始就打算用分表分庫,當初也評估了一下拆分存儲的其他技術(shù)方案。接下來介紹當時是怎么選型的。
拆分存儲的技術(shù)選型
拆分存儲常用的技術(shù)解決方案目前主要分為4種:MySQL的分區(qū)技術(shù)、NoSQL、NewSQL、基于MySQL的分表分庫。
MySQL的分區(qū)技術(shù)
圖3-1所示為MySQL官方文檔中的架構(gòu)圖。MySQL的分區(qū)技術(shù)主要體現(xiàn)在圖3-1中的文件存儲層File System,它可以將一張表的不同行存放在不同的存儲文件中,這對使用者來說比較透明。
在以往的項目中,項目組不使用它的原因主要有3點。
1)MySQL的實例只有一個,它僅僅分攤了存儲,無法分攤請求負載。
2)正是因為MySQL的分區(qū)對用戶透明,所以用戶在實際操作時往往不太注意,如果SQL跨了分區(qū),那么操作就會嚴重影響系統(tǒng)性能。
3)MySQL還有一些其他限制,比如不支持query cache、位操作表達式等 。
感 興 趣 的 讀 者 可 以 查 看 官 方 文 檔 中 的 相 關(guān) 內(nèi) 容
https://dev.mysql.com/doc/refman/5.7/en/partitioninglimitations.html。

NoSQL
比較典型的NoSQL數(shù)據(jù)庫就是MongoDB。MongoDB的分片功能從并發(fā)性和數(shù)據(jù)量這兩個角度已經(jīng)能滿足一般大數(shù)據(jù)量的需求,但是還需要注意下面3點。
1)約束考量:MongoDB不是關(guān)系型數(shù)據(jù)庫而是文檔型數(shù)據(jù)庫,它的每一行記錄都是一個結(jié)構(gòu)靈活可變的JSON,比如存儲非常重要的訂單數(shù)據(jù)時,就不能使用MongoDB,因為訂單數(shù)據(jù)必須使用強約束的關(guān)系型數(shù)據(jù)庫進行存儲。舉個例子,訂單里面有金額相關(guān)的字段,這是系統(tǒng)里面的核心數(shù)據(jù),所以必須保證每個訂單數(shù)據(jù)都有這些金額相關(guān)的字段,并且不管是怎樣的業(yè)務邏輯修改,這些字段都要保存好,這時可以通過數(shù)據(jù)庫的能力加一層校驗,這樣即使業(yè)務代碼出了問題,導致這些字段存儲不正確,也可以在數(shù)據(jù)庫這一層面阻隔問題。
當然,MongoDB 3.2版以后也支持Schema Validation(模式驗證),可以制訂一些約束規(guī)則。不過項目組使用MongoDB的原因之一就是看重它靈活的Schema(模式)。
2)業(yè)務功能考量:訂單這種跟交易相關(guān)的數(shù)據(jù)肯定要支持事務和并發(fā)控制,而這些并不是MongoDB的強項。而且除了這些功能以外,多年來,事務、鎖、SQL、表達式等各種各樣的操作都在MySQL身上一一實踐過,MySQL可以說是久經(jīng)考驗,因此在功能上MySQL能滿足項目所有的業(yè)務需求,MongoDB卻不一定能,且大部分的NoSQL也存在類似復雜功能支持的問題。
3)穩(wěn)定性考量:人們對MySQL的運維已經(jīng)很熟悉了,它的穩(wěn)定性沒有問題,然而MongoDB的穩(wěn)定性無法保證,畢竟很多人不熟悉。
基于以上的原因,當時項目組排除了MongoDB。
NewSQL
NewSQL技術(shù)還比較新,筆者曾經(jīng)想在一些不重要的數(shù)據(jù)中使用NewSQL(比如TiDB),但從穩(wěn)定性和功能擴展性兩方面考量后,最終沒有使用,具體原因與MongoDB類似。
基于MySQL的分表分庫
最后說一下基于MySQL的分表分庫:分表是將一份大的表數(shù)據(jù)進行拆分后存放至多個結(jié)構(gòu)一樣的拆分表中;分庫就是將一個大的數(shù)據(jù)庫拆分成類似于多個結(jié)構(gòu)的小數(shù)據(jù)庫。場景介紹里就舉了個簡單的例子,這里不再贅述。
項目組沒有選用前面介紹的3種拆分存儲技術(shù),而是選擇了基于MySQL的分表分庫,其中有一個重要考量:分表分庫對于第三方依賴較少,業(yè)務邏輯靈活可控,它本身并不需要非常復雜的底層處理,也不需要重新做數(shù)據(jù)庫,只是根據(jù)不同邏輯使用不同SQL語句和數(shù)據(jù)源而已,因此,之后出問題的時候也能夠較快地找出根源。
如果使用分表分庫,有3個通用技術(shù)需求需要實現(xiàn)。
1)SQL組合:因為關(guān)聯(lián)的表名是動態(tài)的,所以需要根據(jù)邏輯組裝動態(tài)的SQL。比如,要根據(jù)一個訂單的ID獲取訂單的相關(guān)數(shù)據(jù),Select語句應該針對(From)哪一張表?
2)數(shù)據(jù)庫路由:因為數(shù)據(jù)庫名也是動態(tài)的,所以需要通過不同的邏輯使用不同的數(shù)據(jù)庫。比如,如果要根據(jù)訂單ID獲取數(shù)據(jù),怎么知道要連接哪一個數(shù)據(jù)庫?
3)執(zhí)行結(jié)果合并:有些需求需要通過多個分庫執(zhí)行后再合并歸集起來。
假設(shè)需要查詢的數(shù)據(jù)分布在多個數(shù)據(jù)庫的多個表中(比如在order1里面的t_order_1,order2里面的t_order_9中),那么需要將針對這些表的查詢結(jié)果合并成一個數(shù)據(jù)集。
而目前能解決以上問題的中間件分為兩類:Proxy模式、Client模式。
1)Proxy模式:圖3-2所示為ShardingSphere官方文檔中的Proxy模式圖,重點看中間的Sharding-Proxy層。
這種設(shè)計模式將SQL組合、數(shù)據(jù)庫路由、執(zhí)行結(jié)果合并等功能全部放在了一個代理服務中,而與分表分庫相關(guān)的處理邏輯全部放在了其他服務中,其優(yōu)點是對業(yè)務代碼無侵入,業(yè)務只需要關(guān)注自身業(yè)務邏輯即可。
2)Client模式:ShardingSphere官方文檔中的Client模式如圖3-3所示。
這種設(shè)計模式將分表分庫相關(guān)邏輯放在客戶端,一般客戶端的應用會引用一個jar,然后在jar中處理SQL組合、數(shù)據(jù)庫路由、執(zhí)行結(jié)果合并等相關(guān)功能。

? 圖3-2 Proxy模式圖

? 圖3-3 Client模式圖
這兩種模式的中間件見表3-2。

表3-2 常見分表分庫中間件
這兩種開源中間件的設(shè)計模式該如何選擇呢?先簡單對比一下它們的優(yōu)缺點,見表3-3。

表3-3 Client模式與Proxy模式的優(yōu)缺點
因為看重“代碼靈活可控”這個優(yōu)勢,項目組最終選擇了Client模式里的Sharding-JDBC來實現(xiàn)分表分庫,如圖3-3所示。
當然,關(guān)于拆分存儲選擇哪種技術(shù)合適,在實際工作中需要根據(jù)具體情況來定。
本文給大家講解的內(nèi)容是分庫分表:拆分存儲的技術(shù)選型
下篇文章給大家講解的內(nèi)容是分庫分表:分表分庫實現(xiàn)思路
覺得文章不錯的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;
感謝大家的支持
本文就是愿天堂沒有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學習更多的話可以到微信公眾號里找我,我等你哦。
