使用ShardingSphere-JDBC完成Mysql的分庫分表和讀寫分離

追風人聊Java發表於2021-10-20

1. 概述

老話說的好:選擇比努力更重要,如果選錯了道路,就很難成功。

 

言歸正傳,之前我們聊了使用 MyCat 實現Mysql的分庫分表和讀寫分離,MyCat是服務端的代理,使用MyCat的好處顯而易見,整個分庫分表和讀寫分離過程對Java程式來說是完全透明的,Java程式像連線Mysql一樣,去連線MyCat即可。

但MyCat的運維成本較高,需要有專門的運維人員去維護,所以今天我們來聊聊另一個實現Mysql分庫分表、讀寫分離的方案 —— ShardingSphere-JDBC。

ShardingSphere-JDBC 是一個輕量級的Java框架, 是客戶端代理,不需要MyCat的中間代理,使用Java程式可以通過配置直接去實現Mysql分庫分表和讀寫分離,適用於運維資源比較少的情況。

 

ShardingSphere-JDBC 支援同一庫內的分表,MyCat 是不支援的,MyCat 只能在不同庫內分表。

ShardingSphere-JDBC 不支援主庫雙寫或多寫,只支援一主多從的讀寫分離配置,因此 Mysql 叢集的高可用需要使用其他手段來實現,例如 MHA。

 

2. 場景介紹 

分片1:

伺服器A IP:192.168.1.22  (Mysql從1)

伺服器B IP:192.168.1.12  (Mysql主1)

伺服器C IP:192.168.1.15  (Mysql主2)

伺服器D IP:192.168.1.16  (Mysql從2)

 

分片2:

伺服器E IP:192.168.1.11  (單點)

 

之前我們在前4臺伺服器上搭建了Mysql雙主雙從的高可用叢集,該叢集與伺服器E實現了分表分庫,本節我們使用ShardingSphere-JDBC去整合這個叢集。

關於Mysql雙主雙從叢集的具體搭建可參考以下文章:

