雪花ID主键冲突

发布时间 2023-10-30 23:02:58作者: 雨涛航海家

前言

为了标识请求的唯一性,项目中往往采用雪花算法生成全局ID,但运行过程中偶现主键冲突情况,分析结果为雪花算法生成ID相同。

 

知识介绍与拓展

1、首先分析ID生成需要具备的特性:

唯一性 不管是单机还是分布式场景下,生成的ID必须全局唯一
时序性 生成的ID与时间戳相关联,有利于分析和回溯,了解ID的生成时间
递增性 ID一般作为数据库主键,保持递增趋势入库,能够提高B+树索引结构 节点插入性能
低延迟 生成ID延迟低,效率高
高QPS 能够兼容大量并发请求,保证以上特性

2、现有常用的全局唯一ID方法包括:

算法   优点   缺点
UUID   生成效率高,能够保证全局唯一   ID无序,且与时间戳无关,入库性能差
MySQL自增主键   ID递增,全局唯一   不适用于分布式场景,效率低,加表锁(锁不是在每次事务完成后释放,而是在完成对自增长值插入的SQL语句后释放,要等待其释放才能进行后续操作。)
雪花算法   与时间戳有关,递增生成   存在ID相同的情况;依赖机器时钟,

 

问题分析

项目初始化雪花算法时,workId和dataId相同,因此同一时间戳可能会产生相同的ID;

 

解决方法

暂只讨论同一个微服务,从服务之间、服务之内两个角度提出解决方案(服务容器化部署):

  1. 不同pod使用不同的workId和dataId,初始化雪花算法;
  2. 相同pod获取雪花ID的静态方法增加单机锁(synchronized)

雪花算法ID重复的分析与在项目中的解决_雪花算法 重复-CSDN博客

分布式id生成之雪花id_分布式雪花id-CSDN博客

 

不同pod之间如何获取不同的初始化信息?

  • 每个服务启动时,根据workId的特性,从0到31依次判断redis中是否存在该值,若无,则写入当前微服务信息,唯一标识一个workId;
  • 每个服务运行过程中,每隔一段时间,为自己所占有的workId续时,避免被其他服务占用;
  • 服务重启或挂掉时,workId自动过期,即可被新服务占用;

 

可优化点

synchronize加在静态方法上,锁粒度太大,可根据不同的业务场景细化锁粒度