分布式系统中生成8位唯一alphanumeric字符串的方案咨询
分布式场景下8位唯一字母数字字符串生成方案
8位字母数字字符串若采用大小写不敏感的36进制编码,总容量为36^8≈2.8万亿,完全满足绝大多数业务的条码使用需求,以下是三种经过生产验证的标准实现方案:
方案1:全局号段预分配(性能最优、零冲突)
这是工业界最常用的分布式发号方案,核心逻辑如下:
- 用中心化存储(MySQL/Redis均可)维护一个全局自增的数值序列,设置预分配步长(建议100~10000,根据实例数量调整)
- 每个应用实例启动时,向中心化存储原子申请独占号段,比如实例A申请到区间
[1000,2000),中心化存储同步将当前序列起始值更新为2000,避免号段冲突 - 实例在本地将号段内的十进制数值转换为36进制字符串,不足8位时在头部补0即可直接作为条码使用
- 本地号段耗尽后,再向中心化存储申请下一个号段即可
- 优势:
- 完全避免重复问题,号段全局唯一分配,多实例部署、应用重启都不会出现冲突
- 性能极高,仅号段耗尽时需要访问一次中心化存储,日常生成本地运算无额外开销
- 无需事后校验唯一键,无重试性能损耗
- 本地转换代码示例(Java):
// 大小写不敏感36进制字符表,如需大小写敏感可替换为62进制字符表 private static final String BASE_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final int CODE_LENGTH = 8; public static String generateCode(long num) { StringBuilder sb = new StringBuilder(); while (num > 0) { sb.append(BASE_CHARS.charAt((int) (num % BASE_CHARS.length()))); num /= BASE_CHARS.length(); } // 不足8位补前置0 while (sb.length() < CODE_LENGTH) { sb.append('0'); } return sb.reverse().toString(); }
方案2:实例标识+本地序列(无中心、低改造成本)
适合实例数量可控、单实例生成QPS不高的场景:
- 提前为每个应用实例分配全局唯一的实例ID,实例ID取值范围控制在
0~35(对应36进制1位) - 实例本地维护自增序列,生成规则为:实例ID(1位36进制) + 本地自增数值转36进制(补0到7位),拼接为8位字符串
- 本地序列可以持久化到实例本地磁盘,每次重启后读取上一次的最大值继续自增,避免重启重复
- 优势:无需中心化发号服务,改造成本低,性能同样接近本地运算
方案3:缓存前置校验唯一键(最小改造成本、适合低流量场景)
如果业务流量不大,不想改动现有随机生成逻辑,可以对原有唯一键方案做优化:
- 本地维护一个LRU缓存,存储最近生成的100万条条码,随机生成条码后先查缓存,命中则直接重新生成
- 缓存未命中时再写入带唯一键约束的数据库,此时唯一键冲突概率可以降低到0.1%以下,几乎不会产生重试开销
内容的提问来源于stack exchange,提问作者SBhogal
相关产品推荐
相关产品推荐