《MyCat的快速搭建》(https://www.cnblogs.com/w84422/p/15394662.html

《Mysql讀寫分離叢集的搭建且與MyCat進行整合》(https://www.cnblogs.com/w84422/p/15401259.html

《Mysql雙主雙從高可用叢集的搭建且與MyCat進行整合》(https://www.cnblogs.com/w84422/p/15418403.html

由於  ShardingSphere-JDBC 不支援主庫雙寫或多寫,因此我們把 伺服器C 也當做一個從庫來配置。

 

 

 

3. ShardingSphere-JDBC在Springboot中的具體使用

3.1 官網地址

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

https://shardingsphere.apache.org/document/current/cn/overview/

 

3.2 引入依賴

這裡我們使用最新的 5.0.0-beta 版本

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

 

3.3 配置JPA相關配置 

# jpa 配置
spring.data.jpa.repositories.bootstrap-mode=default
spring.data.jpa.repositories.enabled=true

spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
# 啟用懶載入
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

這裡要特別注意,使用ShardingSphere-JDBC + JPA 一定要啟動懶載入配置,否則 getById 時會報錯。

 

3.4 配置資料來源

這裡我們按照場景介紹中描述的,配置5臺伺服器的資訊

# 配置真實資料來源
spring.shardingsphere.datasource.names=master0,master1,slave0,slave1,ds1

# 配置 伺服器A 資料來源
spring.shardingsphere.datasource.slave0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.slave0.jdbc-url=jdbc:mysql://192.168.1.22:3306/mycat
spring.shardingsphere.datasource.slave0.username=zhuifengren
spring.shardingsphere.datasource.slave0.password=Zhuifengren@123456

# 配置 伺服器B 資料來源
spring.shardingsphere.datasource.master0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.master0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.master0.jdbc-url=jdbc:mysql://192.168.1.12:3306/mycat
spring.shardingsphere.datasource.master0.username=zhuifengren
spring.shardingsphere.datasource.master0.password=Zhuifengren@123456

# 配置 伺服器C 資料來源
spring.shardingsphere.datasource.master1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.master1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.master1.jdbc-url=jdbc:mysql://192.168.1.15:3306/mycat
spring.shardingsphere.datasource.master1.username=zhuifengren
spring.shardingsphere.datasource.master1.password=Zhuifengren@123456

# 配置 伺服器D 資料來源
spring.shardingsphere.datasource.slave1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.slave1.jdbc-url=jdbc:mysql://192.168.1.16:3306/mycat
spring.shardingsphere.datasource.slave1.username=zhuifengren
spring.shardingsphere.datasource.slave1.password=Zhuifengren@123456

# 配置 伺服器E 資料來源
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://192.168.1.11:3306/mycat
spring.shardingsphere.datasource.ds1.username=zhuifengren
spring.shardingsphere.datasource.ds1.password=Zhuifengren@123456

 

3.5 配置 分片1 的讀寫分離策略

這裡我們使用輪詢演算法,具體的演算法可參見 ShardingSphere 官網。

裡面的 database-balance 是自定義的名稱,與下面的負載均衡演算法配置保持一致即可。

特別注意一點,ShardingSphere裡面的自定義名稱,一定不要包含下劃線,否則會報錯,雖然官網給出的示例就是包含下劃線的。

# 讀寫分離配置

# 寫資料來源名稱
spring.shardingsphere.rules.readwrite-splitting.data-sources.ds0.write-data-source-name=master0
# 讀資料來源名稱,多個從資料來源用逗號分隔
spring.shardingsphere.rules.readwrite-splitting.data-sources.ds0.read-data-source-names=master1,slave0,slave1
# 負載均衡演算法名稱
spring.shardingsphere.rules.readwrite-splitting.data-sources.ds0.load-balancer-name=database-balance
# 是否啟用查詢一致性路由
spring.shardingsphere.rules.readwrite-splitting.data-sources.ds0.query-consistent=false

# 負載均衡演算法配置
# 負載均衡演算法型別,這裡配置為輪詢
spring.shardingsphere.rules.readwrite-splitting.load-balancers.database-balance.type=ROUND_ROBIN

 

3.6 配置 user 表的分庫分表規則

之前MyCat中我們使用的是 MyCat 預設的 auto-sharding-long 演算法,user 表的 id 為 0 到 5000000 時儲存在第一個分片,大於5000000儲存在第二個分片,這裡我們還使用這個演算法。

當然也可以使用其他演算法,例如 取模,大家可參見ShardingSphere的官網文件自行配置。

  # 配置 user 表規則
spring.shardingsphere.rules.sharding.tables.user.actual-data-nodes=ds$->{[0,1]}.user

  # 配置分庫策略
spring.shardingsphere.rules.sharding.tables.user.database-strategy.standard.sharding-column=id
spring.shardingsphere.rules.sharding.tables.user.database-strategy.standard.sharding-algorithm-name=database-inline

  # 配置分表策略
spring.shardingsphere.rules.sharding.tables.user.table-strategy.standard.sharding-column=id
spring.shardingsphere.rules.sharding.tables.user.table-strategy.standard.sharding-algorithm-name=table-inline

spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.props.algorithm-expression=ds$->{(id <= 5000000)?0:1}
spring.shardingsphere.rules.sharding.sharding-algorithms.table-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.table-inline.props.algorithm-expression=user

 

3.7 JPA相關程式碼

User實體類:

@Entity
@Table(name="user")
@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @Id
    private Integer id;

    private String name;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

 

User資料訪問類:

public interface UserRepository extends JpaRepository<User, Integer> {
}

 

3.8 驗證

這裡使用JPA操作增、刪、改、查操作是沒有任何問題的,資料落庫的分片也正確。

 

3.9 不得不說的幾個坑

1)配置ShardingSphere-JDBC時,自定義的名稱不要包含下劃線,包含了會報錯, 本人當時是跟了半天的原始碼才解決。

正確的命名:database-inline、table-inline、database-balance

錯誤的命名:database_inline、table_inline、database_balance

 

2)使用JPA需要開啟懶載入,否則會報錯。

 

3)不支援主庫雙寫或多寫,需要用其他手段保證叢集的高可用。

 

4)官網文件寫的不是很詳細,很多細節需要自己摸索,例如 分片表示式 和 分片策略 的配置都沒有給出示例。相對來說MyCat的官網文件就詳細很多。

 

4. 綜述

今天聊了一下 使用ShardingSphere-JDBC完成Mysql的分庫分表和讀寫分離,希望可以對大家的工作有所幫助。

大家可以根據自己的喜好去選擇使用 MyCat 或是 ShardingSphere-JDBC。

歡迎幫忙點贊、評論、轉發、加關注 :)

關注追風人聊Java,每天更新Java乾貨。

 

5. 個人公眾號

追風人聊Java,歡迎大家關注

相關文章