前言
MySql基礎:https://blog.csdn.net/yhl_jxy/category_5622941.html
MySql進階:https://blog.csdn.net/yhl_jxy/category_6390753.html
一 爲什麼要對數據庫進行優化?
1、超大容量問題
1)海量數據單表,數據庫處理能力將達到上限;
2)硬盤空間達到極限,將無空間可用;
2、性能問題
服務器處理能力有限,單庫單表TPS有上限,無論怎麼優化,隨着數據量的增長最後都會面臨無法增長的局面,
影響業務處理能力和用戶體驗。
3、升級擴展問題
單一主庫無法靈活的進行升級和擴展,無法滿足公司快速發展要求,所有的數據都放在同一庫裏面,存在單點故障的風險;
二 數據庫有哪些常用的優化手段?
1、優化字段,索引,Sql,數據歸檔
2、加緩存(MongoDB,Redis,Memcached,本地緩存等等)
3、讀寫分離(屬於業務相關優化)
4、分庫分表(基於業務分庫分表)
5、分區(純物理級別處理)
三 分庫分表拆分方式?
分庫分表的基本思想就是把一個數據庫拆分成多個部分放到不同的數據庫(Server)上,從而緩解單一數據庫的性能。
主要是圍繞垂直拆分和水平拆分展開。
1、垂直拆分
從數據庫表的數量層面分庫:
對於海量數據的數據庫,如果是因爲表太多,我們可以按模塊,把關係緊密的拆分出來,單獨運行Server。
如果一個數據庫表太多,所有應用都請求都打到一臺實例上,數據庫壓力很大,會成爲性能的瓶頸。
從數據庫表的字段數量層面分庫:
如果一個表字段特別多,意爲着一般索引也會增多,索引文件會增大,查找時從磁盤讀取索引文件速度
會降低,同時根據索引去讀取數據時,單條數據的值比較大,從磁盤讀到內存的速度也會降低。
所以,一個表字段特別多的時候,就要考慮按業務拆分成多個表,然後再按業務拆分到多個數據庫Server。
2、水平拆分
對於表不多,但是表的數據都是海量數據,這種情況比較適合做水平拆分,按照表數據的規則(比如按ID散列,用戶ID等)
拆分到多個Server。
需要注意:分庫分表不是一個事情,是兩個維度的概念,你可以只分庫,不分表,或者只分表,不分庫,
或者分庫分表同時做都可以。
四 分庫分表會帶來哪些問題?
1)Id主鍵
一旦數據庫被拆分到多個物理結點上,我們將不能再依賴數據庫自身的主鍵生成機制。
一方面,某個分區數據庫自生成的ID無法保證在全局上是唯一的;
另一方面,應用程序在插入數據之前需要先獲得ID,以便進行SQL路由;
UUID:
使用UUID作主鍵是最簡單的方案,但是缺點也是非常明顯的。由於UUID非常的長,除佔用大量存儲空間外,
最主要的問題是在索引上,在建立索引和基於索引進行查詢時都存在性能問題。
結合數據庫維護一個Sequence表:
在數據庫中建立一個Sequence表,表的結構類似於:
CREATE TABLE `SEQUENCE` (
`table_name` varchar(18) NOT NULL,
`nextid` bigint(20) NOT NULL,
PRIMARY KEY (`table_name`)
) ENGINE=InnoDB;
每當需要爲某個表的新紀錄生成ID時就從Sequence表中取出對應表的nextid,並將nextid的值加1後更新到數據庫中
以備下次使用。此方案也較簡單,但缺點同樣明顯:
由於所有插入任何都需要訪問該表,該表很容易成爲系統性能瓶頸,同時它也存在單點問題,一旦該表數據庫失效,
整個應用程序將無法工作。有人提出使用Master-Slave進行主從同步,但這也只能解決單點問題,並不能解決讀寫比
爲1:1的訪問壓力問題。
Twitter的分佈式自增ID算法Snowflake:
在分佈式系統中,需要生成全局UID的場合還是比較多的,twitter的snowflake解決了這種需求,實現也還是很
簡單的,除去配置信息,核心代碼就是毫秒級時間41位 機器ID 10位 毫秒內序列12位。
* 10---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
在上面的字符串中,第一位爲未使用(實際上也可作爲long的符號位),接下來的41位爲毫秒級時間,
然後5位datacenter標識位,5位機器ID(並不算標識符,實際是爲線程標識),然後12位該毫秒內的當前
毫秒內的計數,加起來剛好64位,爲一個Long型。
這樣的好處是,整體上按照時間自增排序,並且整個分佈式系統內不會產生ID碰撞(由datacenter和機器ID作區分),
並且效率較高,經測試,snowflake每秒能夠產生26萬ID左右,完全滿足需要。
2)join
只要是進行拆分,跨節點Join的問題是不可避免的。但是良好的設計和拆分卻可以減少此類情況的發生。
解決這一問題的普遍做法是分兩次查詢實現。在第一次查詢的結果集中找出關聯數據的id,根據這些id發起
第二次請求得到關聯數據。
3)count,max等聚合函數,以及order by,group by等
這些是一類問題,因爲它們都需要基於全部數據集合進行計算。多數的代理都不會自動處理合並工作。
解決方案:
與解決跨節點join問題的類似,分別在各個節點上得到結果後在應用程序端進行合併。
和join不同的是每個結點的查詢可以並行執行,因此很多時候它的速度要比單一大表快很多。
但如果結果集很大,對應用程序內存的消耗是一個問題。
4)排序分頁
一般來講,分頁時需要按照指定字段進行排序。當排序字段就是分片字段的時候,我們通過分片規則可以比較容
易定位到指定的分片,而當排序字段非分片字段的時候,情況就會變得比較複雜了。爲了最終結果的準確性,
我們需要在不同的分片節點中將數據進行排序並返回,並將不同分片返回的結果集進行彙總和再次排序,
最後再返回給用戶。
5)數據遷移,容量規劃,擴容等
通常利用對2的倍數取餘具有向前兼容的特性(如對4取餘得1的數對2取餘也是1)
來分配數據,避免了行級別的數據遷移,但是依然需要進行表級別的遷移,同時對擴容規模和分表數量都有限制。
總得來說,這些方案都不是十分的理想,多多少少都存在一些缺點,這也從一個側面反映出了Sharding擴容的難度。
6)分庫數量
分庫數量首先和單庫能處理的記錄數有關,一般來說,Mysql 單庫超過5000萬條記錄,Oracle單庫超過1億
條記錄,DB壓力就很大(當然處理能力和字段數量/訪問模式/記錄長度有進一步關係)。
在滿足上述前提下,如果分庫數量少,達不到分散存儲和減輕DB性能壓力的目的;如果分庫的數量多,
好處是每個庫記錄少,單庫訪問性能好,但對於跨多個庫的訪問,應用程序需要訪問多個庫,如果是併發模式,
要消耗寶貴的線程資源;如果是串行模式,執行時間會急劇增加。
最後分庫數量還直接影響硬件的投入,一般每個分庫跑在單獨物理機上,多一個庫意味多一臺設備。
所以具體分多少個庫,要綜合評估,一般初次分庫建議分4-8個庫,但是一般都是2的冪次方,對數據庫擴展有好處。
7)分庫策略
分庫維度確定後,如何把記錄分到各個庫裏呢?
一般有兩種方式
根據數值範圍,比如用戶Id爲1-9999的記錄分到第一個庫,10000-20000的分到第二個庫,以此類推。
根據數值取模,比如用戶Id mod n,餘數爲0的記錄放到第一個庫,餘數爲1的放到第二個庫,以此類推。
我們做過訂單表分庫分表,按照數據用戶id取模分庫,但是不是簡簡單單的取模,需要考慮分庫以及分表情況。
8)路由透明
分庫從某種意義上來說,意味着DB schema改變了,必然影響應用,但這種改變和業務無關,所以要儘量保證分庫
對應用代碼透明,分庫邏輯儘量在數據訪問層處理。當然完全做到這一點很困難,具體哪些應該由DAL負責,
哪些由應用負責,這裏有一些建議:
對於單庫訪問,比如查詢條件指定用戶Id,則該SQL只需訪問特定庫。此時應該由DAL層自動路由到特定庫,
當庫二次分裂時,也只要修改mod 因子,應用代碼不受影響。
對於簡單的多庫查詢,DAL負責彙總各個數據庫返回的記錄,此時仍對上層應用透明。
9)分庫分表中間件
從網上找了些組件:
輕量級
噹噹sharding-jdbc:https://github.com/dangdangdotcom/sharding-jdbc(現在改名叫sharding-sphere)
蘑菇街TSharding:https://github.com/baihui212/tsharding
重量級
sharding:https://github.com/go-pg/sharding
TDDL Smart Client的方式(淘寶):https://github.com/alibaba/tb_tddl
Atlas(Qihoo 360):https://github.com/Qihoo360/Atlas
alibaba.cobar((是阿里巴巴(B2B)部門開發):https://github.com/alibaba/cobar
MyCAT(基於阿里開源的Cobar產品而研發):http://www.mycat.org.cn/
Oceanus(58同城數據庫中間件):https://github.com/58code/Oceanus
OneProxy(支付寶首席架構師樓方鑫開發):https://www.cnblogs.com/youge-OneSQL/articles/4208583.html
vitess(谷歌開發的數據庫中間件):https://github.com/youtube/vitess
用哪個好?
網上有很多比較,用sharding-sphere或mycat的比較多,sharding-jdbc作爲一個組件集成在應用內,
而mycat則作爲一個獨立的應用需要單獨部署;
分庫分表中間件的一些比較:https://www.cnblogs.com/iceggboom/p/10134853.html
持續更新完善中......