Sharding-JDBC 從入門到精通 -2


《SpringCloud Nginx 高併發核心編程》 環境搭建 - 系列

組件 連接地址
windows centos 虛擬機 安裝&排坑 vagrant+java+springcloud+redis+zookeeper鏡像下載(&製做詳解))
centos mysql 安裝&排坑 centos mysql 筆記(內含vagrant mysql 鏡像)
linux kafka安裝&排坑 kafka springboot (或 springcloud ) 整合
Linux openresty 安裝 Linux openresty 安裝
【必須】Linux Redis 安裝(帶視頻) Linux Redis 安裝(帶視頻)
【必須】Linux Zookeeper 安裝(帶視頻) Linux Zookeeper 安裝, 帶視頻
Windows Redis 安裝(帶視頻) Windows Redis 安裝(帶視頻)
RabbitMQ 離線安裝(帶視頻) RabbitMQ 離線安裝(帶視頻)
ElasticSearch 安裝, 帶視頻 ElasticSearch 安裝, 帶視頻
Nacos 安裝(帶視頻) Nacos 安裝(帶視頻)
【必須】Eureka Eureka 入門,帶視頻
【必須】springcloud Config 入門,帶視頻 springcloud Config 入門,帶視頻
【必須】SpringCloud 腳手架打包與啓動 SpringCloud腳手架打包與啓動
Linux 自啓動 假死自啓動 定時自啓 Linux 自啓動 假死啓動

目錄: Sharding-JDBC 從入門到精通

組件 連接地址
準備一: 在window安裝虛擬機集羣 vagrant+java+springcloud+redis+zookeeper鏡像下載(&製做詳解))
準備二:在虛擬機上安裝 mysql ,至少須要兩個mysql節點 centos mysql 筆記(內含vagrant mysql 鏡像)
Sharding-JDBC 從入門到精通之一 入門實戰
Sharding-JDBC 從入門到精通之二 基本原理
Sharding-JDBC 從入門到精通之源碼 git

1 分庫分表與讀寫分離簡介

1.1爲何要分庫分表?

數據庫分庫分表從互聯網時代開啓至今,一直是熱門話題。在NoSQL橫行的今天,關係型數據庫憑藉其穩定、查詢靈活、兼容等特性,仍被大多數公司做爲首選數據庫。所以,合理採用分庫分表技術應對海量數據和高併發對數據庫的衝擊,是各大互聯網公司不可避免的問題node

1.2分庫分表適用場景

分庫分表用於應對當前互聯網常見的兩個場景——大數據量和高併發。一般分爲兩種:mysql

垂直拆分和水平拆分linux

垂直拆分

垂直拆分是根據業務將一個庫(表)拆分爲多個庫(表)。如:將常常和不常訪問的字段拆分至不一樣的庫或表中。因爲與業務關係密切,目前的分庫分表產品均使用水平拆分方式。nginx

水平拆分

水平拆分則是根據分片算法將一個庫(表)拆分爲多個庫(表)。如:按照ID的最後一位以3取餘,尾數是1的放入第1個庫(表),尾數是2的放入第2個庫(表)等。git

關係型數據庫在大於必定數據量的狀況下檢索性能會急劇降低。在面對互聯網海量數據狀況時,全部數據都存於一張表,顯然會輕易超過數據庫表可承受的數據量閥值。這個單表可承受的數據量閥值,需根據數據庫和併發量的差別,經過實際測試得到。面試

單純的分表雖然能夠解決數據量過大致使檢索變慢的問題,但沒法解決過多併發請求訪問同一個庫,致使數據庫響應變慢的問題。因此一般水平拆分都至少要採用分庫的方式,用於一併解決大數據量和高併發的問題。這也是部分開源的分片數據庫中間件只支持分庫的緣由。redis

1.3分庫

分庫:隨着業務數據量的增長,原來全部的數據都是在一個數據庫上的,網絡IO及文件IO都集中在一個數據庫上的,所以CPU、內存、文件IO、網絡IO均可能會成爲系統瓶頸。

當業務系統的數據容量接近或超過單臺服務器的容量、QPS/TPS接近或超過單個數據庫實例的處理極限等,此時,每每是採用垂直和水平結合的數據拆分方法,把數據服務和數據存儲分佈到多臺數據庫服務器上。

