1. 程式人生 > >分庫分表的幾種常見形式

分庫分表的幾種常見形式

垂直分表:垂直分表在日常開發和設計中比較常見,通俗的說法叫做“大表拆小表”,拆分是基於關係型資料庫中的“列”(欄位)進行的。通常情況,某個表中的欄位比較多,可以新建立一張“擴充套件表”,將不經常使用或者長度較大的欄位拆分出去放到“擴充套件表”中

ps:在欄位很多的情況下,拆分開確實更便於開發和維護(曾見過某個遺留系統中,一個大表中包含100多列的)。某種意義上也能避免“跨頁”的問題(MySQL、MSSQL底層都是通過“資料頁”來儲存的,“跨頁”問題可能會造成額外的效能開銷)。拆分欄位的操作建議在資料庫設計階段就做好。如果是在發展過程中拆分,則需要改寫以前的查詢語句,會額外帶來一定的成本和風險,建議謹慎。

垂直分庫:基本的思路就是按照業務模組來劃分出不同的資料庫,而不是像早期一樣將所有的資料表都放到同一個資料庫中。

ps:系統層面的“服務化”拆分操作,能夠解決業務系統層面的耦合和效能瓶頸,有利於系統的擴充套件維護。而資料庫層面的拆分,道理也是相通的。與服務的“治理”和“降級”機制類似,我們也能對不同業務型別的資料進行“分級”管理、維護、監控、擴充套件等。眾所周知,資料庫往往最容易成為應用系統的瓶頸,而資料庫本身屬於“有狀態”的,相對於Web和應用伺服器來講,是比較難實現“橫向擴充套件”的。資料庫的連線資源比較寶貴且單機處理能力也有限,在高併發場景下,垂直分庫一定程度上能夠突破IO、連線數及單機硬體資源的瓶頸,是大型分散式系統中優化資料庫架構的重要手段。

水平分表:水平分表也稱為橫向分表,比較容易理解,就是將表中不同的資料行按照一定規律分佈到不同的資料庫表中(這些表儲存在同一個資料庫中),這樣來降低單表資料量,優化查詢效能。最常見的方式就是通過主鍵或者時間等欄位進行Hash和取模後拆分。

ps:水平分表,能夠降低單表的資料量,一定程度上可以緩解查詢效能瓶頸。但本質上這些表還儲存在同一個庫中,所以庫級別還是會有IO瓶頸。所以,一般不建議採用這種做法。

水平分庫分表:水平分庫分表與上面講到的水平分表的思想相同,唯一不同的就是將這些拆分出來的表儲存在不同的資料庫中。這也是很多大型網際網路公司所選擇的做法。

ps:某種意義上來講,有些系統中使用的“冷熱資料分離”(將一些使用較少的歷史資料遷移到其他的資料庫中。而在業務功能上,通常預設只提供熱點資料的查詢),也是類似的實踐。在高併發和海量資料的場景下,分庫分表能夠有效緩解單機和單庫的效能瓶頸和壓力,突破IO、連線數、硬體資源的瓶頸。當然,投入的硬體成本也會更高。同時,這也會帶來一些複雜的技術問題和挑戰(例如:跨分片的複雜查詢,跨分片事務等)

垂直分庫帶來的問題和解決思路

跨庫join的問題

在拆分之前,系統中很多列表和詳情頁所需的資料是可以通過sql join來完成的。而拆分後,資料庫可能是分散式在不同例項和不同的主機上,join將變得非常麻煩。而且基於架構規範,效能,安全性等方面考慮,一般是禁止跨庫join的。那該怎麼辦呢?首先要考慮下垂直分庫的設計問題,如果可以調整,那就優先調整。如果無法調整的情況,下面將結合以往的實際經驗,總結幾種常見的解決思路,並分析其適用場景。

跨庫Join的幾種解決思路

全域性表

所謂全域性表,就是有可能系統中所有模組都可能會依賴到的一些表。比較類似我們理解的“資料字典”。為了避免跨庫join查詢,我們可以將這類表在其他每個資料庫中均儲存一份。同時,這類資料通常也很少發生修改(甚至幾乎不會),所以也不用太擔心“一致性”問題。

