04.21 统一发号器与多节点配置
1. 背景
项目原来在多个模块中直接使用 IdUtil.getSnowflake(...)、IdUtil.getSnowflakeNextIdStr() 生成业务编号。
这种写法在单节点时通常可用,但存在几个问题:
- 发号逻辑分散在各业务模块,后续维护成本高
- 多节点部署时,节点号配置容易遗漏,存在重复编号风险
- 后续如果要切换发号实现,需要全项目逐处修改
因此项目已统一收口到公共层发号器。
2. 统一发号器入口
当前统一发号器代码位置:
joolun-common/joolun-common-core/src/main/java/com/joolun/cloud/common/core/util/BizIdUtils.javajoolun-common/joolun-common-core/src/main/java/com/joolun/cloud/common/core/config/BizIdProperties.java
提供的方法:
BizIdUtils.nextId():生成long类型 IDBizIdUtils.nextIdStr():生成字符串 IDBizIdUtils.nextPrefixedId(prefix):生成带业务前缀的编号
3. 使用规范
3.1 新增业务编号时的要求
禁止再直接写:
IdUtil.getSnowflake(0, 0).nextIdStr();
IdUtil.getSnowflake(1, 2).nextId();
IdUtil.getSnowflakeNextIdStr();
统一改为:
BizIdUtils.nextIdStr();
BizIdUtils.nextId();
BizIdUtils.nextPrefixedId("ORDER_");
3.2 推荐写法
普通业务单号:
orderInfo.setOrderNo(BizIdUtils.nextIdStr());
带前缀业务编码:
entity.setSkuCode(BizIdUtils.nextPrefixedId(SupplierConstants.GOODS_SKU_CODE_PREFIX));
租户等主键:
String tenantId = BizIdUtils.nextIdStr();
4. 配置项
统一发号器配置前缀:
joolun:
id:
worker-id: 0
datacenter-id: 0
默认配置已加入:
server/nacos-server/data/tenant-config-data/public/DEFAULT_GROUP/application-dev.yml
字段说明:
worker-id:Snowflake 工作节点编号,范围0-31datacenter-id:Snowflake 数据中心编号,范围0-31
如果超出范围,程序会直接启动失败,避免节点号误配后继续发号。
5. 多节点部署时怎么配
多节点部署时,每个节点必须配置不同的节点组合。
示例:
# 节点 1
joolun:
id:
worker-id: 1
datacenter-id: 1
# 节点 2
joolun:
id:
worker-id: 2
datacenter-id: 1
# 节点 3
joolun:
id:
worker-id: 3
datacenter-id: 1
建议原则:
- 同一套环境内不要出现重复的
worker-id + datacenter-id - 优先按“环境 / 机房 / 节点”提前规划编号
- 配置统一放到 Nacos,避免写死在本地文件
6. 当前已完成的改造
本次已将以下模块里的发号逻辑统一接入 BizIdUtils:
- mall
- supplier
- upms
包括:
- 订单号
- 对账单号
- 结算单号
- 结算项编号
- 供应商申请单号
- 供应商编码
- 租户 ID
7. 后续扩展建议
如果后续还要继续增强,可以按下面方向扩展:
- 在 wiki 或开发规范中明确“禁止直接使用
IdUtil.getSnowflake...” - 在代码扫描或 Sonar 规则中增加检测
- 如果未来有跨机房、跨地域独立编号需求,可在
BizIdUtils内统一替换为新的发号实现