1.4分表

傾向使用分表而不是分庫的理由之一:在於事務的性能。最多見的分表需求是事務問題。同在一個庫則不需考慮分佈式事務,善於使用同庫不一樣表可有效避免分佈式事務帶來的麻煩。目前強一致性的分佈式事務因爲性能問題,致使使用起來並不必定比不分庫分錶快。

分表的另外一個存在的理由是,過多的數據庫實例不利於運維管理。

不過,因爲目前採用最終一致性的柔性事務居多,因此,分庫的事務性能也是很高的,有關最終一致性的柔性事務,請參見瘋狂創客圈的專題博文。

分表也有兩種方案:

  1. 同庫分表:全部的分表都在一個數據庫中,因爲數據庫中表名不能重複,所以須要把數據表名起成不一樣的名字。
  • 優勢:因爲都在一個數據庫中,公共表,沒必要進行復制,處理更簡單
  • 缺點:因爲還在一個數據庫中,CPU、內存、文件IO、網絡IO等瓶頸仍是沒法解決,只能下降單表中的數據記錄數。表名不一致,會導後續的處理複雜(參照mysql meage存儲引擎來處理)   
  1. 不一樣庫分表:因爲分表在不一樣的數據庫中,這個時候就可使用一樣的表名。
  • 優勢:CPU、內存、文件IO、網絡IO等瓶頸能夠獲得有效解決,表名相同,處理起來相對簡單
  • 缺點:公共表因爲在全部的分表都要使用,所以要進行復制、同步。

綜上所述,最佳實踐是合理地配合使用分庫+分表

以 MySQL 爲例,分庫分表從階段應該拆分爲第一階段分表、第2階段分庫.

通常來講是先進行分表,分表的原動力在於 MySQL 單表性能問題,相信你們都據說過相似這樣的話,聽說 MySQL 單表數據量超過 N 千萬、或者表 Size 大於 N十G 性能就不行了。這個說法背後的邏輯是數據量超過必定大小,B+Tree 索引的高度就會增長,而每增長一層高度,整個索引掃描就會多一次 IO 。整個邏輯有必定道理,而從筆者的經驗來看,其實更關鍵在於應用自己的使用,若是多數是索引命中率很高的點查或者小範圍查,其實這個上限還很高,咱們維護的系統裏超過10億級的表很常見。但正是因爲業務的不可控,因此你們每每採起比較保守的策略,這就是分表的緣由。

分庫主要因爲 MySQL 容量上,MySQL 的寫入是很昂貴的操做,它自己有不少優化技術,即便如此,寫入也存在放大不少倍的現象。因此就出現了肚子分離的方案。

1.5讀寫分離方案

海量數據的存儲及訪問,經過對數據庫進行讀寫分離,來提高數據的處理能力。讀寫分離它的方案特色是數據庫產生多個副本,數據庫的寫操做都集中到一個數據庫上,而一些讀的操做呢,能夠分解到其它數據庫上。這樣,只要付出數據複製的成本,就可使得數據庫的處理壓力分解到多個數據庫上,從而大大提高數據處理能力。

MySQL M-S(Master-Slave主從架構) 的架構雖然自然地支持讀流量擴展,但因爲 MySQL 從庫複製默認採用單線程的 SQL thread 進行 Binlog 順序重放,這種單線程的從庫寫入極大地限制整個集羣的寫入能力,(除非不在乎數據延遲,而數據延遲與否直接影響了讀流量的可用性)。

MySQL 基於組提交的並行複製從某種程度上緩解了這個問題,但本質上寫入上限仍是很是容易達到(實際業務也就 小几千 的 TPS ) 。說到這,目前有一些雲 RDS 經過計算與存儲分離、log is database 的理念來很大程度解決了寫入擴大的問題,但在這以前,更爲廣泛的解決方案就是把一個集羣拆分紅 N 個集羣,即分庫分表(sharding)。爲了規避熱點問題,絕大多數採用的方法就是 hash 切分,也有極少的範圍、或者基於 Mapping 的查詢切分。

2 Sharding-JDBC簡介

