当前位置: 首页 > article >正文

基于snowflake id 的 N 位唯一数字id 生成算法总结

文章目录

  • 背景
  • 方法一: 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;
   // 按位运算即可得sequence
   long sequence = snowflakeId & 0xFFFL;
   // 时间戳和序列号拼接结果
   long result = timestamp * 1000 + sequence;
   // 返回10位整数,位数不足则补0
   return 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;
    // 按位运算即可得sequence
    long sequence = snowflakeId & 0xFFFL;

    // 时间戳和序列号拼接结果
    long result = timestamp * 100000L + machine * 1000 + sequence;
    // 随机数
    Random rand = new Random();
    result += rand.nextInt(1000);

    // 返回10位整数,位数不足则补0
    return String.format("%010d", result % 10000000000L);
}

优点: 减小碰撞概率
缺点: snowflake各个位数组合方法可能对结果有影响.


http://www.kler.cn/a/415829.html

相关文章:

  • 【天地图】HTML页面实现车辆轨迹、起始点标记和轨迹打点的完整功能
  • 微软企业邮箱:安全可靠的企业级邮件服务!
  • 电机驱动MCU介绍
  • AD7606使用方法
  • 华为开源操作系统openEuler安装部署
  • 重学 Android 自定义 View 系列(八):星星评分控件(RatingBar)
  • 浅谈Java库之‌Guava
  • SQL进阶技巧:如何寻找同一批用户 | 断点分组应用【最新面试题】
  • 【机器学习chp8】统计学习理论
  • 【llamafactory】安装与环境配置
  • 使用 Python 删除视频的某一段并保留其他时间段
  • 技术模板纪要
  • 解决SpringBoot连接Websocket报:请求路径 404 No static resource websocket.
  • 如何在谷歌浏览器中使用开发者工具调试网页
  • 004 MATLAB数值微积分
  • [Java]微服务之分布式事务
  • Redis【1】- 如何阅读Redis 源码
  • 3.22决策树,离散值
  • SpringMVC-Day2
  • layui-vue第三方库表格列事件怎么写
  • 人工智能之数学基础:欧式距离及在人工智能领域中的应用
  • 【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(6)
  • 牛客 ZT13 小红的数字删除
  • go每日一题:mock打桩、defer、recovery、panic的调用顺序
  • 【Linux】进程控制-----进程等待wait与waitpid
  • 用Go语言重写Linux系统命令 -- ping