IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Sharding-JDBC4.0分库分表实战 -> 正文阅读

[大数据]Sharding-JDBC4.0分库分表实战


一、分库分表的缘由

????随着数据量的增大,或者一些特殊业务需求,单表的性能已经不能满足系统的要求,虽然可以对代码,sql的查询做一些优化,或者做一些数据预热,热点数据捞到缓存中,但是不能从根本上解决单库单表的性能问题,这些都只能作为一些优化手段,此时就需要我们的分库分表,由原来的单库-单表演变为我们的多库-多表。

常见的拆表:

  • 垂直拆分 ??-将单表中不经常用到的字段,拆到一张附属表中,拆完后,俩张表结构不同
  • 水平拆分?? -将单表存放的数据,横切分出一半放到另外一张表中,俩表结构相同

如图:
在这里插入图片描述
????这只是对于表的拆分,不管垂直拆分还是水平拆分,都是可以在单库内进行的,但是单库或单台机器所提供的性能毕竟是有限的,所以一般在分表之上,又会进行一个分库,多台机器,多个库,每个库中多张表,这样就是整个机器集群在提供数据查询服务,性能大大提高。
?
????最终我们整个db服务就演变成这样:
在这里插入图片描述

????说完我们的db集群,再来看我们上图中的分片键路由规则,当我们做了分库分表之后,对于每一条数据的读写操作,我们应该去哪个库哪张表操作呢?数据的插入好说,我们可以随便插入某个库某张表,但是查询、删除、修改呢?总不能每个库每张表遍历,遍历完才能知道对应的数据在哪个库哪张表吧,这样我们分库分表的意义还何在,所以就有了分片键路由规则

分片键:

????举个列子:我们将表分片以后,当执行一条SQL时,通过对字段 order_id 取模的方式来决定,这条数据该在哪个数据库中的哪个表中执行,此时 order_id 字段就是表的分片健,不管是增删改查中哪种操作,都需要携带order_id,我们再通过我们的路由规则计算这条数据应该插入哪个库的哪张表,查询也就不再需要我们遍历所有的数据库,直接定位这条数据在哪个库哪张表,直接去查询,效率大大提升。

路由规则:

????路由规则又可以称之为分片算法,是通过对分片键计算,来得到这条SQL语句应该到哪个库表执行的算法,从执行 SQL 的角度来看,分库分表可以看作是一种路由机制,把 SQL 语句路由到我们期望的数据库或数据表中并获取数据,分片算法可以理解成一种路由规则。

二、分库分表实现

技术选型:

????市面上有很多不错的分库分表的技术框架,当然,当我们对分库分表的实现原理已经熟悉的情况下,也可以手写一个,自己实现分片算法,这里选了俩个市面上常用的开源框架进行对比:mycatshardingJdbc
mycat:

是一个需要单独部署的第三方组件,对项目代码没有入侵
客户端所有的 jdbc 请求都必须要先交给 mycat ,再由 mycat 转发到具本的真实服务器中
由于jdbc请求都需要经过mycat,经过mycat内部进行分片路由计算再转到mysql,所以有额外的性能消耗
支持事务

shardingJdbc:

作为一个组件,需要在项目中集成,项目开发成本增加
在项目中解析sql,路由到具体的mysql库-表,相比mycat,性能较高
有语言限制,目前只支持Java语言
4.0支持事务

这里我说下我为什么选用shardingJdbc,相比于mycat,shardingJdbc目前只支持Java,同时需要在项目代码中集成,但是他的性能较高,同时在代码中集成,能让我们的开发人员更加清楚分库分表的一个底层实现原理,而且不需要额外部署组件,也不需要担心像mycat宕机的风险,而且shardingJdbc4.0也支持事务,和seata整合也比较简单。

准备工作

1、准备一个springboot工程
2、准备好俩个数据库,每个库中5张订单表

在这里插入图片描述
在这里插入图片描述
3、导入shardingJdbc相关依赖

		//mybatis-plus和druid等的依赖,这里就不贴出了,读者自己整合
        <!-- sharding-sphere -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            //最好和此一样版本,4.1.1版本博主测试会报找不到数据源问题,需要重写配置文件
            <version>4.0.0-RC1</version>
        </dependency>