欄位冗餘

這是一種典型的反正規化設計,在網際網路行業中比較常見,通常是為了效能來避免join查詢。

舉個電商業務中很簡單的場景:

“訂單表”中儲存“賣家Id”的同時,將賣家的“Name”欄位也冗餘,這樣查詢訂單詳情的時候就不需要再去查詢“賣家使用者表”。

欄位冗餘能帶來便利,是一種“空間換時間”的體現。但其適用場景也比較有限,比較適合依賴欄位較少的情況。最複雜的還是資料一致性問題,這點很難保證,可以藉助資料庫中的觸發器或者在業務程式碼層面去保證。當然,也需要結合實際業務場景來看一致性的要求。就像上面例子,如果賣家修改了Name之後,是否需要在訂單資訊中同步更新呢?

資料同步

A庫中的tab_a表和B庫中tbl_b有關聯,可以定時將指定的表做同步。當然,同步本來會對資料庫帶來一定的影響,需要效能影響和資料時效性中取得一個平衡。這樣來避免複雜的跨庫查詢。

系統層組裝

在系統層面,通過呼叫不同模組的元件或者服務,獲取到資料並進行欄位拼裝。說起來很容易,但實踐起來可真沒有這麼簡單,尤其是資料庫設計上存在問題但又無法輕易調整的時候。具體情況通常會比較複雜。組裝的時候要避免迴圈呼叫服務,迴圈RPC,迴圈查詢資料庫,最好一次性返回所有資訊,在程式碼裡做組裝。

跨庫事務(分散式事務)的問題

http://www.infoq.com/cn/articles/solution-of-distributed-system-transaction-consistency

水平分庫帶來的問題和解決思路

分散式全域性唯一ID

我們往往直接使用資料庫自增特性來生成主鍵ID,這樣確實比較簡單。而在分庫分表的環境中,資料分佈在不同的分片上,不能再借助資料庫自增長特性直接生成,否則會造成不同分片上的資料表主鍵會重複。簡單介紹幾種ID生成演算法。

  1. Twitter的Snowflake(又名“雪花演算法”)

  2. UUID/GUID(一般應用程式和資料庫均支援)

  3. MongoDB ObjectID(類似UUID的方式)

  4. Ticket Server(資料庫生存方式,Flickr採用的就是這種方式)

其中,Twitter 的Snowflake演算法生成的是64位唯一Id(由41位的timestamp+ 10位自定義的機器碼+ 13位累加計數器組成)。

分片欄位該如何選擇

在開始分片之前,我們首先要確定分片欄位(也可稱為“片鍵”)。很多常見的例子和場景中是採用ID或者時間欄位進行拆分。這也並不絕對的,我的建議是結合實際業務,通過對系統中執行的sql語句進行統計分析,選擇出需要分片的那個表中最頻繁被使用,或者最重要的欄位來作為分片欄位。

常見分片規則

常見的分片策略有隨機分片和連續分片這兩種,當需要使用分片欄位進行範圍查詢時,連續分片可以快速定位分片進行高效查詢,大多數情況下可以有效避免跨分片查詢的問題。後期如果想對整個分片叢集擴容時,只需要新增節點即可,無需對其他分片的資料進行遷移。但是,連續分片也有可能存在資料熱點的問題,有些節點可能會被頻繁查詢壓力較大,熱資料節點就成為了整個叢集的瓶頸。而有些節點可能存的是歷史資料,很少需要被查詢到。隨機分片其實並不是隨機的,也遵循一定規則。通常,我們會採用Hash取模的方式進行分片拆分,所以有些時候也被稱為離散分片。隨機分片的資料相對比較均勻,不容易出現熱點和併發訪問的瓶頸。但是,後期分片叢集擴容起來需要遷移舊的資料。使用一致性Hash演算法能夠很大程度的避免這個問題,所以很多中介軟體的分片叢集都會採用一致性Hash演算法。離散分片也很容易面臨跨分片查詢的複雜問題。

資料遷移,容量規劃,擴容等問題