Sharding-JDBC 是噹噹網開源的適用於微服務的分佈式數據訪問基礎類庫,完整的實現了分庫分表,讀寫分離和分佈式主鍵功能,並初步實現了柔性事務。從 2016 年開源至今,在經歷了總體架構的數次精煉以及穩定性打磨後,現在它已積累了足夠的底蘊。官方的網址以下:

http://shardingsphere.apache.org/index_zh.html

ShardingSphere是一套開源的分佈式數據庫中間件解決方案組成的生態圈,它由Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar這3款相互獨立的產品組成。

他們均提供標準化的數據分片、分佈式事務 和 數據庫治理功能,可適用於如Java同構、異構語言、雲原生等各類多樣化的應用場景。

Apache ShardingSphere 是一套開源的分佈式數據庫中間件解決方案組成的生態圈,它由 JDBC、Proxy 和 Sidecar(規劃中)這 3 款相互獨立,卻又可以混合部署配合使用的產品組成。 它們均提供標準化的數據分片、分佈式事務和數據庫治理功能,可適用於如 Java 同構、異構語言、雲原生等各類多樣化的應用場景。

Apache ShardingSphere 定位爲關係型數據庫中間件,旨在充分合理地在分佈式的場景下利用關係型數據庫的計算和存儲能力,而並不是實現一個全新的關係型數據庫。 它經過關注不變,進而抓住事物本質。關係型數據庫當今依然佔有巨大市場,是各個公司核心業務的基石,將來也難於撼動,咱們目前階段更加關注在原有基礎上的增量,而非顛覆。

Apache ShardingSphere 5.x 版本開始致力於可插拔架構,項目的功能組件可以靈活的以可插拔的方式進行擴展。 目前,數據分片、讀寫分離、數據加密、影子庫壓測等功能,以及 MySQL、PostgreSQL、SQLServer、Oracle 等 SQL 與協議的支持,均經過插件的方式織入項目。 開發者可以像使用積木同樣定製屬於本身的獨特系統。Apache ShardingSphere 目前已提供數十個 SPI 做爲系統的擴展點,仍在不斷增長中。

ShardingSphere 已於2020年4月16日成爲 Apache 軟件基金會的頂級項目。

2.1Sharding-JDBC的優點

Sharding-JDBC直接封裝JDBC API,能夠理解爲加強版的JDBC驅動,舊代碼遷移成本幾乎爲零:

  • 可適用於任何基於Java的ORM框架,如JPA、Hibernate、Mybatis、Spring JDBC Template或直接使用JDBC。
  • 可基於任何第三方的數據庫鏈接池,如DBCP、C3P0、 BoneCP、Druid等。
  • 理論上可支持任意實現JDBC規範的數據庫。雖然目前僅支持MySQL,但已有支持Oracle、SQLServer等數據庫的計劃。

1606623249835

Sharding-JDBC定位爲輕量Java框架,使用客戶端直連數據庫,以jar包形式提供服務,無proxy代理層,無需額外部署,無其餘依賴,DBA也無需改變原有的運維方式。

Sharding-JDBC分片策略靈活,可支持等號、between、in等多維度分片,也可支持多分片鍵。

SQL解析功能完善,支持聚合、分組、排序、limit、or等查詢,並支持Binding Table以及笛卡爾積表查詢。

2.2與常見開源產品對比

下表僅列出在數據庫分片領域很是有影響力的幾個項目:

經過以上表格能夠看出,Cobar(MyCat)屬於中間層方案,在應用程序和MySQL之間搭建一層Proxy。中間層介於應用程序與數據庫間,須要作一次轉發,而基於JDBC協議並沒有額外轉發,直接由應用程序鏈接數據庫,性能上有些許優點。這裏並不是說明中間層必定不如客戶端直連,除了性能,須要考慮的因素還有不少,中間層更便於實現監控、數據遷移、鏈接管理等功能。

Cobar-Client、TDDL和Sharding-JDBC均屬於客戶端直連方案。此方案的優點在於輕便、兼容性、性能以及對DBA影響小。其中Cobar-Client的實現方式基於ORM(Mybatis)框架,其兼容性與擴展性不如基於JDBC協議的後二者。

