mysql+shardingSphere的分庫(kù)分表實(shí)現(xiàn)示例
1.什么是分庫(kù)分表
分庫(kù)分表是一種場(chǎng)景解決方案,它的出現(xiàn)是為了解決一些場(chǎng)景問(wèn)題的,哪些場(chǎng)景喃?
單表過(guò)大的話,讀請(qǐng)求進(jìn)來(lái),查數(shù)據(jù)需要的時(shí)間會(huì)過(guò)長(zhǎng)
讀請(qǐng)求過(guò)多,單節(jié)點(diǎn)IO壓力太大,IO壓力太大會(huì)造成什么?可能會(huì)造成IO阻塞,造成響應(yīng)速度變慢。
分庫(kù)分表是指的兩種維度,一種維度是分庫(kù),另一種維度是分表。分的話有兩種分法,一種是水平分,另一種是垂直分。
水平分是指將數(shù)據(jù)分為多段,一個(gè)服務(wù)器節(jié)點(diǎn)上存放一段,讀寫的時(shí)候走自己要的那一段所在服務(wù)器上。一段也叫一個(gè)分片(sharding)
垂直分是指將一個(gè)庫(kù)或者一個(gè)表從一個(gè)整體拆成多個(gè)部分,不同服務(wù)器上存儲(chǔ)一部分:
2.分片方法
其實(shí)總的來(lái)說(shuō)分庫(kù)都還好,垂直分庫(kù)對(duì)應(yīng)著服務(wù)拆成微服務(wù)做到資源隔離各玩兒各的,問(wèn)題都還不大,而且一般不會(huì)出現(xiàn)水平分庫(kù),因?yàn)閹?kù)里面數(shù)據(jù)多的也就某一些表,我們面對(duì)更多的是水平分表。水平分表首先要面對(duì)的就是如何分片?
分片方法有如下幾種:
hash分片法
range分片法
hash分片法:
主鍵對(duì)服務(wù)器數(shù)量取余。
這種方式在擴(kuò)容后數(shù)據(jù)需要重新散列一遍,重新散列一遍花時(shí)間嗎?當(dāng)然花時(shí)間,但是不散列又不行,為什么喃?舉個(gè)例,原來(lái)id=12的數(shù)據(jù)散列到了0表,擴(kuò)容后不遷移的話按照規(guī)則id=12的表會(huì)散列到4表,這就會(huì)導(dǎo)致id=12這條數(shù)據(jù)在查找的時(shí)候找不到:
當(dāng)然hash算法可以用一致性hash算法來(lái)優(yōu)化,但其數(shù)據(jù)遷移肯定是無(wú)法規(guī)避的,且一致性hash算法本身也存在無(wú)法規(guī)避的缺點(diǎn)。博主之前有一篇一致性hash算法的文章,可移步:
range分片法:
按照編號(hào)順序均勻的分片,好處是擴(kuò)容不用散列,但是新數(shù)據(jù)往往是使用頻率更高的數(shù)據(jù),會(huì)導(dǎo)致壓力不均勻,而且現(xiàn)在一般唯一ID為了安全性都是無(wú)序的,比如采用UUID做主鍵的時(shí)候,所以range分片法的場(chǎng)景適用也很有限。
3.測(cè)試數(shù)據(jù)
用一張訂單表來(lái)做測(cè)試數(shù)據(jù),根據(jù)主鍵來(lái)分庫(kù)分表:
create table order_( id varchar(100) primary key, productName VARCHAR(100), productId VARCHAR(100), createTime datetime, statue INT )ENGINE=INNODB;
準(zhǔn)備了兩個(gè)庫(kù),db01和db02都有這張訂單表:
依賴版本:
千萬(wàn)注意版本的對(duì)齊!
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--prometheus --> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> ? <!-- MySQL驅(qū)動(dòng) --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <!-- MyBatis Plus Starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <!--sharding-jdbc--> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.1</version> </dependency> <!-- Alibaba Druid 數(shù)據(jù)源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.6.3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
4.shardingSphere
4.1.介紹
分片方法說(shuō)起來(lái)容易,要自己去實(shí)現(xiàn)一個(gè)全過(guò)程的分片分表還是很繁瑣的,需要手動(dòng)實(shí)現(xiàn)多數(shù)據(jù)源,然后實(shí)現(xiàn)散列算法來(lái)控制讀寫請(qǐng)求映射到哪一臺(tái)服務(wù)器,升級(jí)一點(diǎn)的功能還包括要與服務(wù)器進(jìn)行心跳通信,獲取服務(wù)器的信息等等。所以說(shuō)還是直接用"輪子"吧。
Apache ShardingSphere 是一個(gè)開源的分布式數(shù)據(jù)庫(kù)中間件解決方案,它由阿里巴巴集團(tuán)開源,目前是 Apache 軟件基金會(huì)旗下的頂級(jí)項(xiàng)目。ShardingSphere 通過(guò)提供一組與數(shù)據(jù)庫(kù)交互的標(biāo)準(zhǔn)化接口(如JDBC驅(qū)動(dòng)或代理服務(wù)),對(duì)上層應(yīng)用隱藏了復(fù)雜的分布式數(shù)據(jù)庫(kù)處理邏輯,為開發(fā)者提供了易用且功能強(qiáng)大的分庫(kù)分表、讀寫分離、數(shù)據(jù)治理、彈性伸縮等功能。
ShardingSphere分為三部分:Sharding-JDBC、Sharding-Proxy、Sharding-Sidecar。
4.2.sharding jdbc
其中Sharding-JDBC,其會(huì)托管JDBC,然后支持實(shí)現(xiàn)分庫(kù)分表、讀寫分離。分庫(kù)分表和讀寫分離都是通過(guò)配置實(shí)現(xiàn)的,配置好數(shù)據(jù)源,然后配置好分庫(kù)規(guī)則即可。當(dāng)然讀寫分離的前提是數(shù)據(jù)庫(kù)已經(jīng)配置成了讀寫分離的模式。以下是配置示例:
spring: application: name: testDemo shardingsphere: datasource: names: ds0,ds1 ds0: driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://localhost:3306/db01?serverTimezone=UTC username: root password: admin ds1: driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://localhost:3306/db02?serverTimezone=UTC username: root password: admin sharding: default-database-strategy: inline: sharding-column: order_id algorithm-expression: ds$->{order_id % 2} tables: t_order: actual-data-nodes: ds$->{0..1}.t_order_$->{0..1} table-strategy: inline: sharding-column: order_id algorithm-expression: t_order_$->{order_id % 2} #讀寫分離 master-slave-rules: ms_ds: master-data-source-name: ds0 slave-data-source-names: ds1 load-balance-algorithm-type: ROUND_ROBIN #負(fù)載均衡算法 props: sql.show: true #是否打印sql
上述YAML配置已經(jīng)使用了inline表達(dá)式實(shí)現(xiàn)了基于order_id字段的分庫(kù)和分表規(guī)則。當(dāng)然還提供了接口,對(duì)于自定義分庫(kù)、分表規(guī)則,可以通過(guò)實(shí)現(xiàn)ShardingSphere提供的接口來(lái)自定義算法類,并在配置中引用這些類。
public class CustomDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> { @Override public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) { // 根據(jù)order_id和其他可能的業(yè)務(wù)邏輯計(jì)算數(shù)據(jù)庫(kù)名稱 int orderId = shardingValue.getValue(); return "ds" + (orderId % 2); // 這里僅作為示例,實(shí)際請(qǐng)根據(jù)業(yè)務(wù)需求編寫 } }
spring: application: name: testDemo shardingsphere: # ... 數(shù)據(jù)源配置 ... sharding: default-database-strategy: precise: sharding-column: order_id algorithm-class-name: com.example.CustomDatabaseShardingAlgorithm tables: t_order: actual-data-nodes: ds$->{0..1}.t_order_$->{0..1} table-strategy: precise: sharding-column: order_id # 同樣可以為表級(jí)別分片指定自定義算法類 algorithm-class-name: com.example.CustomTableShardingAlgorithm # ... 讀寫分離配置 ... props: sql.show: true
同樣的,如果需要自定義分表規(guī)則,也需要?jiǎng)?chuàng)建一個(gè)實(shí)現(xiàn)相應(yīng)接口(如PreciseShardingAlgorithm)的類,并在table-strategy部分通過(guò)algorithm-class-name屬性引用它。以上示例中的CustomTableShardingAlgorithm即是一個(gè)假設(shè)存在的自定義分表策略類。請(qǐng)確保實(shí)際應(yīng)用中已正確創(chuàng)建并配置此類。
4.3.sharding proxy
sharding proxy是一個(gè)中間件,也能實(shí)現(xiàn)分庫(kù)分表和讀寫分離。不同于sharding jdbc需要侵入代碼中對(duì)JDBC進(jìn)行一個(gè)托管,sharding
proxy是無(wú)侵入式的,一個(gè)獨(dú)立的組件。
sharding proxy需要先下載,然后解壓、配置。
配置示例:
配置數(shù)據(jù)庫(kù)的信息
然后需要導(dǎo)入mysql的驅(qū)動(dòng):
配置分庫(kù)分表:
這里要注意了databaseName指向的數(shù)據(jù)庫(kù)是一個(gè)總庫(kù),應(yīng)用都會(huì)往這個(gè)庫(kù)里面進(jìn)行數(shù)據(jù)讀寫,然后由sharding proxy來(lái)向我們配置的不同數(shù)據(jù)源里進(jìn)行分庫(kù)分表。給出一個(gè)配置文件,大家感受一下,該配置文件基于Apache ShardingSphere 5.x版本的語(yǔ)法編寫。不同版本可能配置項(xiàng)存在不同哈。
# config-sharding.yaml ? schemaName: testDemo # 指定邏輯庫(kù)名稱 ? rules: - !SHARDING dataSources: ds0: url: jdbc:mysql://localhost:3306/db01?serverTimezone=UTC username: root password: admin connectionTimeoutMilliseconds: 30000 idleTimeoutMilliseconds: 60000 maxLifetimeMilliseconds: 1800000 type: com.alibaba.druid.pool.DruidDataSource ds1: url: jdbc:mysql://localhost:3306/db02?serverTimezone=UTC username: root password: admin # 其他連接池屬性... ? shardingRule: tables: t_order: actualDataNodes: ds$->{0..1}.t_order_$->{0..1} databaseStrategy: inline: shardingColumn: order_id algorithmExpression: ds$->{order_id % 2} tableStrategy: inline: shardingColumn: order_id algorithmExpression: t_order_$->{order_id % 2} ? masterSlaveRules: ms_ds: masterDataSourceName: ds0 slaveDataSourceNames: [ds1] loadBalanceAlgorithmType: ROUND_ROBIN ? props: sql.show: true
4.4.兩者之間的對(duì)比
sharding jdbc是侵入了應(yīng)用,托管了JDBC,對(duì)代碼有侵入性。
sharding proxy是對(duì)數(shù)據(jù)庫(kù)下手,其并沒(méi)用侵入數(shù)據(jù)庫(kù),也沒(méi)用上數(shù)據(jù)庫(kù)的bin log,而是去監(jiān)聽(tīng)數(shù)據(jù)庫(kù)的端口從而來(lái)攔截下sql。
但是proxy明顯可以看到是中心化的,都在向一個(gè)點(diǎn)來(lái)寫數(shù)據(jù),是會(huì)有性能瓶頸的。
5.留個(gè)尾巴
不管是水平拆還是垂直拆,分庫(kù)分表后一定會(huì)存在兩個(gè)核心問(wèn)題:
不好join,需要在程序?qū)用孢M(jìn)行join
分布式事務(wù)
sharding是如何解決第一個(gè)問(wèn)題的喃?首先sharding會(huì)各個(gè)節(jié)點(diǎn)上進(jìn)行全表掃描,用類似笛卡爾積的辦法聚合成最終的結(jié)果。
至于第二個(gè)問(wèn)題,留在后文,我們將深入探究一下sharding生態(tài)圈是如何實(shí)現(xiàn)分布式事務(wù)的。除此之外還有一些尾巴要留在后文繼續(xù)展開,包括:
- sharding jdbc是如何托管JDBC的
- sharding proxy是否存在中心化架構(gòu)帶來(lái)的性能問(wèn)題?有沒(méi)有辦法規(guī)避?
到此這篇關(guān)于mysql+shardingSphere的分庫(kù)分表實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)mysql shardingSphere分庫(kù)分表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文搞懂mysql如何處理json格式的字段(解析json數(shù)據(jù))
這篇文章主要給大家介紹了關(guān)于mysql如何處理json格式的字段的相關(guān)資料,MySQL中的JSON類型是一種數(shù)據(jù)類型,用于存儲(chǔ)和處理JSON(JavaScript Object Notation)格式的數(shù)據(jù),需要的朋友可以參考下2023-12-12Mysql查詢優(yōu)化的一些實(shí)用方法總結(jié)
對(duì)于MySQL查詢語(yǔ)句來(lái)說(shuō),效率是最重要的,下面這篇文章主要給大家介紹了關(guān)于Mysql查詢優(yōu)化的一些實(shí)用方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04Windows下Mysql啟動(dòng)報(bào)1067的解決方法
這篇文章主要為大家詳細(xì)介紹了Windows下Mysql啟動(dòng)報(bào)1067的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10MySQL中case?when的兩種基本用法及區(qū)別總結(jié)
在mysql中case when用于計(jì)算條件列表并返回多個(gè)可能結(jié)果表達(dá)式之一,下面這篇文章主要給大家介紹了關(guān)于MySQL中case?when的兩種基本用法及區(qū)別的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05詳解騰訊云CentOS7.0使用yum安裝mysql及使用遇到的問(wèn)題
本篇文章主要介紹了騰訊云CentOS7.0使用yum安裝mysql,詳細(xì)的介紹了使用yum安裝mysql及使用遇到的問(wèn)題,有興趣的可以了解一下。2017-01-01MySQL數(shù)據(jù)庫(kù)的23個(gè)注意事項(xiàng)
使用MySQL,安全問(wèn)題不能不注意。以下是MySQL提示的23個(gè)注意事項(xiàng)2010-03-03mysql中g(shù)roup by與having合用注意事項(xiàng)分享
在mysql中g(shù)roup by分組查詢我們經(jīng)常會(huì)用到,并且還同時(shí)會(huì)與having合用,下面我介紹group by用法與having合用注意事項(xiàng),希望此教程對(duì)各位朋友有所幫助2013-10-10