你們好,我是小富~算法
以前有很多剛入坑 Java
的粉絲留言,想系統的學習一下分庫分表相關技術,可我一直沒下定決心搞,眼下遇上公司項目在使用 sharding-jdbc
對現有 MySQL
架構作分庫分表的改造,因此藉此機會出一系分庫分表落地實踐的文章,也算是本身對架構學習的一個總結。數據庫
我在網上陸陸續續的也看了一些有關於分庫分表的文章,可發現網上同質化的資料有點多,並且知識點又都比較零碎,尚未詳細的實戰案例。爲了更深刻的學習下,我在某些平臺買了點付費課程,看了幾節課發現有點經驗的人看還能夠,但對於新手入門來講,其實學習難度仍是蠻大的。服務器
爲了讓新手也能看得懂,有些知識點我可能會用更多的篇幅加以描述,但願你們不要嫌我囉嗦,等這分庫分表系列文章完結後,我會把它作成 PDF
文檔開源出去,能幫一個算一個吧!若是發現文中有哪些錯誤或不嚴謹之處,歡迎你們交流指正。網絡
具體實踐分庫分表以前在囉嗦幾句,回頭複習下分庫分表的基礎概念。架構
什麼是分庫分表
其實 分庫
和 分表
是兩個概念,只不過一般分庫與分表的操做會同時進行,以致於咱們習慣性的將它們合在一塊兒叫作分庫分表。併發
分庫分表是爲了解決因爲庫、表數據量過大,而致使數據庫性能持續降低的問題。按照必定的規則,將本來數據量大的數據庫拆分紅多個單獨的數據庫,將本來數據量大的表拆分紅若干個數據表,使得單一的庫、表性能達到最優的效果(響應速度快),以此提高總體數據庫性能。框架
如何分庫分表
分庫分表的核心理念就是對數據進行切分(Sharding
),以及切分後如何對數據的快速定位與查詢結果整合。而分庫與分表均可以從:垂直
(縱向)和 水平
(橫向)兩種緯度進行切分。運維
下邊咱們就以訂單相關的業務舉例,看看如何作庫、表的 垂直
和 水平
切分。分佈式
垂直切分
垂直切分有 垂直
分庫 和 垂直
分表。微服務
一、垂直分庫
垂直分庫相對來講是比較好理解的,核心理念就四個字:專庫專用
。
按業務類型對錶進行分類,像訂單、支付、優惠券、積分等相應的表放在對應的數據庫中。開發者不能夠跨庫直連別的業務數據庫,想要其餘業務數據,對應業務方能夠提供 API
接口,這就是微服務的初始形態。
垂直分庫很大程度上取決於業務的劃分,但有時候業務間的劃分並非那麼清晰,好比:訂單數據的拆分要考慮到與其餘業務間的關聯關係,並非說直接把訂單相關的表放在一個庫裏這麼簡單。
在必定程度上,垂直分庫彷佛提高了一些數據庫性能,可實際上並無解決因爲單表數據量過大致使的性能問題,因此就須要配合水平切分方式來解決。
二、垂直分表
垂直分表
是基於數據表的列(字段)爲依據切分的,是一種大表拆小表的模式。
例如:一張 order
訂單表,將訂單金額、訂單編號等訪問頻繁的字段,單獨拆成一張表,把 blob
類型這樣的大字段或訪問不頻繁的字段,拆分出來建立一個單獨的擴展表 work_extend
,這樣每張表只存儲原表的一部分字段,再將拆分出來的表分散到不一樣的庫中。
咱們知道數據庫是以行爲單位將數據加載到內存中,這樣拆分之後核心表大可能是訪問頻率較高的字段,並且字段長度也都較短,於是能夠加載更多數據到內存中,來增長查詢的命中率,減小磁盤IO,以此來提高數據庫性能。
垂直切分的優勢:
-
業務間數據解耦,不一樣業務的數據進行獨立的維護、監控、擴展。
-
在高併發場景下,必定程度上緩解了數據庫的壓力。
垂直切分的缺點:
-
提高了開發的複雜度,因爲業務的隔離性,不少表沒法直接訪問,必須經過接口方式聚合數據。
-
分佈式事務管理難度增長。
-
數據庫仍是存在單表數據量過大的問題,並未根本上解決,須要配合水平切分。
水平切分
前邊說了垂直切分仍是會存在單庫、表數據量過大的問題,當咱們的應用已經沒法在細粒度的垂直切分時, 依舊存在單庫讀寫、存儲性能瓶頸,這時就要配合水平切分一塊兒了,水平切分能大幅提高數據庫性能。
一、水平分庫
水平分庫是把同一個表按必定規則拆分到不一樣的數據庫中,每一個庫能夠位於不一樣的服務器上,以此實現水平擴展,是一種常見的提高數據庫性能的方式。
這種方案每每能解決單庫存儲量及性能瓶頸問題,但因爲同一個表被分配在不一樣的數據庫中,數據的訪問須要額外的路由工做,所以系統的複雜度也被提高了。
例以下圖,訂單DB_1
、訂單DB_1
、訂單DB_3
三個數據庫內有徹底相同的表 order
,咱們在訪問某一筆訂單時能夠經過對訂單的訂單編號取模的方式 訂單編號 mod 3 (數據庫實例數)
,指定該訂單應該在哪一個數據庫中操做。
二、水平分表
水平分表是在同一個數據庫內,把一張大數據量的表按必定規則,切分紅多個結構徹底相同表,而每一個表只存原表的一部分數據。
例如:一張 order
訂單表有 900萬數據,通過水平拆分出來三個表,order_1
、order_2
、order_3
,每張表存有數據 300萬,以此類推。
水平分表儘管拆分了表,但子表都仍是在同一個數據庫實例中,只是解決了單一表數據量過大的問題,並無將拆分後的表分散到不一樣的機器上,還在競爭同一個物理機的CPU、內存、網絡IO等。要想進一步提高性能,就須要將拆分後的表分散到不一樣的數據庫中,達到分佈式的效果。
水平切分的優勢:
-
解決高併發時單庫數據量過大的問題,提高系統穩定性和負載能力。
-
業務系統改造的工做量不是很大。
水平切分的缺點:
-
跨分片的事務一致性難以保證。
-
跨庫的join關聯查詢性能較差。
-
擴容的難度和維護量較大,(拆分紅幾千張子表想一想都恐怖)。
必定規則是什麼
咱們上邊提到過不少次 必定規則
,這個規則實際上是一種路由算法,就是決定一條數據具體應該存在哪一個數據庫的哪張表裏。
常見的有 取模算法
和 範圍限定算法
一、取模算法
按字段取模(對hash結果取餘數 (hash() mod N),N爲數據庫實例數或子表數量)是最爲常見的一種切分方式。
還拿 order
訂單表舉例,先對數據庫從 0 到 N-1進行編號,對 order
訂單表中 work_no
訂單編號字段進行取模,獲得餘數 i
,i=0
存第一個庫,i=1
存第二個庫,i=2
存第三個庫....以此類推。
這樣同一筆訂單的數據都會存在同一個庫、表裏,查詢時用相同的規則,用 work_no
訂單編號做爲查詢條件,就能快速的定位到數據。
優勢:
- 數據分片相對比較均勻,不易出現請求都打到一個庫上的狀況。
缺點:
- 這種算法存在一些問題,當某一臺機器宕機,本應該落在該數據庫的請求就沒法獲得正確的處理,這時宕掉的實例會被踢出集羣,此時算法變成hash(userId) mod N-1,用戶信息可能就再也不在同一個庫中了。
二、範圍限定算法
按照 時間區間
或 ID區間
來切分,好比:咱們切分的是用戶表,能夠定義每一個庫的 User
表裏只存10000條數據,第一個庫只存 userId
從1 ~ 9999的數據,第二個庫存 userId
爲10000 ~ 20000,第三個庫存 userId
爲 20001~ 30000......以此類推,按時間範圍也是同理。
優勢:
-
單表數據量是可控的
-
水平擴展簡單隻需增長節點便可,無需對其餘分片的數據進行遷移
-
能快速定位要查詢的數據在哪一個庫
缺點:
- 因爲連續分片可能存在數據熱點,好比按時間字段分片,可能某一段時間內訂單驟增,可能會被頻繁的讀寫,而有些分片存儲的歷史數據,則不多被查詢。
分庫分表的難點
一、分佈式事務
因爲表分佈在不一樣庫中,不可避免會帶來跨庫事務問題。通常可以使用 "三階段提交
"和 "兩階段提交
" 處理,可是這種方式性能較差,代碼開發量也比較大。一般作法是作到最終一致性的方案,若是不苛求系統的實時一致性,只要在容許的時間段內達到最終一致性便可,採用事務補償的方式。
這裏我應用阿里的分佈式事務框架Seata
來作分佈式事務的管理,後邊會結合實際案例。
二、分頁、排序、跨庫聯合查詢
分頁、排序、聯合查詢是開發中使用頻率很是高的功能,但在分庫分表後,這些看似普通的操做倒是讓人很是頭疼的問題。將分散在不一樣庫中表的數據查詢出來,再將全部結果進行彙總整理後提供給用戶。
三、分佈式主鍵
分庫分表後數據庫的自增主鍵意義就不大了,由於咱們不能依靠單個數據庫實例上的自增主鍵來實現不一樣數據庫之間的全局惟一主鍵,此時一個可以生成全局惟一ID的系統是很是必要的,那麼這個全局惟一ID就叫 分佈式ID
。
四、讀寫分離
不難發現大部分主流的關係型數據庫都提供了主從架構的高可用方案,而咱們須要實現 讀寫分離
+ 分庫分表
,讀庫與寫庫都要作分庫分表處理,後邊會有具體實戰案例。
五、數據脫敏
數據脫敏,是指對某些敏感信息經過脫敏規則進行數據轉換,從而實現敏感隱私數據的可靠保護,如身份證號、手機號、卡號、帳號密碼等我的信息,通常這些都須要進行作脫敏處理。
分庫分表工具
我仍是那句話,儘可能不要本身造輪子,由於本身造的輪子可能不那麼圓,業界已經有了不少比較成熟的分庫分表中間件,咱們根據自身的業務需求挑選,將更多的精力放在業務實現上。
sharding-jdbc
(噹噹)TSharding
(蘑菇街)Atlas
(奇虎360)Cobar
(阿里巴巴)MyCAT
(基於Cobar)Oceanus
(58同城)Vitess
(谷歌)
爲何選 sharding-jdbc
sharding-jdbc
是一款輕量級 Java
框架,以 jar
包形式提供服務,是屬於客戶端產品不須要額外部署,它至關因而個加強版的 JDBC
驅動;相比之下像 Mycat
這類須要單獨的部署服務的服務端產品,就稍顯複雜了。何況我想把更多精力放在實現業務,不想作額外的運維工做。
sharding-jdbc
的兼容性也很是強大,適用於任何基於JDBC
的ORM
框架,如:JPA
,Hibernate
,Mybatis
,Spring JDBC Template
或直接使用的JDBC
。- 完美兼容任何第三方的數據庫鏈接池,如:
DBCP
,C3P0
,BoneCP
,Druid
,HikariCP
等,幾乎對全部關係型數據庫都支持。
不難發現確實是比較強大的一款工具,並且它對項目的侵入性很小,幾乎不用作任何代碼層的修改,也無需修改 SQL
語句,只需配置待分庫分表的數據表便可。
總結
簡單的回顧一下分庫分表的基礎知識,接下來的文章會配合實戰項目介紹 sharding-jdbc
在分庫分表中的各個功能點。
整理了幾百本各種技術電子書,送給小夥伴們。關注公號回覆【666】自行領取。和一些小夥伴們建了一個技術交流羣,一塊兒探討技術、分享技術資料,旨在共同窗習進步,若是感興趣就加入咱們吧!