目前經常使用的就是Cobar(MyCat)與Sharding-JDBC兩種方案

MyCAT

MyCAT是社區愛好者在阿里cobar基礎上進行二次開發,解決了cobar當時存 在的一些問題,而且加入了許多新的功能在其中。目前MyCAT社區活 躍度很高,

目前已經有一些公司在使用MyCAT。整體來講支持度比 較高,也會一直維護下去,發展到目前的版本,已經不是一個單純的MySQL代理了,

它的後端能夠支持MySQL, SQL Server, Oracle, DB2, PostgreSQL等主流數據庫,也支持MongoDB這種新型NoSQL方式的存儲,將來還會支持更多類型的存儲。

MyCAT是一個強大的數據庫中間件,不只僅能夠用做讀寫分離,以及分表分庫、容災管理,並且能夠用於多租戶應用開發、雲平臺基礎設施,讓你的架構具有很強的適應性和靈活性,

藉助於即將發佈的MyCAT只能優化模塊,系統的數據訪問瓶頸和熱點一目瞭然,根據這些統計分析數據,你能夠自動或手工調整後端存儲,將不一樣的表隱射到不一樣存儲引擎上,而整個應用的代碼一行也不用改變。

MyCAT是在Cobar基礎上發展的版本,兩個顯著提升:後端由BIO改成NIO,併發量有大幅提升; 增長了對Order By, Group By, Limit等聚合功能

(雖然Cobar也能夠支持Order By, Group By, Limit語法,可是結果沒有進行聚合,只是簡單返回給前端,聚合功能仍是須要業務系統本身完成, 適用於有專門團隊維護的大型企業、或者大團隊。)

Sharding-JDBC

Sharding-JDBC定位爲輕量Java框架,使用客戶端直連數據庫,以jar包形式提供服務,無proxy代理層,無需額外部署,無其餘依賴,DBA也無需改變原有的運維方式。因此 ,適用於中小企業、或者中小團隊

Sharding-JDBC分片策略靈活,可支持等號、between、in等多維度分片,也可支持多分片鍵。

SQL解析功能完善,支持聚合、分組、排序、limit、or等查詢,並支持Binding Table以及笛卡爾積表查詢。

Sharding-JDBC 功能列表

  • 分庫 & 分表
  • 讀寫分離
  • 分佈式主鍵

3 Sharding-JDBC實現原理

前文已介紹了Sharding-JDBC是實現了JDBC協議的jar文件。基於JDBC協議的實現與基於MySQL等數據庫協議實現的中間層略有差異。

不管使用哪一種架構,核心邏輯均極爲類似,除了協議實現層不一樣(JDBC或數據庫協議),都會分爲分片規則配置、SQL解析、SQL改寫、SQL路由、SQL執行以及結果歸併等模塊。

Sharding-JDBC的總體架構圖參見圖1。

img圖1 Sharding-JDBC的

分片規則配置

Sharding-JDBC的分片邏輯很是靈活,支持:

  • 分片策略自定義
  • 複數分片鍵、
  • 多運算符分片等。

如:根據用戶ID分庫,根據訂單ID分表這種分庫分表結合的分片策略;或根據年分庫,月份+用戶區域ID分表這樣的多片鍵分片。

Sharding-JDBC除了支持 = 運算符進行分片,還支持IN/BETWEEN運算符分片,提供了更增強大的分片功能,分片算法須要應用方開發者自行實現, 可實現的靈活度很是高。

分片算法

目前提供4種分片算法。因爲分片算法和業務實現緊密相關,所以並未提供內置分片算法,而是經過分片策略將各類場景提煉出來,提供更高層級的抽象,並提供接口讓應用開發者自行實現分片算法。

  • 精確分片算法
    對應PreciseShardingAlgorithm,用於處理使用單一鍵做爲分片鍵的=與IN進行分片的場景。須要配合StandardShardingStrategy使用。

  • 範圍分片算法
    對應RangeShardingAlgorithm,用於處理使用單一鍵做爲分片鍵的BETWEEN AND進行分片的場景。須要配合StandardShardingStrategy使用。

  • 複合分片算法
    對應ComplexKeysShardingAlgorithm,用於處理使用多鍵做爲分片鍵進行分片的場景,包含多個分片鍵的邏輯較複雜,須要應用開發者自行處理其中的複雜度。須要配合ComplexShardingStrategy使用。

  • Hint分片算法
    對應HintShardingAlgorithm,用於處理使用Hint行分片的場景。須要配合HintShardingStrategy使用。\

