ShardingSphere-JDBC学习笔记

news2024/11/17 13:36:25

引言

开源产品的小故事

Sharding-JDBC是2015年开源的,早期的定位就是一个分布式数据库的中间件,而在它之前有一个MyCat的产品。MyCat也是从阿里开源出来的,作为分库分表的代名词火了很长一段时间,而MyCat早年的目标就是想进入apache(从命名也可以看出,希望像Tomcat一样),但是很可惜最后由于社区运营不是很成熟没有达成。但是现在它的这个愿望早就已经被ShardingSphere达成了,ShardingSphere现在就是apache的顶级开源项目。

ShardingSphere版本演进

从15年开始作为一个小的中间件,发展至今已成为了一个庞然大物。

当不使用分片键时,ShardingSphere是怎么执行的呢?

在之前4.x版本下,这种情况会拆分成多个SQL(每个真实表分片对应一个sql),查询多次。新版本下,会将每一个真实库里的语句通过UNION合并成一个大SQL,一起进行查询。

如果需要对一个真实库进行多个SQL查询,那么就需要通过多线程进行并发查询,这种情况下,如果要进行后续的结果归并,比如sum、max这样的结果归并,那就只能将所有的结果都合并到一个大内存,再进行归并。这种方式称为内存归并消耗内存,多线程

如果合并成了一个大的SQL,对一个真实库只要进行一次SQL查询,这样就可以通过一个线程进行查询。在进行结果归并时,就可以拿一条数据归并一次。这种方式称为流式归并极大的节约内存

另外,在使用in进行查询时,有可能计算出属于多个不同的分片。在4.x版本当中,如果出现了这种情况,由于ShardingSphere无法确定in算出来的分片有多少个,所以遇到这种情况,他就不再去计算in中所有的分片结果了,直接改为全路由分片。这样计算比较简单,但是查询的效率肯定不好。而在新版本下,能够准确的计算出分片

补充:ShardingSphere实现分库分表的核心概念

  1. 虚拟库: ShardingSphere的核心就是提供一个具备分库分表功能的虚拟库,他是一个ShardingSphereDatasource实例。应用程序只需要像操作单数据源一样访问这个ShardingSphereDatasource即可。

  2. 真实库: 实际保存数据的数据库。这些数据库都被包含在ShardingSphereDatasource实例当中,由ShardingSphere决定未来需要使用哪个真实库。

  3. 逻辑表: 应用程序直接操作的逻辑表。

  4. 真实表: 实际保存数据的表。这些真实表与逻辑表表名不需要一致,但是需要有相同的表结构,可以分布在不同的真实库中。应用可以维护一个逻辑表与真实表的对应关系,所有的真实表默认也会映射成为ShardingSphere的虚拟表。

  5. 分布式主键生成算法: 给逻辑表生成唯一主键。由于逻辑表的数据是分布在多个真实表当中的,所以单表的索引就无法保证逻辑表的ID唯一性。ShardingSphere集成了几种常见的基于单机生成的分布式主键生成器。比如SNOWFLAKE,COSID_SNOWFLAKE雪花算法可以生成单调递增的long类型的数字主键,还有UUID,NANOID可以生成字符串类型的主键。当然,ShardingSphere也支持应用自行扩展主键生成算法。比如基于Redis,Zookeeper等第三方服务,自行生成主键。

  6. 分片策略: 表示逻辑表要如何分配到真实库和真实表当中,分为分库策略和分表策略两个部分。分片策略由分片键和分片算法组成。分片键是进行数据水平拆分的关键字段。如果没有分片键,ShardingSphere将只能进行全路由,SQL执行的性能会非常差。分片算法则表示根据分片键如何寻找对应的真实库和真实表。简单的分片策略可以使用Groovy表达式直接配置,当然,ShardingSphere也支持自行扩展更为复杂的分片算法。

ShardingSphere-JDBC其他策略

广播表

广播表认为在所有的片里面是一致的,不会进行转发,即使配置了分片规则也不会生效

使用场景:在所有分片都需要的表,比如字典表,在所有库上数据保持一致

参考配置:

# 打印SQL,spring.shardingsphere.props.sql-show,不同版本的参数可能不同,中间是-
spring.shardingsphere.props.sql.show=true
spring.main.allow-bean-definition-overriding=true
spring.shardingsphere.datasource.names=m0,m1

spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=UTC
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=123666

spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb2?serverTimezone=UTC
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123666

