文章目录
- 背景
- 方法一: snowflake id 取余
- 方法二: 哈希映射
- 方法三: 时间戳和序号拼接
- 方法四: 结合时间戳,机器码以及序列号
背景
分布式场景下选择snowflake id 生成算法来生成id是常见的技术选型,然而默认情况下snowflake id 生成器生成的id长度为19位数字,有些场景下我们需要的是8位,9位等长度小于19的唯一数字id,这个时候就需要将原有的snowflake id 进行一定的处理才能得到满足要求的指定为数的唯一数字id.本文详细总结一下常用的处理方法以及其优缺点.
假设需要生成的唯一数字id长度为10位.
方法一: snowflake id 取余
public static String testGenId() {long snowflakeId= IdUtil.getSnowflake(1,1 ).nextId();// 10 位long res = snowflakeId % 10000000000L;return String.valueOf(res);
}
优点:简单粗暴
缺点:高并发场景下id容器碰撞
方法二: 哈希映射
本质上通过hash运算将长整数映射为短整数
@SneakyThrows
public static String testGenId() {long snowflakeId= IdUtil.getSnowflake(1,1 ).nextId();String snowflakeStr = String.valueOf(snowflakeId);// md5 hash 算法MessageDigest md5 = MessageDigest.getInstance("MD5");byte[] digest = md5.digest(snowflakeStr.getBytes(StandardCharsets.UTF_8));// 16进制整数转换为10进制整数字符串String hexString = new BigInteger(1, digest).toString(10);// 截取前10位作为结果return hexString.substring(0, 10);
}
优点:1. 更加随机且均匀分布的映射,减少碰撞. 2. 保持了 Snowflake ID 的唯一性和分布特性
缺点:1. 计算相对复杂,需要额外的哈希步骤. 2. 依赖哈希算法的特性,可能存在极小的碰撞概率.
方法三: 时间戳和序号拼接
本质结合snowflake id 中的时间戳和序号, 缩小为10位数.
回顾 snowflake id 组成:
首位为0
41位时间戳
10位机器码,高5位数据中心,低5位是工作节点id.
12位序列号
public static String testGenId() {long snowflakeId= IdUtil.getSnowflake(1,1 ).nextId();// 右移22位移出 机器码和序列号 按位运算即可得到时间戳long timestamp = (snowflakeId >> 22) & 0x1FFFFFFFFFFL;// 按位运算即可得sequencelong sequence = snowflakeId & 0xFFFL;// 时间戳和序列号拼接结果long result = timestamp * 1000 + sequence;// 返回10位整数,位数不足则补0return String.format("%010d", result % 10000000000L);
}
优点: 保证id唯一性和时间连续性
缺点: 丢失了snowflake机器码信息,只使用了时间戳和序列号
方法四: 结合时间戳,机器码以及序列号
public static String testGenId() {long snowflakeId= IdUtil.getSnowflake(1,1 ).nextId();// 右移22位移出 机器码和序列号 按位运算即可得到时间戳long timestamp = (snowflakeId >> 22) & 0x1FFFFFFFFFFL;// 机器码long machine = (snowflakeId >> 12) & 0xFFL;// 按位运算即可得sequencelong sequence = snowflakeId & 0xFFFL;// 时间戳和序列号拼接结果long result = timestamp * 100000L + machine * 1000 + sequence;// 随机数Random rand = new Random();result += rand.nextInt(1000);// 返回10位整数,位数不足则补0return String.format("%010d", result % 10000000000L);
}
优点: 减小碰撞概率
缺点: snowflake各个位数组合方法可能对结果有影响.