14-ShardingSphere的分布式主键实现

news/2025/3/17 22:43:18/文章来源:https://www.cnblogs.com/JavaEdge/p/18232819

1 ShardingSphere自动生成键

MySQL自增键、Oracle自增序列等。分片场景下问题就复杂了,不能依靠单实例上的自增键来实现不同数据节点之间的全局唯一主键,分布式主键的需求应运而生。ShardingSphere 作为一款优秀分库分表开源软件,同样提供分布式主键实现机制。

1.1 GeneratedKey

使用 ShardingSphere 提供的自动生成键方案时,开发过程及效果和上面描述完全一致。

ShardingSphere实现了 GeneratedKey 类:

先从 ShardingRule 找主键对应 Column是否已包含:

  • 是,则找到该主键
  • 不是,则生成新主键

分布式主键的生成看:

image-20240605101514365

GeneratedKey#generatedValues变量保存生成的主键,但生成主键的工作转移到 ShardingRule#generateKey,跳转过去:

根据logicTableName找TableRule,再找其包含的 ShardingKeyGenerator,再通过 ShardingKeyGenerator#generateKey 生成主键。

设计模式分析

ShardingRule只是个外观类,真正创建 ShardingKeyGenerator 的过程在 TableRule。而这里的 ShardingKeyGenerator 显然就是真正生成分布式主键入口。

1.2 ShardingKeyGenerator

public interface ShardingKeyGenerator extends TypeBasedSPI {/*** Generate key.* * @return generated key*/Comparable<?> generateKey();
}

TableRule一个构造器找到 ShardingKeyGenerator 创建:

ShardingKeyGeneratorServiceLoader类定义:

// 继承了 TypeBasedSPIServiceLoader
public final class ShardingKeyGeneratorServiceLoader extends TypeBasedSPIServiceLoader<ShardingKeyGenerator> {static {// 注册类路径中所有的 ShardingKeyGeneratorNewInstanceServiceLoader.register(ShardingKeyGenerator.class);}public ShardingKeyGeneratorServiceLoader() {super(ShardingKeyGenerator.class);}
}

执行完后,ShardingKeyGeneratorServiceLoader#newService基于类型参数通过 SPI 创建实例,并赋值 Properties 属性:

继承 TypeBasedSPIServiceLoader 创建一个新的 ServiceLoader 类,然后在其静态方法注册相应 SPI 实现,这是 ShardingSphere 应用微内核模式常见做法。

sharding-core-common 工程的 META-INF/services 目录看到具体 SPI 定义:

2 ShardingSphere分布式主键实现

ShardingKeyGenerator 接口存在一批实现类。除前面:

  • SnowflakeShardingKeyGenerator
  • UUIDShardingKeyGenerator

还实现了:

  • LeafSegmentKeyGenerator
  • LeafSnowflakeKeyGenerator

2.1 UUIDShardingKeyGenerator

最简单的ShardingKeyGenerator:

2.2 SnowflakeShardingKeyGenerator

ShardingSphere最大容忍的时钟回拨毫秒数的默认0,可通过max.tolerate.time.difference.milliseconds设置。

常量定义,维护 SnowFlake 算法中各个 bit 之间的关系

generateKey 负责生成具体ID:

综合考虑时钟回拨、同一ms内请求,才完成 SnowFlake 算法具体实现。

2.3 LeafSegmentKeyGenerator 和 LeafSnowflakeKeyGenerator

实现类似SnowflakeShardingKeyGenerator的ShardingKeyGenerator困难,也属重复造轮子。因此,尽管 ShardingSphere 4.x提供了完整实现:

但5.x移除。目前,ShardingSphere 专门提供 OpenSharding 库存放新版的 LeafSegmentKeyGenerator 和 LeafSnowflakeKeyGenerator。新版实现类直接采用第三方美团提供的 Leaf 开源实现。

Leaf 提供两种生成 ID 方式:

  • 号段(Segment)模式
  • Snowflake 模式

无论哪种,都要提供一个 leaf.properties 文件,并设置配置项。无论哪种,应用程序都要设置一个leaf.key:

# for keyGenerator key
leaf.key=sstest# for LeafSnowflake
leaf.zk.list=localhost:2181

如用号段模式,需依赖一张数据库表存储运行时数据,因此要在 leaf.properties 文件中添加数据库配置:

# for LeafSegment
leaf.jdbc.url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useSSL=false
leaf.jdbc.username=root
leaf.jdbc.password=123456

即可创建对应DataSource,并进一步创建用于生成分布式 ID 的 IDGen 实现类。

LeafSegmentKeyGenerator

基于号段模式的 SegmentIDGenImpl 实现类:

//通过DruidDataSource构建数据源并设置属性
DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(properties.getProperty(LeafPropertiesConstant.LEAF_JDBC_URL));dataSource.setUsername(properties.getProperty(LeafPropertiesConstant.LEAF_JDBC_USERNAME));dataSource.setPassword(properties.getProperty(LeafPropertiesConstant.LEAF_JDBC_PASSWORD));
dataSource.init();//构建数据库访问Dao组件
IDAllocDao dao = new IDAllocDaoImpl(dataSource);
//创建IDGen实现类
this.idGen = new SegmentIDGenImpl();
//将Dao组件绑定到IDGen实现类
((SegmentIDGenImpl) this.idGen).setDao(dao);
this.idGen.init();
this.dataSource = dataSource;

创建IDGen实现类,即可通过该类生成目标 ID,LeafSegmentKeyGenerator 类中包含所有的实现细节:

Result result = this.idGen.get(properties.getProperty(LeafPropertiesConstant.LEAF_KEY));
return result.getId();

LeafSnowflakeKeyGenerator

LeafSnowflakeKeyGenerator实现依赖于分布式协调框架 Zookeeper,所以在配置文件中需要指定 Zookeeper 的目标地址:

# for LeafSnowflake
leaf.zk.list=localhost:2181

创建用于 LeafSnowflake 的 IDGen 实现类 SnowflakeIDGenImpl 相对比较简单,直接在构造器设置 zk 地址即可:

IDGen idGen = new SnowflakeIDGenImpl(properties.getProperty(LeafPropertiesConstant.LEAF_ZK_LIST), 8089);

通过 IDGen 获取模板 ID 的方式一致:

idGen.get(properties.getProperty(LeafPropertiesConstant.LEAF_KEY)).getId();

基于 Leaf 框架实现号段模式和 Snowflake 模式下的分布式 ID 生成方式非常简单,Leaf 框架为我们屏蔽了内部实现复杂性。

3 总结

ShardingSphere的分布式主键设计非常独立,本文各种分布式主键实现完全可直接套用到日常开发。

无论ShardingSphere自身实现的SnowflakeShardingKeyGenerator,还是基于第三方框架实现的 LeafSegmentKeyGenerator 和 LeafSnowflakeKeyGenerator,都为我们使用分布式主键提供直接解决方案。

参考:

  • 分布式主键

关注我,紧跟本系列专栏文章,咱们下篇再续!

作者简介:魔都技术专家,多家大厂后端一线研发经验,在分布式系统、和大数据平台设计等方面有多年研究和实践经验,拥有从0到1的大数据平台和基础架构研发经验,对分布式存储、数据平台架构、数据仓库等领域都有丰富实践经验。

各大技术社区头部专家博主。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。

负责:

  • 中央/分销预订系统性能优化
  • 活动&优惠券等营销中台建设
  • 交易平台及数据中台等架构和开发设计
  • 车联网核心平台-物联网连接平台、大数据平台架构设计及优化

目前主攻降低软件复杂性设计、构建高可用系统方向。

参考:

  • 编程严选网

本文由博客一文多发平台 OpenWrite 发布!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mesh快连

Mesh快连一、名词解释 Mesh快连是一种由多个节点组成的网络系统,这些节点可以相互连接,形成一个“网状”的结构。二、如何使用有线Mesh: 网络拓扑:设备版本:3.7.12企业版。 配置要求:从设备需恢复默认配置。 拓扑说明:设备接入电源,Q6000作为主设备通过LAN口连接从设备…

【Unity】Vector3的方法

属性和方法 作用normalized 使用Vector3.normalized的一个常见场景是在物理模拟中,比如计算速度向量或在射线投射(Raycasting)中确定射线的方向。Lerp Vector3.Lerp在Unity中非常常用,尤其是在动画和游戏逻辑中,用于平滑地过渡从一个状态到另一个状态,例如角色移动、颜色…

perfers-color-scheme 使用简单介绍

perfers-color-scheme 简介 prefers-color-scheme 媒体查询属性用于检测用户操作系统是否使用深色模式。 属性值dark 表示用户操作系统使用深色模式 light 表示用户操作系统使用浅色模式 no-preference 表示用户操作系统没有偏好,或者操作系统不支持该属性示例 @media (prefer…

正则表达式学习(1)——模式

正则表达式用于处理字符和字符串,是一种强大的工具 1. 正则表达式的模式字面值字符:例如字母、数字、空格等,可以直接匹配它们自身。特殊字符:例如点号 .、星号 *、加号 +、问号 ? 等,它们具有特殊的含义和功能。字符类:用方括号 [ ] 包围的字符集合,用于匹配方括号内的…

修改软链接实现提权

在做 vulnhub bottleneck 靶机过程中,看到一个修改软链接实现提权或越权的小技巧,固记录一下 提权成功后,是 www-data 的权限,运行 sudo -l 发现系统中存在clear_logs ,可以让bytevsbyte 免密运行 尝试先把权限提升至 bytevsbyte 再考虑 提root查看 clear_logs 文件属性看…

Python数据类型转换(新)

目录Python数据类型的转换隐式类型转换显式类型转换 Python数据类型的转换 数据类型分为1.隐式类型转换 2.显式类型转换 隐式类型转换在隐式类型转换中,Python会自动将一种数据类型转换为另一种数据类型,不需要认为去干预比如在进行算术运算的时候,较低数据类型(整数)就会转换…

在modelsim中查找指定信号是否有特定值

先选中信号,然后在上方搜索框输入后按回车就可以搜索,搜索框右边分别为搜索上一个和搜索下一个。

Python2 input函数漏洞利用

在 Python2 中,input 函数相当于 eval(raw_input(prompt))如果输入的数据是一个恶意的表达式,存在任意代码执行的风险 实例演示字符串拼接命令执行__import__(os).system(cat /etc/passwd)靶场利用 在 vulnhub bottleneck 靶机中,遇到 input 漏洞利用的情况 # 核心代码forea…

Python3基本语法(新)

目录基本语法输出print()格式化输出标识符import关键字保留字(关键字)注释多行注释1、单引号()2、双引号(""")缩进空行同一行显示多条语句等待用户输入inputimport 与 from...import 基本语法 输出print() print() 是一个让计算机在屏幕上进行输出的指令.它…

Python数据类型(新)

目录数据类型类型查看同时多个变量赋值标准数据类型1.数字(Number)2.字符串3.bool(布尔类型)4.元组元组的运算+ 运算+=运算* 运算元组的删除5.列表(List)查找列表修改列表列表的切片列表是可以修改的列表的追加列表的插入列表的连接列表的删除列表的清空列表的复制6.字典查找字…

[Tools] 使用 Charles 对 Android 应用进行 HTTPS 数据抓包

抓包工具 Charleshttps://www.charlesproxy.com/操作步骤 1. 在电脑上安装 Charles 客户端并进行配置 1.1 设置 Proxy Setting1.2 设置 SSL Proxing Setting1.3 重启 Charles 客户端 2. 在手机上安装 Charles 证书 2.1 将手机与电脑连接到同一 WIFI 网络 2.2 设置手机 WIFI 为…

Tita的OKR:如何开好 OKR 季度回顾会议?

你刚刚度过了一个美好的季度, 你意识到有些人已经接受了OKR,有些人还没有。 有些人很沮丧,因为他们发现每周衡量他们的OKR很困难,其他人则提到,这对他们保持正轨有很大帮助。在这个季度,你学到了很多东西,感觉你取得了一些出色的进展。 但是,你如何确保下一季度的工作更…