1. 程式人生 > >MySql分庫分表與分割槽的區別和思考

MySql分庫分表與分割槽的區別和思考

一.分分合合

  說過很多次,不要拘泥於某一個技術的一點,技術是相通的。重要的是程式設計思想,思想是最重要的。當資料量大的時候,需要具有分的思想去細化粒度。當資料量太碎片的時候,需要具有合的思想來粗化粒度。

1.1 分

  很多技術都運用了分的程式設計思想,這裡來舉幾個例子,這些都是分的思想

  • 集中式服務發展到分散式服務
  • 從Collections.synchronizedMap(x)到1.7ConcurrentHashMap再到1.8ConcurrentHashMap,細化鎖的粒度的同時依舊保證執行緒安全
  • 從AtomicInteger到LongAdder,ConcurrentHashMap的size()方法。用分散思想,減少cas次數,增強多執行緒對一個數的累加
  • JVM的G1 GC演算法,將堆分成很多Region來進行記憶體管理
  • Hbase的RegionServer中,將資料分成多個Region進行管理
  • 平時開發是不是執行緒池都資源隔離

2.2 合

  很多技術也運用到了合的程式設計思想,這裡舉幾個例子,這些都是合的思想

  • TLAB(Thread Local Allocation Buffers),執行緒本地分配快取。避免多執行緒衝突,提高物件分配效率
  • 逃逸分析,將變數的例項化記憶體直接在棧裡分配,無需進入堆,執行緒結束棧空間被回收。減少臨時物件在堆內分配數量
  • CMS GC演算法下,雖然使用標記清除,但是也有配置支援整理記憶體碎片。如:-XX:UseCMS-CompactAtFullCollection(FullGC後是否整理,Stop The World會變長)和-XX:CMSFullGCs-BeforeCompaction(幾次FullGC之後進行壓縮整理)
  • 鎖粗化,當JIT發現一系列連續的操作都是對同一物件反覆加鎖和釋放鎖,會加大鎖同步的範圍
  • kafka的網路資料傳輸有一些資料配置,減少網路開銷。如:batch.size和linger.ms等等
  • 平時開發是不是都個叫批量獲取介面

二.分割槽

  本文一切基於MySql InnoDB

  說了這麼多,接下來說主體,先說分割槽,因為之前博主寫過一篇MySql分割槽的部落格所以這裡不會多費筆墨來寫,具體見:https://www.cnblogs.com/GrimMjx/p/10526821.html

2.1 實現方式

  具體如何實現上面連結裡有寫,這裡只需記住如果表中存在主鍵或唯一索引時,分割槽列必須是唯一索引的一個組成部分。

  這個是資料庫分的,應用透明,程式碼無需修改任何東西。

2.2 內部檔案

  先去data目錄,如果不知道目錄位置的可以執行:

   接下來看下內部檔案:

 

  從上圖我們可以看出,有2中型別的檔案,.frm檔案和.ibd檔案

  • .frm檔案:表結構檔案
  • .ibd檔案:InnoDB中,索引和資料都在同個檔案.ibdata(你的執行結果可能是.MYD索引檔案和.MYI資料檔案,沒關係,這是MyIsAm儲存引擎,對應著InnoDB的.ibd檔案)。因為Order這張表分為5個區,所以有5個這樣的檔案
  • .par檔案:你執行的結果可能有.par檔案也可能沒有。注意:從MySql 5.7.6開始,不再建立.par分割槽定義檔案。分割槽定義儲存在內部資料字典中。

