Mysql分庫分表方案

weixin_33858249發表於2017-11-07

Mysql分庫分表方案

1.為什麼要分表:

當一張表的資料達到幾千萬時,你查詢一次所花的時間會變多,如果有聯合查詢的話,我想有可能會死在那兒了。分表的目的就在於此,減小資料庫的負擔,縮短查詢時間。

mysql中有一種機制是表鎖定和行鎖定,是為了保證資料的完整性


表鎖定表示你們都不能對這張表進行操作,必須等我對錶操作完才行。


行鎖定也一樣,別的sql必須等我對這條資料操作完了,才能對這條資料進行操作。


  1. mysql proxy:amoeba

做mysql叢集,利用amoeba。

從上層的java程式來講,不需要知道主伺服器和從伺服器的來源,即主從資料庫伺服器對於上層來講是透明的。可以通過amoeba來配置。

3.大資料量並且訪問頻繁的表,將其分為若干個表

比如對於某網站平臺的資料庫表-公司表,資料量很大,這種能預估出來的大資料量表,我們就事先分出個N個表,這個N是多少,根據實際情況而定。

某網站現在的資料量至多是5000萬條,可以設計每張表容納的資料量是500萬條,也就是拆分成10張表,那麼如何判斷某張表的資料是否容量已滿呢?可以在程式段對於要新增資料的表,在插入前先做統計表記錄數量的操作,當<500萬條資料,就直接插入,當已經到達閥值,可以在程式段新建立資料庫表(或者已經事先建立好),再執行插入操作。

  1. 利用merge儲存引擎來實現分表

如果要把已有的大資料量表分開比較痛苦,最痛苦的事就是改程式碼,因為程式裡面的sql語句已經寫好了。用merge儲存引擎來實現分表, 這種方法比較適合.

舉例子:

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy

資料庫架構

1、簡單的MySQL主從複製:

MySQL的主從複製解決了資料庫的讀寫分離,並很好的提升了讀的效能,其圖如下:

其主從複製的過程如下圖所示:
640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy

但是,主從複製也帶來其他一系列效能瓶頸問題:

  1. 寫入無法擴充套件

  2. 寫入無法快取

  3. 複製延時

  4. 鎖表率上升

  5. 表變大,快取率下降

那問題產生總得解決的,這就產生下面的優化方案,一起來看看。

2、MySQL垂直分割槽

如果把業務切割得足夠獨立,那把不同業務的資料放到不同的資料庫伺服器將是一個不錯的方案,而且萬一其中一個業務崩潰了也不會影響其他業務的正常進行,並且也起到了負載分流的作用,大大提升了資料庫的吞吐能力。經過垂直分割槽後的資料庫架構圖如下:
640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy

然而,儘管業務之間已經足夠獨立了,但是有些業務之間或多或少總會有點聯絡,如使用者,基本上都會和每個業務相關聯,況且這種分割槽方式,也不能解決單張表資料量暴漲的問題,因此為何不試試水平分割呢?

3、MySQL水平分片(Sharding)

這是一個非常好的思路,將使用者按一定規則(按id雜湊)分組,並把該組使用者的資料儲存到一個資料庫分片中,即一個sharding,這樣隨著使用者數量的增加,只要簡單地配置一臺伺服器即可,原理圖如下:
640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy

如何來確定某個使用者所在的shard呢,可以建一張使用者和shard對應的資料表,每次請求先從這張表找使用者的shard id,再從對應shard中查詢相關資料,如下圖所示:
640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy





拆分策略選擇


其實拆分很靈活,有的是

垂直切分,將一個庫拆成兩個或多個,將有相關聯的表放在一個庫裡。有的是


水平切分將資料量大的表按照一定邏輯進行拆分。


個人感覺垂直切分的相對來說緩解了IO的瓶頸,而水平切分,目的是減輕了單個表或某些表讀寫的壓力。

我們專案根據個人需求,採用的水平切分,沒有去分庫。之後要看看需要採用何種的切分了。

瞭解到的有: 分表、分割槽、MERGE引擎分表。


MERGE引擎分表


簡介


先介紹merge表,此方法只適用於MyISAM。我資料庫的表都是採用InnoDB引擎的,所以首先就被pass了,但是還是在這裡簡單介紹下吧。

mysql 5.1 手冊裡的說的

640?tp=webp&wxfrom=5&wx_lazy=1

改變到MERGE引擎表,意味著成為一個被分割槽的表,這樣將單一的表各分割槽儲存在分離的檔案中。分割槽可以使一些操作效率更顯著,並且不受MyISAM儲存引擎的限制。(蹩腳的英語,各位看官多擔待吧。)


以上應該是使用merge表的主要原因吧。


建立使用


能夠建立MERGE表的要求,首先是一組資料結構完全相同的表,並且儲存引擎為MyISAM。