規則配置

Sharding-JDBC能夠經過Java,YAML,Spring命名空間和Spring Boot Starter四種方式配置,開發者可根據場景選擇適合的配置方式。詳情請參見後面的內容。

JDBC規範重寫

Sharding-JDBC對JDBC規範的重寫思路是針對DataSource、Connection、Statement、PreparedStatement和ResultSet五個核心接口封裝,將多個真實JDBC實現類集合(如:MySQL JDBC實現/DBCP JDBC實現等)歸入Sharding-JDBC實現類管理。

Sharding-JDBC儘可能最大化實現JDBC協議,包括addBatch這種在JPA中會使用的批量更新功能。但分片JDBC畢竟與原生JDBC不一樣,因此目前仍有未實現的接口,包括Connection遊標,存儲過程和savePoint相關、ResultSet向前遍歷和修改等不太經常使用的功能。此外,爲了保證兼容性,並未實現JDBC 4.1及其後發佈的接口(如:DBCP 1.x版本不支持JDBC 4.1)。

SQL解析

SQL解析做爲分庫分表類產品的核心,性能和兼容性是最重要的衡量指標。目前常見的SQL解析器主要有fdb/jsqlparser和Druid。Sharding-JDBC使用Druid做爲SQL解析器,經實際測試,Druid解析速度是另外兩個解析器的幾十倍。

目前Sharding-JDBC支持join、aggregation(包括avg)、order by、 group by、limit、甚至or查詢等複雜SQL的解析。目前不支持union、部分子查詢、函數內分片等不太適用在分片場景中出現的SQL解析。

SQL改寫

SQL改寫分爲兩部分,一部分是將分表的邏輯表名稱替換爲真實表名稱。另外一部分是根據SQL解析結果替換一些在分片環境中不正確的功能。這裏具兩個例子:

  • 第1個例子是avg計算。

在分片的環境中,以( avg1 +avg2+avg3)/3 計算平均值並不正確,須要改寫爲(sum1+sum2+sum3)/(count1+count2+ count3)。這就須要將包含avg的SQL改寫爲sum和count,而後再結果歸併時從新計算平均值。

  • 第2個例子是分頁。

假設每10條數據爲一頁,取第2頁數據。在分片環境下獲取limit 10, 10,歸併以後再根據排序條件取出前10條數據是不正確的結果。

正確的作法是將分條件改寫爲limit 0, 20,取出全部前2頁數據,再結合排序條件算出正確的數據。能夠看到越是靠後的Limit分頁效率就會越低,也越浪費內存。有不少方法可避免使用limit進行分頁,好比構建記錄行記錄數和行偏移量的二級索引,或使用上次分頁數據結尾ID做爲下次查詢條件的分頁方式。

SQL路由

SQL路由是根據分片規則配置,將SQL定位至真正的數據源。主要分爲單表路由、Binding表路由和笛卡爾積路由。

  • 單表路由

單表路由最爲簡單,但路由結果不必定落入惟一庫(表),由於支持根據between和in這樣的操做符進行分片,因此最終結果仍然可能落入多個庫(表)。

  • Binding表路由

Binding表可理解爲分庫分表規則徹底一致的主從表。舉例說明:訂單表和訂單詳情表都根據訂單ID做爲分片鍵,任意時刻分片邏輯均相同。這樣的關聯查詢和單表查詢難度和性能至關。

  • 笛卡爾積路由

笛卡爾積查詢最爲複雜,由於沒法根據Binding關係定位分片規則的一致性,因此非Binding表的關聯查詢須要拆解爲笛卡爾積組合執行。查詢性能較低,並且數據庫鏈接數較高,需謹慎使用。

SQL執行

路由至真實數據源後,Sharding-JDBC將採用多線程併發執行SQL,並完成對addBatch等批量方法的處理。

結果歸併