spring.shardingsphere.sharding.tables.dict.key-generator.column=dictId
spring.shardingsphere.sharding.tables.dict.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.dict.key-generator.props.worker.id=1
spring.shardingsphere.sharding.tables.dict.actual-data-nodes=m$->{0..1}.dict_$->{1..2}

spring.shardingsphere.sharding.broadcast-tables=dict

测试代码:

@Test
public void dict()
{
    Dict dict = new Dict();
    dict.setDictkey("1");
    dict.setDictval("true");
    dictMapper.insert(dict);

    Dict dict2 = new Dict();
    dict2.setDictkey("2");
    dict2.setDictval("false");
    dictMapper.insert(dict2);
}

@TableName("dict")
public class Dict {
    private Long dictid;
    private String dictkey;
    private String dictval;

    @Override
    public String toString() {
        return "Dict{" +
                "dictId=" + dictid +
                ", dictkey='" + dictkey + '\'' +
                ", dictval='" + dictval + '\'' +
                '}';
    }

    public Long getDictid() {
        return dictid;
    }

    public void setDictid(Long dictid) {
        this.dictid = dictid;
    }

    public String getDictkey() {
        return dictkey;
    }

    public void setDictkey(String dictkey) {
        this.dictkey = dictkey;
    }

    public String getDictval() {
        return dictval;
    }

    public void setDictval(String dictval) {
        this.dictval = dictval;
    }
}

测试结果:两个库的Dict表都增加了两条数据

注意:这里插入的是dict表,而不是dict_1和dict_2

绑定表

参考配置:

spring.shardingsphere.props.sql.show=true

spring.shardingsphere.datasource.names=m0,m1

spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=UTC
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=123666

spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb2?serverTimezone=UTC
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123666

#以下是新增部分
spring.shardingsphere.sharding.tables.user.key-generator.column=userid
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.user.key-generator.props.worker.id=1

spring.shardingsphere.sharding.tables.user.actual-data-nodes=m$->{0..1}.user_$->{1..2}
spring.shardingsphere.sharding.tables.user_course_info.actual-data-nodes=m$->{0..1}.user_course_info_$->{1..2}

spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=userid
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{Math.abs(userid.hashCode()%4).intdiv(2) +1}

spring.shardingsphere.sharding.tables.user_course_info.table-strategy.inline.sharding-column=userid
spring.shardingsphere.sharding.tables.user_course_info.table-strategy.inline.algorithm-expression=user_course_info_$->{Math.abs(userid.hashCode()%4).intdiv(2) +1}

spring.shardingsphere.sharding.binding-tables[0]=user,user_course_info

绑定表有什么作用呢?

举例生产场景:订单表和订单详情表,这两张表分片键的值是相同的,也就是说在相同分片规则的情况下,关联的数据一定会被分配到同一个分片中,所以直接到指定分片查询就可以了。绑定表在生产上非常常用,当分片数量很多时,比如64分片,试想不使用绑定表的情况下要如何查询(64*64的笛卡尔积,业务上肯定不能接受)

主从模式

早期版本叫主从模式,后续版本叫读写分离,主从做的事情其实就是读写分离。

主从参考配置:

spring.shardingsphere.props.sql.show=true

spring.shardingsphere.datasource.names=m0,m1

spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=UTC
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=123666

spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb2?serverTimezone=UTC
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123666

#以下是添加的部分,预期效果对dict表操作,更新到m0库,查询从m1
spring.shardingsphere.sharding.master-slave-rules.gao.master-data-source-name=m0
spring.shardingsphere.sharding.master-slave-rules.gao.slave-data-source-names[0]=m1

spring.shardingsphere.sharding.tables.dict.actual-data-nodes=gao.dict
spring.shardingsphere.sharding.tables.dict.key-generator.column=dictid
spring.shardingsphere.sharding.tables.dict.key-generator.type=snowflake
spring.shardingsphere.sharding.tables.dict.key-generator.props.worker.id=1

数据加密

对指定的字段类进行加密,加密后的密文字段存在数据表的指定列中。在应用代码使用时仍然操作明文列,但是观察日志可以看出转发到真实表的sql会处理成加密列去做操作,这样就达到了我们想要的效果。

好处是,不需要应用代码中额外的加密操作,内置支持多种加密方式AES、MD5、SM3、RC4等

参跑配置:

spring.shardingsphere.props.sql.show=true
spring.main.allow-bean-definition-overriding=true
spring.shardingsphere.datasource.names=m0,m1

spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=UTC
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=123666

spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb2?serverTimezone=UTC
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123666