讓我們先建立一個

640?tp=webp&wxfrom=5&wx_lazy=1

之後查詢

640?tp=webp&wxfrom=5&wx_lazy=1

你建立了total表,只是相當於在t1,t2的表的基礎上建立的,需要注意的是在單個表中的主鍵或唯一索引,放在MERGE後的total表中就不能再當唯一索引用了,這點應該比較好理解但還是要說一下的。


同時你可以drop或者ALTER TABLE tbl_name UNION=(...)改變表的資料集,這樣可以讓其動態變化,剔除不需要的。


使用場景


如果你的資料記錄呈現一定時間規律,比如每天產生的一些需要記錄的日誌,可能你只需要最近一個月的或者最近幾個月的,這樣你可以每天或者一定時間建立一個資料表,當需要查詢一段時間的資料,你只要將這段時間的資料表建立一張總計的MERGE表。這樣資料集可以控制在可控的範圍呢,不錯吧。so easy。


分表


分表其實想法上很簡單,顧名思義就是將現有的一張資料量大的表去拆分。如果資料庫的效能瓶頸在幾個關鍵表上,這時你可以將分表列入你考慮的範圍。


遇到的問題


我說說我在實驗分表時遇到的問題和相關解決方式


1.如何去分表


根據什麼策略把現有表中的資料分到多個表中,並且還有考慮到以後的擴充套件性上。



是建立一張索引表,使用者id與資料庫id對應,(這裡他將相同結構的表分在了不同的資料庫中進一步減少壓力,但同時對於資料的同步也需要通過其他手段來解決),其本質也是分表了同時分庫了。這麼做的好處是便於以後的擴充套件,但損耗一點效能,因為會多一次查詢嘛。


個人想法,這樣索引表可能會成為新的瓶頸,除非使用者不會一直增長哈。


我的做法屬於另一種,寫了個演算法通過計算某列值,按照一定規律將資料大致均分在每個分表中。至於擴充套件性,寫演算法時候考慮進去了以後增加分表數的問題了。


選擇哪種策略,是要看自己的表的業務特點了,方法沒有絕對的優缺,還是要根據自己的需求選取。


2.分表之後主鍵的維護


分表之前,主鍵就是自動遞增的bigint型。所以主鍵的格式已經提早被確定了,像什麼uuid之類的就被直接pass掉了。


還有想過自己寫一個主鍵生成程式,利用Java 的Atomic原子量特性,但是考慮還需要增加工作量並且高併發下,這裡很可能是個隱患。


還有就是通過應用層上管理主鍵,如redis中有原子性的遞增。


網上較有名的策略是《Ticket Servers: Distributed Unique Primary Keys on the Cheap》, 大致意思是使用一張名Tickets64的MyISAM儲存引擎表,專門用來儲存主鍵,資料只有一行,用的話通過

640?tp=webp&wxfrom=5&wx_lazy=1

來取。並且設定了兩個庫,相同的方法,只是每次增長的步長不同,防止一個宕掉,還可以穩定執行。


2.動態選擇表名


表分好之後,問題又來了,資料庫層我們的專案使用的是Mybatis框架。SQL語句都寫在了xml檔案中,現在我需要動態的設定表名。


其實設定mybatis本身,就可以解決這個問題

640?tp=webp&wxfrom=5&wx_lazy=1

只要把屬性statementType設定為STATEMENT,表名就可以以引數形式傳入。傳入引數時要以美元符${columnName}這樣傳入引數,至於Statement,PreparedStatement 的區別我想大家應該都能知道的。


另一種解決方式,是使用《shardbatis外掛》,它是開源的,可以實現資料水平切分功能,有興趣的朋友可以瞭解下。


分割槽表


從mysql5.1之後,提供了一種partition引擎的表,看這句

640?tp=webp&wxfrom=5&wx_lazy=1

在我的理解,如果把一張表分割槽之後,不同分割槽放在不同磁碟位置上,對整體的讀取是否更有益?


分割槽表優缺點


這裡主要是看的mysql手冊,我也就起到了個翻譯的作用。

640?tp=webp&wxfrom=5&wx_lazy=1

在選擇mysql 分割槽方案時,還有一個需要考慮的,在mysql的bug中有一個關於mysql分割槽表查詢快取的bug: 《Partitioning + Query Cache》,因為這個問題,mysql已經將分割槽表的查詢快取disable了,無論你是否開啟查詢快取,都不會啟用查詢快取。如果你在意這點,請慎重選擇方案。


以上是關於,mysql三個拆分方案的總結,資料方面都是自己查詢的所以不免有些會不準確,如有發現請務必告知,希望與各位共成長~~~。











本文轉自 chengxuyonghu 51CTO部落格,原文連結:http://blog.51cto.com/6226001001/1726092,如需轉載請自行聯絡原作者

相關文章