使用shardingJDBC中的雪花算法生成id

常用ID解决方案

数据库自增id

  • 依靠数据库系统的功能实现,但是未来扩容麻烦
  • 主从切换时的不⼀致可能会导致重复发号
  • 性能瓶颈存在单台sql上

UUID

  • 性能非常高,没有网络消耗
  • 无序的字符串,不具备趋势自增特性
  • UUID太长,不易于存储,浪费存储空间,很多场景不适用

Redis发号器

利用Redis的INCR和INCRBY来实现,原子操作,线程安全,性能比Mysql强劲

需要占用网络资源,增加系统复杂度

Snowflake雪花算法

雪花算法(Snowflake)是twitter公司内部分布式项目采用的ID生成算法

ID在内存生成,不依赖于数据库,高性能高可用

每秒可生成几百万ID,容量大

由于ID呈趋势递增,插入数据库后,使用索引的时候性能较高

代码实现简单、不占用宽带、数据迁移不受影响
生成的 id 中包含有时间戳,所以生成的 id按照时间递增
部署了多台服务器,需要保证系统时间⼀样,机器编号不⼀样

依赖系统时钟(多台服务器时间⼀定要⼀样)

 Snowflake生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特

使用shardingJDBC中的雪花算法生成id_第1张图片

雪花算法的位数

  • 雪花算法生成的数字,long类,所以是:8个byte,64bit
  • 表示的值 -9223372036854775808(-2的63次方)~9223372036854775807(2的63次⽅-1)
  • 生成的唯⼀值⽤于数据库主键,不能是负数,所以值为0~9223372036854775807(2的63次方-1)
  • 第一个bit位代表符号位,正数是0,负数是1,ID为正数,所以固定为0
  • 毫秒级时间戳部分占41bit,不是存储当前时间的时间截,服务上线的时间毫秒级的时间戳(为当前时间-服务第一次上线时间)
  • 工作机器 id占10bit,可支持210 =1024个节点
  • 序列号部分占12bit,可允许同一毫秒生成212 =4096个Id,则理论上一秒就可生成4096*1000 = 400万个ld
  • 组合起来刚好是64位,Long类型
     

Snowflake必须注意的地方

分布式部署就需要分配不同的workId, 如果workId相同,可能会导致⽣成的id相同

分布式情况下,需要保证各个系统时间⼀致,如果服务器的时钟回拨,就会导致⽣成的 id 重复

Snowflake雪花算法实现

配置文件

#配置workId
spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1

 方式一:订单id使用MybatisPlus的配置,ProductOrder类配置

@TableId(value = "id", type = IdType.ASSIGN_ID)
默认实现类为DefaultIdentifierGenerator雪花算法

方式二:使用Sharding-Jdbc配置文件,注释DO类里面的id分配策略

#id⽣成策略
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE

 方式三 进阶:动态指定sharding jdbc 的雪花算法中的属性work.id属性

使用sharding-jdbc中的使用IP后几位来做workId,但在某些情况下会出现生成重复ID的情况
解决办法: 在启动时给每个服务分配不同的workId, 引⼊redis/zk都行,缺点就是多了依赖

配置文件完整

spring.application.name=xdclass-sharding-jdbc
server.port=8080


# 打印执行的数据库以及语句
spring.shardingsphere.props.sql.show=true

# 数据源 db0
spring.shardingsphere.datasource.names=ds0,ds1

# 第一个数据库
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://10.24.201.232:3306/xdclass_shop_order_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root


# 第二个数据库
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://10.24.201.232:3306/xdclass_shop_order_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=root

#配置workId
spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1



#id生成策略
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE

# 指定product_order表的数据分布情况,配置数据节点,行表达式标识符使用 ${...} 或 $->{...},
# 但前者与 Spring 本身的文件占位符冲突,所以在 Spring 环境中建议使用 $->{...}
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds0.product_order_$->{0..1}

# 指定product_order表的分片策略,分片策略包括【分片键和分片算法】
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{user_id % 2}

雪花算法测试结果

使用shardingJDBC中的雪花算法生成id_第2张图片

你可能感兴趣的:(mysql,shardingJDBC,数据库)