面試官:小夥子,ShardingSphere去學一下吧

Java全能架構師發表於2020-11-07

一、ShardingSphere簡介

在資料庫設計時候考慮垂直分庫和垂直分表。隨著資料庫資料量增加,不要馬上考慮做水平切分,首先考慮快取處理,讀寫分離,使 用索引等等方式,如果這些方式不能根本解決問題了,再考慮做水平分庫和水平分表。

分庫分表導致的問題:

  • 跨節點連線查詢問題(分頁、排序)
  • 多資料來源管理問題

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

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

二、Sharding-JDBC

Sharding-JDBC 是輕量級的 java 框架,是增強版的 JDBC 驅動,簡化對分庫分表之後資料相關操作

面試官:小夥子,ShardingSphere學一下吧

 

新建專案並新增依賴:

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-parentartifactId>
    <version>2.2.1.RELEASEversion>
parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starterartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
    dependency>
    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>druid-spring-boot-starterartifactId>
        <version>1.1.20version>
    dependency>
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
    dependency>
    <dependency>
        <groupId>org.apache.shardingspheregroupId>
        <artifactId>sharding-jdbc-spring-boot-starterartifactId>
        <version>4.0.0-RC1version>
    dependency>
    <dependency>
        <groupId>com.baomidougroupId>
        <artifactId>mybatis-plus-boot-starterartifactId>
        <version>3.0.5version>
    dependency>
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
    dependency>
dependencies>

2.1 Sharding-JDBC實現水平分表

① 按照水平分表的方式,建立資料庫和資料庫表

水平分表規則:如果新增 cid是偶數把資料新增 course_1,如果是奇數新增到 course_2

面試官:小夥子,ShardingSphere學一下吧

 

CREATE TABLE `course_1`  (
  `cid` bigint(16) NOT NULL,
  `cname` varchar(255) ,
  `userId` bigint(16),
  `cstatus` varchar(16) ,
  PRIMARY KEY (`cid`)
)

② 編寫實體和 Mapper 類

@Data
public class Course {
    private Long cid;
    private String cname;
    private Long userId;
    private String cstatus;
}
@Repository
public interface CourseMapper extends BaseMapper<Course> {

}

③ 詳細配置檔案


spring:
  main:

    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:

      names: m1
      m1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.182.200:3306/course_db?serverTimezone=GMT%2B8
        username: root
        password: 1234
    sharding:
      tables:
        course:

          actual-data-nodes: m1.course_$->{1..2}

          key-generator:
            column: cid
            type: SNOWFLAKE

          table-strategy:
            inline:
              shardingcolumn: cid
              algorithm-expression: course_$->{cid%2+1}
    props:
      sql:
        show: true

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false

④ 測試

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingSphereTestApplication {

    @Autowired
    CourseMapper courseMapper;

    @Test
    public void addCourse() {
        for (int i = 1; i  10; i++) {
            Course course = new Course();
            course.setCname("java" + i);
            course.setUserId(100L);
            course.setCstatus("Normal" + i);
            courseMapper.insert(course);
        }
    }

    @Test
    public void queryCourse() {
        QueryWrapper<Course> wrapper = new QueryWrapper<>();
        wrapper.eq("cid",493001315358605313L);
        Course course = courseMapper.selectOne(wrapper);
        System.out.println(course);

    }
}

面試官:小夥子,ShardingSphere學一下吧

 

 

面試官:小夥子,ShardingSphere學一下吧

 

2.2 Sharding-JDBC實現水平分庫

① 需求分析

面試官:小夥子,ShardingSphere學一下吧

 

② 建立資料庫和表

③ 詳細配置檔案


spring:
  main:

    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:

      names: m1,m2
      m1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.182.200:3306/course_db_2?serverTimezone=GMT%2B8
        username: root
        password: 1234
      m2:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.182.200:3306/course_db_3?serverTimezone=GMT%2B8
        username: root
        password: 1234
    sharding:

      tables:
        course:

          actual-data-nodes: m$->{1..2}.course_$->{1..2}

          key-generator:
            column: cid
            type: SNOWFLAKE

          database-strategy:
            inline:
              sharding-column: userId
              algorithm-expression: m$->{userId%2+1}
          table-strategy:
            inline:
              sharding-column: cid
              algorithm-expression: course_$->{cid%2+1}
    props:
      sql:
        show: true

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false

