mysql分布式主键方案_分库分表的 9种分布式主键ID 生成方案,挺全乎的

来自公众号:程序员内点事

《sharding-jdbc 分库分表的 4种分片策略》 中我们介绍了 sharding-jdbc 4种分片策略的使用场景,可以满足基础的分片功能开发,这篇我们来看看分库分表后,应该如何为分片表生成全局唯一的主键 ID。

引入任何一种技术都是存在风险的,分库分表当然也不例外,除非库、表数据量持续增加,大到一定程度,以至于现有高可用架构已无法支撑,否则不建议大家做分库分表,因为做了数据分片后,你会发现自己踏上了一段踩坑之路,而分布式主键 ID 就是遇到的第一个坑。

不同数据节点间生成全局唯一主键是个棘手的问题,一张逻辑表 t_order 拆分成多个真实表 t_order_n,然后被分散到不同分片库 db_0、db_1... ,各真实表的自增键由于无法互相感知从而会产生重复主键,此时数据库本身的自增主键,就无法满足分库分表对主键全局唯一的要求。

db_0--

|-- t_order_0

|-- t_order_1

|-- t_order_2

db_1--

|-- t_order_0

|-- t_order_1

|-- t_order_2

尽管我们可以通过严格约束,各个分片表自增主键的 初始值 和 步长 的方式来解决 ID 重复的问题,但这样会让运维成本陡增,而且可扩展性极差,一旦要扩容分片表数量,原表数据变动比较大,所以这种方式不太可取。

步长 step = 分表张数

db_0--

|-- t_order_0  ID: 0、6、12、18...

|-- t_order_1  ID: 1、7、13、19...

|-- t_order_2  ID: 2、8、14、20...

db_1--

|-- t_order_0  ID: 3、9、15、21...

|-- t_order_1  ID: 4、10、16、22...

|-- t_order_2  ID: 5、11、17、23...

目前已经有了许多第三放解决方案可以完美解决这个问题,比如基于 UUID、SNOWFLAKE算法 、segment号段,使用特定算法生成不重复键,或者直接引用主键生成服务,像美团(Leaf)和 滴滴(TinyId)等。

而sharding-jdbc 内置了两种分布式主键生成方案,UUID、SNOWFLAKE,不仅如此它还抽离出分布式主键生成器的接口,以便于开发者实现自定义的主键生成器,后续我们会在自定义的生成器中接入 滴滴(TinyId)的主键生成服务。

前边介绍过在 sharding-jdbc 中要想为某个字段自动生成主键 ID,只需要在 application.properties 文件中做如下配置:

# 主键字段

spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id

# 主键ID 生成方案

spring.shardingsphere.sharding.tables.t_order.key-generator.type=UUID

# 工作机器 id

spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123

key-generator.column 表示主键字段,key-generator.type 为主键 ID 生成方案(内置或自定义的),key-generator.props.worker.id 为机器ID,在主键生成方案设为 SNOWFLAKE 时机器ID 会参与位运算。

在使用 sharding-jdbc 分布式主键时需要注意两点:

一旦 insert 插入操作的实体对象中主键字段已经赋值,那么即使配置了主键生成方案也会失效,最后SQL 执行的数据会以赋的值为准。

不要给主键字段设置自增属性,否则主键ID 会以默认的 SNOWFLAKE 方式生成。比如:用 mybatis plus 的 @TableId 注解给字段 order_id 设置了自增主键,那么此时配置哪种方案,总是按雪花算法生成。

下面我们从源码上分析下 sharding-jdbc 内置主键生成方案 UUID、SNOWFLAKE 是怎么实现的。

UUID

打开 UUID 类型的主键生成实现类 UUIDShardingKeyGenerator 的源码发现,它的生成规则只有 UUID.randomUUID() 这么一行代码,额~ 心中默默来了一句卧槽。

UUID 虽然可以做到全局唯一性,但还是不推荐使用它作为主键,因为我们的实际业务中不管是 user_id 还是 order_id 主键多为整型,而 UUID 生成的是个 32 位的字符串。

它的存储以及查询对 MySQL 的性能消耗较大,而且 MySQL 官方也明确建议,主键要尽量越短越好,作为数据库主键 UUID 的无序性还会导致数据位置频繁变动,严重影响性能。

public final class UUIDShardingKeyGenerator implements ShardingKeyGenerator {

private Properties properties = new Properties();

public UUIDShardingKeyGenerator() {

}

public String getType() {

return "UUID";

}

public synchronized Comparable> generateKey() {

return UUID.randomUUID().toString().replaceAll("-", "");

}

public Properties getProperties() {

return this.properties;

}

public void setProperties(Properties properties) {

this.properties &#

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值