目錄
1.什么是分庫分表
2.分片方法
3.測試數(shù)據(jù)
4.shardingSphere
4.1.介紹
4.2.sharding jdbc
4.3.sharding proxy
4.4.兩者之間的對比
5.留個尾巴
1.什么是分庫分表
分庫分表是一種場景解決方案,它的出現(xiàn)是為了解決一些場景問題的,哪些場景喃?
-
單表過大的話,讀請求進(jìn)來,查數(shù)據(jù)需要的時間會過長
-
讀請求過多,單節(jié)點(diǎn)IO壓力太大,IO壓力太大會造成什么?可能會造成IO阻塞,造成響應(yīng)速度變慢。
分庫分表是指的兩種維度,一種維度是分庫,另一種維度是分表。分的話有兩種分法,一種是水平分,另一種是垂直分。
水平分是指將數(shù)據(jù)分為多段,一個服務(wù)器節(jié)點(diǎn)上存放一段,讀寫的時候走自己要的那一段所在服務(wù)器上。一段也叫一個分片(sharding)
垂直分是指將一個庫或者一個表從一個整體拆成多個部分,不同服務(wù)器上存儲一部分:
2.分片方法
其實(shí)總的來說分庫都還好,垂直分庫對應(yīng)著服務(wù)拆成微服務(wù)做到資源隔離各玩兒各的,問題都還不大,而且一般不會出現(xiàn)水平分庫,因?yàn)閹炖锩鏀?shù)據(jù)多的也就某一些表,我們面對更多的是水平分表。水平分表首先要面對的就是如何分片?
分片方法有如下幾種:
-
hash分片法
-
range分片法
hash分片法:
主鍵對服務(wù)器數(shù)量取余。
這種方式在擴(kuò)容后數(shù)據(jù)需要重新散列一遍,重新散列一遍花時間嗎?當(dāng)然花時間,但是不散列又不行,為什么喃?舉個例,原來id=12的數(shù)據(jù)散列到了0表,擴(kuò)容后不遷移的話按照規(guī)則id=12的表會散列到4表,這就會導(dǎo)致id=12這條數(shù)據(jù)在查找的時候找不到:
當(dāng)然hash算法可以用一致性hash算法來優(yōu)化,但其數(shù)據(jù)遷移肯定是無法規(guī)避的,且一致性hash算法本身也存在無法規(guī)避的缺點(diǎn)。博主之前有一篇一致性hash算法的文章,可移步:
一致性hash算法_一直hash算法-CSDN博客
range分片法:
按照編號順序均勻的分片,好處是擴(kuò)容不用散列,但是新數(shù)據(jù)往往是使用頻率更高的數(shù)據(jù),會導(dǎo)致壓力不均勻,而且現(xiàn)在一般唯一ID為了安全性都是無序的,比如采用UUID做主鍵的時候,所以range分片法的場景適用也很有限。
3.測試數(shù)據(jù)
用一張訂單表來做測試數(shù)據(jù),根據(jù)主鍵來分庫分表:
create table order_( id varchar(100) primary key, productName VARCHAR(100), productId VARCHAR(100), createTime datetime, statue INT )ENGINE=INNODB;
準(zhǔn)備了兩個庫,db01和db02都有這張訂單表:
依賴版本:
千萬注意版本的對齊!
<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ū)動 --> ? ? ? <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.介紹
分片方法說起來容易,要自己去實(shí)現(xiàn)一個全過程的分片分表還是很繁瑣的,需要手動實(shí)現(xiàn)多數(shù)據(jù)源,然后實(shí)現(xiàn)散列算法來控制讀寫請求映射到哪一臺服務(wù)器,升級一點(diǎn)的功能還包括要與服務(wù)器進(jìn)行心跳通信,獲取服務(wù)器的信息等等。所以說還是直接用"輪子"吧。
Apache ShardingSphere 是一個開源的分布式數(shù)據(jù)庫中間件解決方案,它由阿里巴巴集團(tuán)開源,目前是 Apache 軟件基金會旗下的頂級項(xiàng)目。ShardingSphere 通過提供一組與數(shù)據(jù)庫交互的標(biāo)準(zhǔn)化接口(如JDBC驅(qū)動或代理服務(wù)),對上層應(yīng)用隱藏了復(fù)雜的分布式數(shù)據(jù)庫處理邏輯,為開發(fā)者提供了易用且功能強(qiáng)大的分庫分表、讀寫分離、數(shù)據(jù)治理、彈性伸縮等功能。
ShardingSphere分為三部分:Sharding-JDBC、Sharding-Proxy、Sharding-Sidecar。
4.2.sharding jdbc
其中Sharding-JDBC,其會托管JDBC,然后支持實(shí)現(xiàn)分庫分表、讀寫分離。分庫分表和讀寫分離都是通過配置實(shí)現(xiàn)的,配置好數(shù)據(jù)源,然后配置好分庫規(guī)則即可。當(dāng)然讀寫分離的前提是數(shù)據(jù)庫已經(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字段的分庫和分表規(guī)則。當(dāng)然還提供了接口,對于自定義分庫、分表規(guī)則,可以通過實(shí)現(xiàn)ShardingSphere提供的接口來自定義算法類,并在配置中引用這些類。
public class CustomDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> { ? @Override ? public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) { ? ? ? // 根據(jù)order_id和其他可能的業(yè)務(wù)邏輯計(jì)算數(shù)據(jù)庫名稱 ? ? ? int orderId = shardingValue.getValue(); ? ? ? return "ds" + (orderId % 2); // 這里僅作為示例,實(shí)際請根據(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 ? ? ? ? ? ? # 同樣可以為表級別分片指定自定義算法類 ? ? ? ? ? ? algorithm-class-name: com.example.CustomTableShardingAlgorithm ? ? # ... 讀寫分離配置 ... ? props: ? ? sql.show: true
同樣的,如果需要自定義分表規(guī)則,也需要創(chuàng)建一個實(shí)現(xiàn)相應(yīng)接口(如PreciseShardingAlgorithm)的類,并在table-strategy部分通過algorithm-class-name屬性引用它。以上示例中的CustomTableShardingAlgorithm即是一個假設(shè)存在的自定義分表策略類。請確保實(shí)際應(yīng)用中已正確創(chuàng)建并配置此類。
4.3.sharding proxy
sharding proxy是一個中間件,也能實(shí)現(xiàn)分庫分表和讀寫分離。不同于sharding jdbc需要侵入代碼中對JDBC進(jìn)行一個托管,sharding
proxy是無侵入式的,一個獨(dú)立的組件。
sharding proxy需要先下載,然后解壓、配置。
配置示例:
配置數(shù)據(jù)庫的信息
然后需要導(dǎo)入mysql的驅(qū)動:
配置分庫分表:
這里要注意了databaseName指向的數(shù)據(jù)庫是一個總庫,應(yīng)用都會往這個庫里面進(jìn)行數(shù)據(jù)讀寫,然后由sharding proxy來向我們配置的不同數(shù)據(jù)源里進(jìn)行分庫分表。給出一個配置文件,大家感受一下,該配置文件基于Apache ShardingSphere 5.x版本的語法編寫。不同版本可能配置項(xiàng)存在不同哈。
# config-sharding.yaml ? schemaName: testDemo # 指定邏輯庫名稱 ? 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.兩者之間的對比
sharding jdbc是侵入了應(yīng)用,托管了JDBC,對代碼有侵入性。
sharding proxy是對數(shù)據(jù)庫下手,其并沒用侵入數(shù)據(jù)庫,也沒用上數(shù)據(jù)庫的bin log,而是去監(jiān)聽數(shù)據(jù)庫的端口從而來攔截下sql。
但是proxy明顯可以看到是中心化的,都在向一個點(diǎn)來寫數(shù)據(jù),是會有性能瓶頸的。
5.留個尾巴
不管是水平拆還是垂直拆,分庫分表后一定會存在兩個核心問題:
-
不好join,需要在程序?qū)用孢M(jìn)行join
-
分布式事務(wù)
sharding是如何解決第一個問題的喃?首先sharding會各個節(jié)點(diǎn)上進(jìn)行全表掃描,用類似笛卡爾積的辦法聚合成最終的結(jié)果。文章來源:http://www.zghlxwxcb.cn/news/detail-838754.html
至于第二個問題,留在后文,我們將深入探究一下sharding生態(tài)圈是如何實(shí)現(xiàn)分布式事務(wù)的。除此之外還有一些尾巴要留在后文繼續(xù)展開,包括:文章來源地址http://www.zghlxwxcb.cn/news/detail-838754.html
- sharding jdbc是如何托管JDBC的
- sharding proxy是否存在中心化架構(gòu)帶來的性能問題?有沒有辦法規(guī)避?
到了這里,關(guān)于【分庫分表】基于mysql+shardingSphere的分庫分表技術(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!