④ 測試程式碼

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingSphereTestApplication {

    @Autowired
    CourseMapper courseMapper;

    @Test
    public void addCourse() {
        for (int i = 1; i  20; i++) {
            Course course = new Course();
            course.setCname("java" + i);
            int random = (int) (Math.random() * 10);
            course.setUserId(100L + random);
            course.setCstatus("Normal" + i);
            courseMapper.insert(course);
        }
    }

    @Test
    public void queryCourse() {
        QueryWrapper<Course> wrapper = new QueryWrapper<>();
        wrapper.eq("cid", 493001315358605313L);
        Course course = courseMapper.selectOne(wrapper);
        System.out.println(course);
    }
}

查詢實際對應的 SQL:

面試官:小夥子,ShardingSphere學一下吧

 

2.3 Sharding-JDBC操作公共表

公共表 :

  • 儲存固定資料的表,表資料很少發生變化,查詢時候經常進行關聯
  • 在每個資料庫中建立出相同結構公共表

① 思路分析

面試官:小夥子,ShardingSphere學一下吧

 

② 在對應資料庫建立公共表 t_udict,並建立對應實體和 Mapper``

CREATE TABLE `t_udict`  (
  `dict_id` bigint(16) NOT NULL,
  `ustatus` varchar(16) ,
  `uvalue` varchar(255),
  PRIMARY KEY (`dict_id`)
)

③ 詳細配置檔案


spring:
  main:

    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:

      names: m1,m2
      m1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.182.200:3306/course_db_2?serverTimezone=GMT%2B8
        username: root
        password: 1234
      m2:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.182.200:3306/course_db_3?serverTimezone=GMT%2B8
        username: root
        password: 1234
    sharding:

      tables:
        course:

          actual-data-nodes: m$->{1..2}.course_$->{1..2}

          key-generator:
            column: cid
            type: SNOWFLAKE

          database-strategy:
            inline:
              sharding-column: userId
              algorithm-expression: m$->{userId%2+1}
          table-strategy:
            inline:
              sharding-column: cid
              algorithm-expression: course_$->{cid%2+1}
        t_udict:
          key-generator:
            column: dict_id
            type: SNOWFLAKE
      broadcast-tables: t_udict

    props:
      sql:
        show: true

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false

④ 進行測試

經測試:資料插入時會在每個庫的每張表中插入,刪除時也會刪除所有資料。

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingSphereTestApplication {

    @Autowired
    UdictMapper udictMapper;

    @Test
    public void addUdict() {
        Udict udict = new Udict();
        udict.setUstatus("a");
        udict.setUvalue("已啟用");
        udictMapper.insert(udict);
    }

    @Test
    public void deleteUdict() {
        QueryWrapper<Udict> wrapper = new QueryWrapper<>();
        wrapper.eq("dict_id", 493080009351626753L);
        udictMapper.delete(wrapper);
    }
}

2.4 Sharding-JDBC實現讀寫分離

為了確保資料庫產品的穩定性,很多資料庫擁有雙機熱備功能。也就是,第一臺資料庫伺服器是對外提供增刪改業務的生產伺服器;第二臺資料庫伺服器主要進行讀的操作。

Sharding-JDBC通過 sql語句語義分析,實現讀寫分離過程,不會做資料同步,資料同步通常資料庫叢集間會自動同步。

詳細配置檔案:


spring:
  main:

    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:

      names: m0,s0
      m0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.182.200:3306/course_db?serverTimezone=GMT%2B8
        username: root
        password: 1234
      s0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.182.200:3307/course_db?serverTimezone=GMT%2B8
        username: root
        password: 1234

    masterslave:
      master-data-source-name: m0
      slave-data-source-names: s0
    props:
      sql:
        show: true

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false

經過測試:增刪改操作都是會通過 master資料庫,同時 master資料庫會同步資料給 slave資料庫;查操作都是通過 slave資料庫.

三、Sharding-Proxy

Sharding-Proxy定位為 透明化的資料庫代理端,提供封裝了資料庫二進位制協議的服務端版本,用於完成對異構語言的支援, 目前僅 MySQL和 PostgreSQL版本。

Sharding-Proxy是獨立應用,需要安裝服務,進行分庫分表或者讀寫分離配置,啟動使用。

面試官:小夥子,ShardingSphere學一下吧

 

今天就聊到這裡了,如果覺得本文對你有幫助,可以轉發關注支援一下

原文連結:https://my.oschina.net/u/4199331/blog/4705383?_from=gitee_search

如果覺得本文對你有幫助,可以點贊關注支援一下,也可以關注我公眾號,上面有更多技術乾貨文章以及相關資料共享,大家一起學習進步!

相關文章