spring.shardingsphere.sharding.tables.user.actual-data-nodes=m0.user_$->{1..2}
spring.shardingsphere.sharding.tables.user.key-generator.column=userid
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE

spring.shardingsphere.sharding.encrypt-rule.encryptors.encryptor_aes.type=aes
spring.shardingsphere.sharding.encrypt-rule.encryptors.encryptor_aes.props.aes.key.value=123456
spring.shardingsphere.sharding.encrypt-rule.tables.user.columns.password.plainColumn=password
spring.shardingsphere.sharding.encrypt-rule.tables.user.columns.password.cipherColumn=password_cipher
#spring.shardingsphere.sharding.encrypt-rule.tables.user.columns.password.assistedQueryColumn=user_assisted
spring.shardingsphere.sharding.encrypt-rule.tables.user.columns.password.encryptor=encryptor_aes

影子库

主要是用在压测的场景,比如说你的业务开发完了,需要测试性能,这个时候最好的情况是压测环境和生产的环境是一样的,影子库就是和生产环境的库是一样的,但是数据不同。在操作生产环境的库时,ShardingSphere内部会转发到影子库去完成测试。但是要注意,既然是压测,对生产环境的性能肯定是有影响的

这里参考配置就不列举了,因为笔者也没测试过,感兴趣的参考官方文档测试效果

总结

学习时建议多关注各种策略的思想(结合虚拟库、真实表等核心概念理解记忆),而且学习ShardingSphere强烈推荐结合官方文档自己多多尝试。使用其实不难的,关键是要找对方法,网上文章千千万,版本也是千奇百怪,初学者看的配置越多可能越不理解,ShardingSphere每个大版本的配置项都有很多改进,所以笔者建议理解每种策略存在的意义,解决问题的思想才是更有价值的。

基本技能:至少要了解每种策略是干什么用的?适合哪些场景?如何参考官方文档配置落地?

高级功能:5.x版本提供的可插拔扩展点使用,比如分片算法策略扩展、路由策略扩展、转发到真实表前的扩展(加密脱敏等)、jdbc数据库扩展、甚至sql的解析规则扩展等(建议学习SPI的扩展方式,源码中大量使用)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1363429.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云计算:OpenStack 分布式架构管理VXLAN网络(单控制节点与多计算节点)

目录 一、实验 1.环境 2.各节点新增网卡准备VXLAN网络 3.控制节点配置私有网络 4.计算节点1配置私有网络 5.计算节点2配置私有网络 6.重启服务 7.修改Dashboard 8.新建项目(租户)及用户 9.新建网络与子网 10.新建实例 11.新建路由 12.新增浮…

使用PyTorch实现去噪扩散模型

在深入研究去噪扩散概率模型(DDPM)如何工作的细节之前,让我们先看看生成式人工智能的一些发展,也就是DDPM的一些基础研究。 VAE VAE 采用了编码器、概率潜在空间和解码器。在训练过程中,编码器预测每个图像的均值和方差。然后从高斯分布中对…

用友NC word.docx 任意文件读取漏洞复现

0x01 产品简介 用友NC是一款企业级ERP软件。作为一种信息化管理工具,用友NC提供了一系列业务管理模块,包括财务会计、采购管理、销售管理、物料管理、生产计划和人力资源管理等,帮助企业实现数字化转型和高效管理。 0x02 漏洞概述 用友NC 系统word.docx等接口存在任意文件…

Java调用shell脚本实现数据库备份功能

本篇文章主要介绍怎样使用Java程序,执行服务器上的数据库备份Shell脚本进行MySQL数据库的备份功能。 学习目标 使用Java执行Shell脚本、实现MySQL数据库的备份功能。 学习内容 编写导出MysSQL数据库的Shell脚本 以下是一个使用Bash脚本进行数据库备份的示例代码…

每天刷两道题——第七天+第八天

力扣官网 1.1移动零 给定一个数组 n u m s nums nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序,在不复制数组的情况下原地对数组进行操作。 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 代码 def moveZeroea…

分布式锁3: zk实现分布式锁4 使用临时顺序节点+watch监听+可重入(threadLocal)

一 zk实现分布式锁的可重入性 1.1 使用ThreadLocal属性 引入ThreadLocal线程局部变量保证zk分布式锁的可重入性。 1.2 关键代码说明 1.3 代码 1.3.1 初始化客户端 1.3.2 分布式锁代码 package com.atguigu.distributed.lock.config;import com.baomidou.mybatisplus.core…

