欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

分布式系统之全局唯一ID生成策略 (UUID,基于mysql的replace into基于redis生成全局唯一id,Twitter的分布式自增id雪花算法 )

程序员文章站 2022-03-08 17:54:52
...

通过在 生产生活中,分布式的系统以及大数据量的存储和读取都离不开 ID的 唯一性,例如订单号,快递单号,商品编号等等。通常我们都会采用 uuid ,mysql replace into ,

一、 UUID 

直接使用 java 代码 本地生成,没有网络消。 但是会存在以下的缺点:

1. 无序,无法预测他的生成顺序,不能生成递增有序的数字。

首先分布式id 一般都会作为主键,但是mysql官方推荐主键要尽量越短越好,uuid 每一个都很长,所以不是很推荐。

2. uuid 作为 主键,在特定的环境下会存在一些问题

比如做 DB主键的场景下,uuid 就非常不适用 mysql,官方有明确的建议主键要尽量越短越好,36个字符长度的uuid不符合要求。

3.索引,b+树索引的分裂

既然分布式id 是 主键,然后主键是包含索引的,然后 mysql 的 索引是通过b+树 来实现的,每一次新的uuid 的数据插入,为了查询的优化,都会对索引底层的b+树进行修改,因为 uuid 是无序的,所以每一次的uuid 数据的插入都会对主键底层的b+树进行很大的修改,这一点很不好,插入完全无序,不但会导致一些中间节点产生分裂,也会自创造出很多不饱和的节点,这样大大降低了数据库插入的性能。

二、mysql 的 replace into 生成唯一id

replcae into 首先尝试 插入数据列表中,如果发现表中已经有此行数据,(根据主键或者唯一索引进行判断)则先删除,后插入。

实现方式: 

 create  table  `t_test` (

    id  bigint(20)  unsigned  not null auto_increment  primary key,

    stub char(1) not null default '',

    unique key stub(stub)

);

select * from t_test;

replcae into  t_test (stub) values ('b') ;

select LAST_INSERT_ID();

这种方式生成的 id 很显然在高并发的场景 下仍然是不太合适作为分布式id 的,一秒内mysql 的性能达不到 10万。

会存在以下缺点:

1.系统水平扩展比较困难,比如定义好了步长和机器台数之后,如果要添加机器该怎么做? 假设现在只有一台机器,发号是1,2,3,4,5(步长是1),这个时候需要扩容机器一台,可以这样做: 把第二台机器的初始值设置的比第一台机器超过很多,貌似还好,现在想象一下,如果我们线上有100台机器,这个时候要 扩容该怎么做?简直是噩梦,所以系统水平扩展复杂难以实现。

2. 数据库压力还是很大,每次获取id 都得读写一次数据库,非常影响性能,不符合分布式id里面的低延迟和高qps的规则

 

三 、基于 redis生成 全局唯一id 的策略

因为redis是单线程的天生 保证原子性,可以使用原子操作incr 和 incrby 来实现。

在 redis 集群的情况下, 和 mysql 一样要设置 不同的 增长步长,同时key一定要设置有效期。可以使用redis 集群来获得更高的吞吐量,假如一个集群中有5台redis,可以初始化每台redis 的值分别为1,2,3,4,5,然后步长都是5.

 

以上 三个生成 全局唯一id 的方式均有优缺点。

四、 Twitter 的分布式自增id 算法snowflake  雪花算法

分布式系统之全局唯一ID生成策略 (UUID,基于mysql的replace into基于redis生成全局唯一id,Twitter的分布式自增id雪花算法 )

分布式系统之全局唯一ID生成策略 (UUID,基于mysql的replace into基于redis生成全局唯一id,Twitter的分布式自增id雪花算法 ) 分布式系统之全局唯一ID生成策略 (UUID,基于mysql的replace into基于redis生成全局唯一id,Twitter的分布式自增id雪花算法 )

分布式系统之全局唯一ID生成策略 (UUID,基于mysql的replace into基于redis生成全局唯一id,Twitter的分布式自增id雪花算法 ) 

分布式系统之全局唯一ID生成策略 (UUID,基于mysql的replace into基于redis生成全局唯一id,Twitter的分布式自增id雪花算法 )

 Snowflake 可以保证:

所有生成的id 按照时间趋势递增,整个分布式系统内不会产生重复id ,因为有 datacenterid 和 workerid来做区分。

项目地址 :https://github.com/twitter-archive/snowflake

hutool 工具包: https://www.hutool.cn/  , https://github.com/looly/hutool

spring boot 整合 雪花算法 

(1)pom 文件 添加依赖 

<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-captcha -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-captcha</artifactId>
    <version>5.3.3</version>
</dependency>

(2)

@Component
@Slf4j
public class IdGeneratorSnowflake{
   private  long  workerId = 0 ;
   private  long  datacenterId = 1; 
   private  Snowflake snowflake = IdUtil.createSnowflake(workerId,datacenterId);

   @PostConstruct
   public void init(){
      try{
        workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
        log.info("当前机器的workerId:{}",workerId);
      }catch(Exception e){
        e.printStackTrace();
        log.warn("当前机器的workerId获取失败",e);
        workerId = NetUtil.getLocalhostStr().hashCode();
      } 
   }

   public  synchronized long  snowflake(){
        return snowflake.nextId();
   }

   public  synchronized long  snowflake(long workerId,long datacenterId){
        Snowflake snowflake = IdUtil.createSnowflake(workerId,datacenterId);
        return snowflake.nextId();
   }

   public static void main(String[] args){
      System.out.println(new IdGeneratorSnowflake().snowflake());
   }
}

分布式系统之全局唯一ID生成策略 (UUID,基于mysql的replace into基于redis生成全局唯一id,Twitter的分布式自增id雪花算法 )

如果想 彻底解决 机器时钟回拨导致重复id 生成的问题,则可以参考 百度开源的分布式id 生成器 UidGenerator 和 美团点评的分布式id 生成系统 Leaf 。 

相关标签: 分布式ID