很少有專案會在初期就開始考慮分片設計的,一般都是在業務高速發展面臨效能和儲存的瓶頸時才會提前準備。因此,不可避免的就需要考慮歷史資料遷移的問題。一般做法就是通過程式先讀出歷史資料,然後按照指定的分片規則再將資料寫入到各個分片節點中。此外,我們需要根據當前的資料量和QPS等進行容量規劃,綜合成本因素,推算出大概需要多少分片(一般建議單個分片上的單表資料量不要超過1000W)。如果是採用隨機分片,則需要考慮後期的擴容問題,相對會比較麻煩。如果是採用的範圍分片,只需要新增節點就可以自動擴容。

跨分片的排序分頁 

分頁時需要按照指定欄位進行排序。當排序欄位就是分片欄位的時候,我們通過分片規則可以比較容易定位到指定的分片,而當排序欄位非分片欄位的時候,情況就會變得比較複雜了。為了最終結果的準確性,我們需要在不同的分片節點中將資料進行排序並返回,並將不同分片返回的結果集進行彙總和再次排序,最後再返回給使用者。

跨分片的函式處理

在使用Max、Min、Sum、Count之類的函式進行統計和計算的時候,需要先在每個分片資料來源上執行相應的函式處理,然後再將各個結果集進行二次處理,最終再將處理結果返回。

跨分片join

Join是關係型資料庫中最常用的特性,但是在分片叢集中,join也變得非常複雜。應該儘量避免跨分片的join查詢(這種場景,比上面的跨分片分頁更加複雜,而且對效能的影響很大)。通常有以下幾種方式來避免:

全域性表

全域性表的概念之前在“垂直分庫”時提過。基本思想一致,就是把一些類似資料字典又可能會產生join查詢的表資訊放到各分片中,從而避免跨分片的join。

ER分片

在關係型資料庫中,表之間往往存在一些關聯的關係。如果我們可以先確定好關聯關係,並將那些存在關聯關係的表記錄存放在同一個分片上,那麼就能很好的避免跨分片join問題。在一對多關係的情況下,我們通常會選擇按照資料較多的那一方進行拆分。

記憶體計算

隨著spark記憶體計算的興起,理論上來講,很多跨資料來源的操作問題看起來似乎都能夠得到解決。可以將資料丟給spark叢集進行記憶體計算,最後將計算結果返回。

我們的系統真的需要分庫分表嗎?

其實這點沒有明確的判斷標準,比較依賴實際業務情況和經驗判斷。一般MySQL單表1000W左右的資料是沒有問題的(前提是應用系統和資料庫等層面設計和優化的比較好)。

當然,除了考慮當前的資料量和效能情況時,作為架構師,我們需要提前考慮系統半年到一年左右的業務增長情況,對資料庫伺服器的QPS、連線數、容量等做合理評估和規劃,並提前做好相應的準備工作。如果單機無法滿足,且很難再從其他方面優化,那麼說明是需要考慮分片的。這種情況可以先去掉資料庫中自增ID,為分片和後面的資料遷移工作提前做準備。

很多人覺得“分庫分表”是宜早不宜遲,應該儘早進行,因為擔心越往後公司業務發展越快、系統越來越複雜、系統重構和擴充套件越困難…這種話聽起來是有那麼一點道理,但我的觀點恰好相反,對於關係型資料庫來講,我認為“能不分片就別分片”,除非是系統真正需要,因為資料庫分片並非低成本或者免費的。這裡推薦一個比較靠譜的過渡技術–“表分割槽”。主流的關係型資料庫中基本都支援。不同的分割槽在邏輯上仍是一張表,但是物理上卻是分開的,能在一定程度上提高查詢效能,而且對應用程式透明,無需修改任何程式碼。當時有一個系統,主業務表有大約8000W左右的資料,考慮到成本問題,當時就是採用“表分割槽”來做的,效果比較明顯,且系統執行的很穩定。

小結