結果歸併包括4類:普通遍歷類、排序類、聚合類和分組類。每種類型都會先根據分頁結果跳過不須要的數據。

  • 普通遍歷類

普通遍歷類最爲簡單,只需按順序遍歷ResultSet的集合便可。

  • 排序類

排序類結果將結果先排序再輸出,由於各分片結果均按照各自條件完成排序,因此採用歸併排序算法整合最終結果。

  • 聚合類

聚合類分爲3種類型,比較型、累加型和平均值型。比較型包括max和min,只返回最大(小)結果。累加型包括sum和count,須要將結果累加後返回。平均值則是經過SQL改寫的sum和count計算,相關內容已在SQL改寫涵蓋,再也不贅述。

  • 分組類

分組類最爲複雜,須要將全部的ResultSet結果放入內存,使用map-reduce算法分組,最後根據排序和聚合條件作相關處理。最消耗內存,最損失性能的部分便是此,能夠考慮使用limit合理的限制分組數據大小。

結果歸併部分目前並未採用管道解析的方式,以後會針對這裏作更多改進。

Sharding核心配置主要以下

首先介紹,什麼是分片鍵?用於分片的數據庫字段,是將數據庫(表)水平拆分的關鍵字段。例:將訂單表中的訂單主鍵的尾數取模分片,則訂單主鍵爲分片字段。 SQL中若是無分片字段,將執行全路由,性能較差。 除了對單分片字段的支持,ShardingSphere也支持根據多個字段進行分片。

官網的說明

  • 分片規則

    分片規則配置的總入口。包含數據源配置、表配置、綁定表配置以及讀寫分離配置等

  • 數據源配置

    真實數據源列表

  • 表配置

    邏輯表名稱、數據節點與分表規則的配置

  • 數據節點配置

    用於配置邏輯表與真實表的映射關係。可分爲均勻分佈和自定義分佈兩種形式

    • 均勻分佈

    指數據表在每一個數據源內呈現均勻分佈的態勢,例如:

    db0
      ├── t_order0 
      └── t_order1 
    db1
      ├── t_order0 
      └── t_order1

    那麼數據節點的配置以下:

    db0.t_order0, db0.t_order1, db1.t_order0, db1.t_order1
    • 自定義分佈

    指數據表呈現有特定規則的分佈,例如:

    db0
      ├── t_order0 
      └── t_order1 
    db1
      ├── t_order2
      ├── t_order3
      └── t_order4

    那麼數據節點的配置以下:

    db0.t_order0, db0.t_order1, db1.t_order2, db1.t_order3, db1.t_order4
  • 分片策略配置

    對於分片策略存有數據源分片策略和表分片策略兩種維度

    • 數據源分片策略:

      對應於DatabaseShardingStrategy。用於配置數據被分配的目標數據源

    • 表分片策略
      對應於TableShardingStrategy。用於配置數據被分配的目標表,該目標表存在與該數據的目標數據源內。故表分片策略是依賴與數據源分片策略的結果的

  • 自增主鍵生成策略

    經過在客戶端生成自增主鍵替換以數據庫原生自增主鍵的方式,作到分佈式主鍵無重複。

  • Config Map

配置分庫分表數據源的元數據,可經過調用ConfigMapContext.getInstance()獲取ConfigMap中的shardingConfig數據。例:若是機器權重不一樣則流量可能不一樣,可經過ConfigMap配置機器權重元數據。

4.一、分片策略

Sharding-JDBC認爲對於分片策略存有兩種維度:

  • 數據源分片策略(DatabaseShardingStrategy):數據被分配的目標數據源
  • 表分片策略(TableShardingStrategy):數據被分配的目標表

兩種分片策略API徹底相同,可是表分片策略是依賴於數據源分片策略的(即:先分庫而後纔有分表)

Sharding分片策略繼承自ShardingStrategy,提供了5種分片策略:

  img

因爲分片算法和業務實現緊密相關,所以Sharding-JDBC並未提供內置分片算法,而是經過分片策略將各類場景提煉出來,提供更高層級的抽象,並提供接口讓應用開發者自行實現分片算法。

StandardShardingStrategy

標準分片策略。提供對SQL語句中的 =, IN和BETWEEN AND的分片操做支持。