编写配置文件

先编写我们的配置文件,由于考虑到后续还要和nacos,seata整合。此处采用yml写法,后续从nacos上拉去配置文件:application.yml

server:
    port: 4010

spring:
    application:
        name: learn_shardingsphere
    main:
        allow-bean-definition-overriding: true
    shardingsphere:
        datasource:
            default:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: root
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://ip:3306/[默认库]?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
                username: root
            ds1:
                driver-class-name: com.mysql.cj.jdbc.Driver
                jdbc-url: jdbc:mysql://ip:3306/taobao1?serverTimezone=GMT%2B8&useSSL=false
                password: root
                type: com.zaxxer.hikari.HikariDataSource
                username: root
            ds2:
                driver-class-name: com.mysql.cj.jdbc.Driver
                jdbc-url: jdbc:mysql://ip:3306/taobao2?serverTimezone=GMT%2B8&useSSL=false
                password: root
                type: com.zaxxer.hikari.HikariDataSource
                username: root
            names: default,ds1,ds2
        #是否开启SQL显示,默认值: false
        props:
            sql:
                show: true
        sharding:
        	#默认数据源配置,当没有配置分片规则的表将使用此数据源
            default-data-source-name: default
            tables:
            	#逻辑表名
                order:
                	##由数据源名 + 表名组成,以小数点分隔
                    actual-data-nodes: ds1.order_$->{1..5},ds2.order_$->{6..9}
                    database-strategy:
                        standard:
                        	#库路由规则
                            precise-algorithm-class-name: org.example.config.PreciseDatabaseShardingAlgorithm
                            #分片键
                            sharding-column: id
                    table-strategy:
                        standard:
                        	#表路由规则
                            precise-algorithm-class-name: org.example.config.PreciseTableShardingAlgorithm
                            #分片键
                            sharding-column: id
logging:
    level:
        com:
            sharding:
                demo:
                    mapper: DEBUG
#mp配置                    
mybatis-plus:
    configuration:
        auto-mapping-behavior: full
        map-underscore-to-camel-case: true
    mapper-locations: classpath:/mapper/*Mapper.xml

库分片规则实现:
我们这里简单规定,取订单id的个位数,小于5则放在ds1库中,大于5放在ds2库中

public class PreciseDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {

    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Long> id) {
        
        // 分片键值
        long value = id.getValue();

        // 库后缀
        String number;
        String str = String.valueOf(value).substring(String.valueOf(value).length() - 1);

        if (Integer.parseInt(str) <= 5) {
            number = "1";
        } else {
            number = "2";
        }

        if (value <= 0) {
            throw new UnsupportedOperationException("preciseShardingValue is null");
        }

        for (String availableTargetName : collection) {
            if (availableTargetName.endsWith(number)) {
                return availableTargetName;
            }
        }
        throw new UnsupportedOperationException();
    }
}

表分片规则实现:
取订单id个位数,拼接表:order{订单id个位数}

public class PreciseTableShardingAlgorithm implements PreciseShardingAlgorithm<Long> {

    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Long> id) {
        // 分片键值
        long value = id.getValue();

        if (value <= 0) {
            throw new UnsupportedOperationException("preciseShardingValue is null");
        }

        // 表后缀
        String str = String.valueOf(value).substring(String.valueOf(value).length() - 1);

        for (String availableTargetName : collection) {
            if (availableTargetName.endsWith(str)) {
                return availableTargetName;
            }
        }
        throw new UnsupportedOperationException();

    }
}

这里再贴出OrderMpper.xml的写法:
实体类,service实现,文章中就不具体贴出了
这里在xml中订单表都是取的逻辑表:order

    <insert id="insert" parameterType="org.example.entity.Order">
        insert into order(id,name,count,description) values(#{id},#{name},#{count},#{description})
    </insert>

    <update id="update" parameterType="org.example.entity.Order">
        update order set
        name=#{name},
        count=#{count},
        description=#{count}
        where id = #{id}
    </update>

    <delete id="delete">
        delete from order where id = #{id}
    </delete>

    <select id="select" resultType="org.example.entity.Order" parameterType="org.example.entity.Order">
        select * from order where id = #{id}
    </select>
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:49:30  更:2022-04-18 17:51:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:57:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码