當前主要有兩類解決方案:

  1. 基於應用程式層面的DDAL(分散式資料庫訪問層) 

    比較典型的就是淘寶半開源的TDDL,噹噹網開源的Sharding-JDBC等。分散式資料訪問層無需硬體投入,技術能力較強的大公司通常會選擇自研或參照開源框架進行二次開發和定製。對應用程式的侵入性一般較大,會增加技術成本和複雜度。通常僅支援特定程式語言平臺(Java平臺的居多),或者僅支援特定的資料庫和特定資料訪問框架技術(一般支援MySQL資料庫,JDBC、MyBatis、Hibernate等框架技術)。 

    資料庫中介軟體,比較典型的像mycat(在阿里開源的cobar基礎上做了很多優化和改進,屬於後起之秀,也支援很多新特性),基於Go語言實現kingSharding,比較老牌的Atlas(由360開源)等。這些中介軟體在網際網路企業中大量被使用。另外,MySQL 5.x企業版中官方提供的Fabric元件也號稱支援分片技術,不過國內使用的企業較少。 

  2. 中介軟體也可以稱為“透明閘道器”,大名鼎鼎的mysql_proxy大概是該領域的鼻祖(由MySQL官方提供,僅限於實現“讀寫分離”)。中介軟體一般實現了特定資料庫的網路通訊協議,模擬一個真實的資料庫服務,遮蔽了後端真實的Server,應用程式通常直接連線中介軟體即可。而在執行SQL操作時,中介軟體會按照預先定義分片規則,對SQL語句進行解析、路由,並對結果集做二次計算再最終返回。

    引入資料庫中介軟體的技術成本更低,對應用程式來講侵入性幾乎沒有,可以滿足大部分的業務。增加了額外的硬體投入和運維成本,同時,中介軟體自身也存在效能瓶頸和單點故障問題,需要能夠保證中介軟體自身的高可用、可擴充套件。 

總之,不管是使用分散式資料訪問層還是資料庫中介軟體,都會帶來一定的成本和複雜度,也會有一定的效能影響。所以,還需讀者根據實際情況和業務發展需要慎重考慮和選擇。

相關推薦

分庫常見形式以及可能遇到的難題

在談論資料庫架構和資料庫優化的時候,我們經常會聽到“分庫分表”、“分片”、“Sharding”…這樣的關鍵詞。讓人感到高興的是,這些朋友所服務的公司業務量正在(或者即將面臨)高速增長,技術方面也面臨著一些挑戰。讓人感到擔憂的是,他們系統真的就需要“分庫分表”了嗎?“分庫分表”有那麼容易實踐嗎?為此,筆者整

分庫常見形式

垂直分表:垂直分表在日常開發和設計中比較常見,通俗的說法叫做“大表拆小表”,拆分是基於關係型資料庫中的“列”(欄位)進行的。通常情況,某個表中的欄位比較多,可以新建立一張“擴充套件表”,將不經常使用或者長度較大的欄位拆分出去放到“擴充套件表”中。 ps:在欄位很多的情況下,

JS進階-閉包的常見形式

++ 常見 spa chain () clas js進階 undefined alert 作用域鏈: //作用域鏈 var a = 1; function test() { var b =2; return a; }

分庫常見玩法及如何解決跨庫查詢等問題

時間 擔憂 idt web 分布 rpc sharding har 安全性 在談論數據庫架構和數據庫優化的時候,我們經常會聽到“分庫分表”、“分片”、“Sharding”…這樣的關鍵詞。讓人感到高興的是,這些朋友所服務的公司業務量正在(或者即將面臨)高速增長,技術方面也面臨

【資料庫】分庫方式及總結

分庫分表的幾種常見形式公司業務的發展過程中,提高系統的處理承載能力,在資料庫端通常都會選擇分庫分表。今天對資料庫的分庫分表進行了一次學習與總結。1、垂直分表垂直分表在日常開發和設計中比較常見,通俗的說法叫做“大表拆小表”,拆分是基於關係型資料庫中的“列”(欄位)進行的。通常情

常見SQL頁方式效率比較