StandardShardingStrategy只支持單分片鍵,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個分片算法。

  • PreciseShardingAlgorithm是必選的,用於處理=和IN的分片。
  • RangeShardingAlgorithm是可選的,用於處理BETWEEN AND分片,若是不配置RangeShardingAlgorithm,SQL中的BETWEEN AND將按照全庫路由處理。

ComplexShardingStrategy

複合分片策略。提供對SQL語句中的=, IN和BETWEEN AND的分片操做支持。

ComplexShardingStrategy支持多分片鍵,因爲多分片鍵之間的關係複雜,所以Sharding-JDBC並未作過多的封裝,而是直接將分片鍵值組合以及分片操做符交於算法接口,徹底由應用開發者實現,提供最大的靈活度。

HintShardingStrategy

經過Hint而非SQL解析的方式分片的策略。

InlineShardingStrategy

Inline表達式分片策略。使用Groovy的Inline表達式,提供對SQL語句中的=和IN的分片操做支持。

InlineShardingStrategy只支持單分片鍵,對於簡單的分片算法,能夠經過簡單的配置使用,從而避免繁瑣的Java代碼開發,如:

tuser${user_id % 8} 表示t_user表按照user_id按8取模分紅8個表,表名稱爲t_user_0到t_user_7。

4.二、分片算法

Sharding提供瞭如下4種算法接口:

  • PreciseShardingAlgorithm
  • RangeShardingAlgorithm
  • HintShardingAlgorithm
  • ComplexKeysShardingAlgorithm

能夠本身實現自定義的分片算法,下面以t_order_items表爲例本身實現分片算法:

Sharding-JDBC開發

引入依賴

<dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
            <version>5.0.0-alpha</version>
        </dependency>

jpa配置

spring:
  application:
    name: sharding-jdbc-provider
  jpa:  #配置自動建表:updata:沒有表新建,有表更新操做,控制檯顯示建表語句
    hibernate:
      ddl-auto: none
      dialect: org.hibernate.dialect.MySQL5InnoDBDialect
      show-sql: true
  freemarker:
    allow-request-override: false
    allow-session-override: false
    cache: false
    charset: UTF-8
    check-template-location: true
    content-type: text/html
    enabled: true
    expose-request-attributes: false
    expose-session-attributes: false
    expose-spring-macro-helpers: true
    prefer-file-system-access: true
    settings:
      classic_compatible: true
      default_encoding: UTF-8
      template_update_delay: 0
    suffix: .ftl
    template-loader-path: classpath:/templates/
  shardingsphere:
    props:
      sql:
        show: true
    # 配置真實數據源
    datasource:
      common:
        type: com.alibaba.druid.pool.DruidDataSource
#        driver-class-name: oracle.jdbc.driver.OracleDriver
        driver-class-name: com.mysql.cj.jdbc.Driver
        validationQuery: SELECT 1 FROM DUAL
      # 配置第 1 個數據源
      names: ds0,ds1
      ds0:
          url: jdbc:mysql://cdh1:3306/store?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=true&serverTimezone=UTC
          username: root
          password: 123456
      # 配置第 2 個數據源  org.apache.commons.dbcp2
      ds1:
          url: jdbc:mysql://cdh2:3306/store?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=true&serverTimezone=UTC
          username: root
          password: 123456
    # 配置分片規則和分片算法
    rules:
      # 配置分片規則
      sharding:
        tables:
          # 配置 t_order 表規則
          t_order:
            actualDataNodes: ds$->{0..1}.t_order_$->{0..1}
            # 配置分庫策略
            databaseStrategy:
              standard:
                shardingColumn: user_id
                shardingAlgorithmName: database-inline
            # 配置分表策略
            tableStrategy:
              standard:
                shardingColumn: order_id
                shardingAlgorithmName: table-inline
            keyGenerateStrategy:
              column: order_id
              keyGeneratorName: snowflake
        # 配置分片算法
        bindingTables: t_order
        sharding-algorithms:
          database-inline:
            type: INLINE
            props:
              algorithm-expression: ds$->{user_id % 2}
          table-inline:
            type: INLINE
            props:
              algorithm-expression: t_order_$->{order_id % 2}
        keyGenerators:
          snowflake:
            type: SNOWFLAKE
            props:
              workerId: 123