Docker学习与应用(六)-Docker网络

1、Docker网络 Docker有多种网络模式可以选择,可以根据应用场景和需求选择合适的网络模式。 桥接模式(Bridge Mode):默认情况下,Docker使用桥接模式创建一个虚拟网络,所有容器会连接到这个虚拟网络中。每个…

PPT模板(100套IT科技互联网风)

哈喽,小伙伴们,最近是不是都在准备年终总结、年终述职,一个好的PPT模板是编写报告的开端。我最近也在准备年终总结报告,一块整理了一些PPT模板。这些模板适用于各种IT科技互联网相关的场合,如产品发布会、项目提案、工…

TypeScript基础(一)基本类型与类型运算

✨ 专栏介绍 TypeScript是一种由微软开发的开源编程语言,它是JavaScript的超集,意味着任何有效的JavaScript代码都是有效的TypeScript代码。TypeScript通过添加静态类型和其他特性来增强JavaScript,使其更适合大型项目和团队开发。 在TypeS…

C#,入门教程(11)——枚举(Enum)的基础知识和高级应用

上一篇: C#,入门教程(10)——常量、变量与命名规则的基础知识https://blog.csdn.net/beijinghorn/article/details/123913570 不会枚举,就不会编程! 枚举 一个有组织的常量系列 比如:一个星期每一天的名字&#xf…

【SpringCloud】之入门级及nacos的集成使用

🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是君易--鑨,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的博客专栏《SpringCloud开发之入门级及nacos》。&#x1f3…

k8s 陈述式资源管理

k8s 陈述式资源管理 命令行:kubectl命令行工具 优点:90%以上的场景都可以满足 对资源的增,删,查比较方便,对改不是很友好 缺点: 命令比较冗长,复杂难记 声明式: k8s当中的yaml…

SpringCloud-高级篇(十二)

在主从集群中slave节点发生了宕机,不用担心,只要它重启就能从master节点上完成数据的同步,恢复数据,如果宕机的不是slave而是master,是不是master重启就可以呢?如果你做了master节点的数据持久化&#xff0…

SolidUI Gitee GVP

感谢Gitee,我是一个典型“吃软不吃硬”的人。奖励可以促使我进步,而批评往往不会得到我的重视。 我对开源有自己独特的视角,我只参与那些在我看来高于自身认知水平的项目。 这么多年来,我就像走台阶一样,一步一步参与…

MySQL第四战:视图以及常见面试题(上)

目录 目录: 一.视图 1.介绍什么是视图 2.视图的语法 语法讲解 实例操作 二.MySQL面试题 1.SQL脚本 2.面试题实战 三.思维导图 目录: 随着数字化时代的飞速发展,数据库技术,特别是MySQL,已经成为IT领域中不可…

自动驾驶:低阶可部署的单目测距算法-基于YOLO与透视变换

一、开发环境 部署平台:英伟达的Jetson Nano 环境:Linux ROS 语言:C 设备:1920*1080像素的摄像头、开发板。 模型:yolo-v8s 二、单目测距实现思路 0、标定相机和车辆(假设已经标定完成) 1、通…

配置cendos 安装docker 配置阿里云国内加速

由于我安装的cendos是镜像版。已经被配置好了。所以只需要更新相关配置信息即可。 输入 yum update自动更新所有配置 更新完成后输入 yum list docker-ce --showduplicates | sort -r 自动查询所有可用的docker版本 输入 yum install docker-ce docker-ce-cli container…

【Nginx】#安装配置及应用场景使用说明

文章目录 常见公网DNS服务1.Nginx的安装版本区别解压文件1.1编译安装1.2 启动安装1.3 安装成系统服务 2.运行原理3.Nginx配置及应用场景3.1最小配置worker_processesworker_connectionsinclude mime.types;default_type application/octet-stream;sendfifile on;keepalive_time…

k8s实践(14)--scheduler调度器和pod调度策略

一、scheduler调度器 1、kube-scheduler简介 k8s实践(10) -- Kubernetes集群运行原理详解 介绍过kube-scheduler。 kube-scheduler是运行在master节点上,其主要作用是负责资源的调度(Pod调度),通过API Server的Watch接口监听新建…

vue3按钮点击频率控制

现有一个按钮&#xff0c;如下图 点击时 再次点击 刷新窗口再次点击 刷新窗口依然可以实现点击频率控制。 代码实现&#xff1a; <template><!--<el-config-provider :locale"locale"><router-view/></el-config-provider>--><el…