har n) over mage 適用於 not blog toolbar 大數 1.創建測試環境,(插入100萬條數據大概耗時5分鐘)。 create database DBTestuse DBTest--創建測試表create table pagetest(id

資料庫分庫(sharding)系列(五) 一支援自由規劃無須資料遷移和修改路由程式碼的Sharding擴容方案(轉)...

作為一種資料儲存層面上的水平伸縮解決方案,資料庫Sharding技術由來已久,很多海量資料系統在其發展演進的歷程中都曾經歷過分庫分表的Sharding改造階段。簡單地說,Sharding就是將原來單一資料庫按照一定的規則進行切分,把資料分散到多臺物理機(我們稱之為Shard)上儲存,從

資料庫分庫 sharding 系列 五 一支援自由規劃無須資料遷移和修改路由程式碼的Sharding擴容方案

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

常見SQL頁方式

第一種方法:效率最高 [sql]  view plain  copy SELECT TOP 頁大小 *   

常見的HTML割線

   一、基礎程式碼:1、<HR>2、<HR align=center width=300color=#987cb9 SIZE=1>align 線條位置(可選left、right、center);width 線條長度;color 顏色;size 厚度二、特效(效果並不是孤立的,可相互組

Android開發——聯絡人中常見的mimetype、常見的Uri

2個常見的Uri "content://com.android.contacts/raw_contacts" "content://com.android.contacts/data" 3中常見的mimetype "vnd.android.cursor.item/nam

常見的中文詞包的分析與比較

1:中文分詞簡介 2:Lucence的中文分詞 3:庖丁分詞簡介 4:IK中文分詞簡介 一:中文分詞簡介     1:分詞演算法分類         -----基於字串匹配的中文分詞方法                eg:句子:我來自瀋陽航空航天大學          

常見的網頁佈局形式

關鍵字: “國”、“匡”、“三”、“川”、封面型佈局、Flash佈局、標題文字型佈局、框架型佈局和變化型佈局等 國字佈局 也可以稱為“同”字型,是一些大型網站所喜歡的型別,即最上面是網站的標題以及橫幅廣告條,接下來就是網站的主要內容,左右分列兩小

WAV格式常見壓縮形式(compression code)

WAV為微軟公司(Microsoft)開發的一種聲音檔案格式,它符合RIFF(Resource Interchange File Format)檔案規範,用於儲存Windows平臺的音訊資訊資源,被Windows平臺及其應用程式所廣泛支援,該格式也支援MSADPCM,CC

[置頂] 資料庫分庫(sharding)系列(五) 一支援自由規劃無須資料遷移和修改路由程式碼的Sharding擴容方案

作為一種資料儲存層面上的水平伸縮解決方案,資料庫Sharding技術由來已久,很多海量資料系統在其發展演進的歷程中都曾經歷過分庫分表的Sharding改造階段。簡單地說,Sharding就是將原來單一資料庫按照一定的規則進行切分,把資料分散到多臺物理機(我們稱之為Sh

sharding-jdbc 分庫的 4分片策略,還蠻簡單的

上文[《快速入門分庫分表中介軟體 Sharding-JDBC (必修課)》](https://mp.weixin.qq.com/s?__biz=MzAxNTM4NzAyNg==&mid=2247488500&idx=1&sn=108bf704a54b0a9638e84698deb3ce4c&chksm=9b8

分庫神器 Sharding-JDBC,千萬的資料你不搞一下?

今天我們介紹一下 `Sharding-JDBC`框架和快速的搭建一個分庫分表案例,為講解後續功能點準備好環境。 ### **一、Sharding-JDBC 簡介** `Sharding-JDBC` 最早是噹噹網內部使用的一款分庫分表框架,到2017年的時候才開始對外開源,這幾年在大量社

MySQL分庫備份腳本

數據庫備份數據庫腳本[[email protected]/* */ script]# cat store_backup.sh #!/bin/shMYUSER=rootMYPASS=qwe123SOCKET=/data/3306/mysql.sockMYLOGIN="mysql -u$MYUSER

html中設置錨點定位的常見方法

element 針對 htm com script int nbsp onclick .get 1,使用id定位: <a href="#1F" name="1F">錨點1</a> <div name="1F"> <p>

數據庫(分庫)中間件對比

系統瓶頸 地址 ring 缺點 無需 網絡io 數據遷移 用戶 osql 轉自:http://www.cnblogs.com/cangqiongbingchen/p/7094822.html 分區:對業務透明,分區只不過把存放數據的文件分成了許多小塊,例如mysql中的一張