一键开箱-id 生成器本地化生产 (附源码)

一.背景

1.1 背景

  • 业务背景:

目前梳理 SaaS 系统中存在以下几种 Id 生成的场景.

财务系统: 财务在生产财务单的时候,获取财务单 Id ,满足分布式场景下能够获取全局Id即可.

支付系统 :订单系统在进行外部提单过程中,需要将生成的订单号与外部的支付平台做对接.在具体开发调试过程中出现这种情况.客户需要支持私有化交付.我们在 SaaS 的开发环境部署联调时,已经与外部的支付平台进行了对接.完成联调结束后.在客户的私有化环境中再次进行测试回归出现了,出现了因为订单号重复导致了支付失败的场景.

商品系统: 商品系统在生产具体的Id形式上有几种业务侧的诉求.

场景 具体逻辑 示例
SPUId SPUId 生产支持固定位数(可配),起始值(可配)的自增流水Id 固定6位.起始值.100000.流水Id:100000,100001,100002等
类目Id 类目Id .支持固定前缀(可配).流水固定位数(可配)的流水自增 固定前缀Ca.流水固定位数(6),Ca000001,Ca000002
  • 技术背景:

现有 SaaS 的不同系统中存在不同的 Id 生产的逻辑和服务,大概可以分为两种方案.

  • 第一种:基于中心化的 Id 服务来获得.
  • 第二种:基于本地化的 Id 数据库来生产. 结合目前的 SaaS系统 会有私有化部署的场景,那就是需要去考虑部署成本的因素.且目前的中心化方案可能带来的单点故障问题.基于以上的一个背景

1.2 目标

  • 支持分布式全局
  • 支持私有化部署独立部署
  • 支持自定义规则 Id 生产
  • 性能目标:单机4c8g下 1000 qps 目标

二.技术方案

2.1 技术调研对比

常见方案 优势 对比目标后的缺点
UUID 使用简单,支持分布式场景,理论上存在碰撞可能(几率极低) 分布式支持;独立部署支持;不支持自定义规则;最重要的原因是利用UUID 作为分布式数据库业务Id 的场景下,由于B+树作为底层的数据结构会带来大量的页分裂和反复的插入以及翻转,并以此带来的大量性能损耗
雪花算法 支持分布式;性能优秀 依赖物理机时钟,时钟回拨回带来碰撞问题;不支持自定义规则;
Redis 支持分布式;性能优秀; 额外的Redis服务成本,不支持自定义规则
ZK 支持分布式; 额外的ZK服务成本;不支持自定义规则

2.2 结合现有业务的最终选择

抛开业务场景的下的技术方案设计都是刷流氓.基于目前咱们的技术目标.选用了一个基于数据库(不额外支出其他资源)的且支持自定义规则的设计方案.

markdown 复制代码
- 支持分布式全局
- 支持私有化部署独立部署
- 支持自定义规则 **Id** 生产
- 性能目标:单机4c8g下 1000 **qps** 目标

三.详细设计

3.1 方案流程

3.1.1 配置初始化

3.1.2 生产 Id 流程

3.2 类图

  • IdAutoBootConfig

  • spring.factories 入口方法

  • 能力1:用以保证引入的业务方能够自动扫描本身的包体,扫描对应的bean到spring container

  • 能力2:用以扫描对应的 mybatis mapper 注入动态代理

  • IdGenerator 用以外漏 id 的生产接口. 方法1:生成全局id generatorGlobalId(String name) tenantId =9527 方法2:生成租户级别全局唯一generatorGlobalId(long tenantId,String name);

  • IdGeneratorImpl 具体方法生成的实现类. 内部持有持有上下文中具体的Sequence name 与 SequenceValue 的映射的读写操作.

核心读写锁分离处理具体流程(方便理解可能与上图部分有重复).

  • InitSequenceConfigWare& SequenceStepContextHolder InitSequenceConfigWare 通过实现 InitializingBean扩展点 完成容器启动后(本质是利用容器启动完成,数据源完成注入)来实现数据库Sequence 读取得到 SequenceConfigModel .通过 SequenceStepContextHolder 维护 sequenceName 与 SequenceValue的映射关系.为了减少 内存占用.将SequenceConfigModel 简化一部分得到 SequenceValue 进而维护到 SequenceStepContextHolder 持有的 ALL_SEQUENCE_CONTEXT 中.

3.3 DB设计

code rule 表(非必选)本期没有实现后续可以持续在这个表进行扩展得到更加灵活的SequenceId表达.

sql 复制代码
CREATE TABLE `code_rule` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `tenant_id` bigint(20) NOT NULL COMMENT '租户id',
  `biz_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '业务:1-商品编码规则,2-类目编码规则,参见BizTypeEnum',
  `rule_key` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1-流水自增,2-租户自定义,3-类目编号和流水自增,参见RuleKeyEnum',
  `rule_value` varchar(256) NOT NULL COMMENT '编码规则描述json格式',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '数据中心抽数专用字段,无业务含义',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_tid_type` (`tenant_id`,`biz_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='编码规则表';

/**
* **sequence** 表。必选表。本期先实现需要业务方自行创建**ddl**维护到对应数据源中.
*/
CREATE TABLE `sequence` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '当前序列最大值',
  `tenant_id` bigint(20) NOT NULL COMMENT '租户id',
  `name` varchar(200) NOT NULL COMMENT '序列名称',
  `start` bigint(20) NOT NULL COMMENT '开始值',
  `end` bigint(20) NOT NULL COMMENT '结束值',
  `step_size` bigint(20) DEFAULT NULL COMMENT 'id号段数量',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='序列号表';

3.4 no more talking 一键开箱

详见:github github.com/Baixiu-code...

3.5 测试

本着面向TDD的原则,我也开放了多线程版本的自测演示.一键直达吧. github.com/Baixiu-code...

相关推荐
2401_854391081 分钟前
高效开发:SpringBoot网上租赁系统实现细节
java·spring boot·后端
Cikiss10 分钟前
微服务实战——SpringCache 整合 Redis
java·redis·后端·微服务
Cikiss11 分钟前
微服务实战——平台属性
java·数据库·后端·微服务
OEC小胖胖25 分钟前
Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)
java·spring boot·后端·spring·mybatis·web
2401_857617621 小时前
SpringBoot校园资料平台:开发与部署指南
java·spring boot·后端
计算机学姐1 小时前
基于SpringBoot+Vue的在线投票系统
java·vue.js·spring boot·后端·学习·intellij-idea·mybatis
Yvemil72 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
2401_854391082 小时前
Spring Boot大学生就业招聘系统的开发与部署
java·spring boot·后端
虽千万人 吾往矣2 小时前
golang gorm
开发语言·数据库·后端·tcp/ip·golang
这孩子叫逆3 小时前
Spring Boot项目的创建与使用
java·spring boot·后端