2.3 資料處理

  分割槽表後,提高了MySql效能。如果一張表的話,那就只有一個.ibd檔案,一顆大的B+樹。如果分表後,將按分割槽規則,分成不同的區,也就是一個大的B+樹,分成多個小的樹。

  (PS:如果想研究一顆聚集索引B+樹可以放多少行資料,請看:https://www.cnblogs.com/GrimMjx/p/10540263.html)

  讀的效率肯定提升了,如果走分割槽鍵索引的話,先走對應分割槽的輔助索引B+樹,再走對應分割槽的聚集索引B+樹。

  如果沒有走分割槽鍵,將會在所有分割槽都會執行一次。會造成多次邏輯IO!平時開發如果想檢視sql語句的分割槽查詢可以使用explain partitons select xxxxx語句。可以看到一句select語句走了幾個分割槽。 

mysql> explain partitions select * from TxnList where startTime>'2016-08-25 00:00:00' and startTime<'2016-08-25 23:59:00';  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
| id | select_type | table             | partitions | type | possible_keys | key  | key_len | ref  | rows  | Extra       |  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
|  1 | SIMPLE      | ClientActionTrack | p20160825  | ALL  | NULL          | NULL | NULL    | NULL | 33868 | Using where |  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
row in set (0.00 sec)

三.分庫分表

  當一張表隨著時間和業務的發展,庫裡表的資料量會越來越大。資料操作也隨之會越來越大。一臺物理機的資源有限,最終能承載的資料量、資料的處理能力都會受到限制。這時候就會使用分庫分表來承接超大規模的表,單機放不下的那種。

  區別於分割槽的是,分割槽一般都是放在單機裡的,用的比較多的是時間範圍分割槽,方便歸檔。只不過分庫分表需要程式碼實現,分割槽則是mysql內部實現。分庫分表和分割槽並不衝突,可以結合使用。

3.1 實現

3.1.1 分庫分表標準

  • 儲存佔用100G+
  • 資料增量每天200w+
  • 單表條數1億條+

3.1.2 分庫分表字段

  分庫分表字段取值非常重要

  1. 在大多數場景該欄位是查詢欄位
  2. 數值型

  一般使用userId,可以滿足上述條件

3.2 分散式資料庫中介軟體

  分散式資料庫中介軟體分為兩種,proxy和客戶端式架構。proxy模式有MyCat、DBProxy等,客戶端式架構有TDDL、Sharding-JDBC等。那麼proxy和客戶端式架構有何區別呢?各自有什麼優缺點呢?其實看一張圖便可知曉。

  proxy模式的話我們的select和update語句都是傳送給代理,由這個代理來操作具體的底層資料庫。所以必須要求代理本身需要保證高可用,否則資料庫沒有宕機,proxy掛了,那就走遠了。

  客戶端模式通常在連線池上做了一層封裝,內部與不同的庫連線,sql交給smart-client進行處理。通常僅支援一種語言,如果其他語言要使用,需要開發多語言客戶端。

  

  各自的優缺點如下: 

3.3 內部檔案

  找了一個分庫分表+分割槽的例子,基本上和分割槽表的差不多,只是多了多了很多表的.ibd檔案,上面有檔案的解釋:

[miaojiaxing@Grim testmydata]# ls | grep 'base_info'
base_info_00.frm
base_info_00#P#p_2018.ibd
base_info_00#P#p_2019.ibd
base_info_00#P#p_2020.ibd
base_info_00#P#p_2021.ibd
base_info_00#P#p_init.ibd
base_info_00#P#p_max.ibd
base_info_01.frm
base_info_01#P#p_2018.ibd
base_info_01#P#p_2019.ibd
base_info_01#P#p_2020.ibd
base_info_01#P#p_2021.ibd
base_info_01#P#p_init.ibd
base_info_01#P#p_max.ibd
base_info.frm
base_info.ibd

3.4 問題

3.4.1 事務問題

  既然分庫分表了,那麼肯定涉及到分散式事務,如何保證插入到不同庫的多條記錄能夠要麼同時成功,要麼同時失敗。有些同學可能想到XA,XA效能差而且不需要使用mysql5.7。柔性事務是目前主流的方案,TCC模式就屬於柔性事務。

  對於分散式事務問題每家公司有自己的實現,華為用saga,阿里用TXC,螞蟻用DTX,支援FMT模式和TCC模式。

3.4.2 join問題

  tddl、MyCAT等都支援跨分片join。但是盡力避免跨庫join,比如通過欄位冗餘的方式等。

  如果出現了這種情況且中介軟體支援分片join,那麼可以這樣使用。如果不支援可以手工查詢。

四.總結

  分表和在用途上不一樣,分表是為了承接超大規模的表,單機放不下那種。分割槽的話則一般都是放在單機裡的,用的比較多的是時間範圍分割槽,方便歸檔。效能穩定上的話都是一個個子表,差不多,區別應該是分割槽表是mysql內部實現的,會比分表方案少一點資料交