基於Java編碼的規則配置

Sharding-JDBC的分庫分表經過規則配置描述,如下例子是根據user_id取模分庫, 且根據order_id取模分表的兩庫兩表的配置。

// 配置真實數據源
    Map<String, DataSource> dataSourceMap = new HashMap<>();
    
    // 配置第一個數據源
    BasicDataSource dataSource1 = new BasicDataSource();
    dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource1.setUrl("jdbc:mysql://localhost:3306/ds0");
    dataSource1.setUsername("root");
    dataSource1.setPassword("");
    dataSourceMap.put("ds0", dataSource1);
    
    // 配置第二個數據源
    BasicDataSource dataSource2 = new BasicDataSource();
    dataSource2.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource2.setUrl("jdbc:mysql://localhost:3306/ds1");
    dataSource2.setUsername("root");
    dataSource2.setPassword("");
    dataSourceMap.put("ds1", dataSource2);
    
    // 配置Order表規則
    TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
    orderTableRuleConfig.setLogicTable("t_order");
    orderTableRuleConfig.setActualDataNodes("ds${0..1}.t_order${0..1}");
    
    // 配置分庫 + 分表策略
    orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds${user_id % 2}"));
    orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order${order_id % 2}"));
    
    // 配置分片規則
    ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
    shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);
    
    // 省略配置order_item表規則...
    // ...
    
    // 獲取數據源對象
    DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new ConcurrentHashMap(), new Properties());

基於Spring boot的規則配置

sharding.jdbc.datasource.names=ds0,ds1

sharding.jdbc.datasource.ds0.type=org.apache.commons.dbcp2.BasicDataSource
sharding.jdbc.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.ds0.url=jdbc:mysql://localhost:3306/ds0
sharding.jdbc.datasource.ds0.username=root
sharding.jdbc.datasource.ds0.password=

sharding.jdbc.datasource.ds1.type=org.apache.commons.dbcp2.BasicDataSource
sharding.jdbc.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.ds1.url=jdbc:mysql://localhost:3306/ds1
sharding.jdbc.datasource.ds1.username=root
sharding.jdbc.datasource.ds1.password=

sharding.jdbc.config.sharding.default-database-strategy.inline.sharding-column=user_id
sharding.jdbc.config.sharding.default-database-strategy.inline.algorithm-expression=ds$->{user_id % 2}

sharding.jdbc.config.sharding.tables.t_order.actual-data-nodes=ds$->{0..1}.t_order$->{0..1}
sharding.jdbc.config.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
sharding.jdbc.config.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order$->{order_id % 2}

sharding.jdbc.config.sharding.tables.t_order_item.actual-data-nodes=ds$->{0..1}.t_order_item$->{0..1}
sharding.jdbc.config.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id
sharding.jdbc.config.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item$->{order_id % 2}

基於Yaml的規則配置

或經過Yaml方式配置,與以上配置等價:

dataSources:
  ds0: !!org.apache.commons.dbcp.BasicDataSource
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ds0
    username: root
    password: 
  ds1: !!org.apache.commons.dbcp.BasicDataSource
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ds1
    username: root
    password: 

tables:
  t_order: 
    actualDataNodes: ds${0..1}.t_order${0..1}
    databaseStrategy: 
      inline:
        shardingColumn: user_id
        algorithmInlineExpression: ds${user_id % 2}
    tableStrategy: 
      inline:
        shardingColumn: order_id
        algorithmInlineExpression: t_order${order_id % 2}
  t_order_item: 
    actualDataNodes: ds${0..1}.t_order_item${0..1}
    databaseStrategy: 
      inline:
        shardingColumn: user_id
        algorithmInlineExpression: ds${user_id % 2}
    tableStrategy: 
      inline:
        shardingColumn: order_id
        algorithmInlineExpression: t_order_item${order_id % 2}

DataSource dataSource = YamlShardingDataSourceFactory.createDataSource(yamlFile);

回到◀瘋狂創客圈

瘋狂創客圈 - Java高併發研習社羣,爲你們開啓大廠之門

相關文章
相關標籤/搜索