题目:集群高并发情况下如何保证分布式唯一全局id生成?


文章目录

  • 一、问题
  • 二、一般通用方案
  • 三、snowflake(雪花算法)
  • 四、其它补充


一、问题

1 问题
1.1 为什么需要分布式全局唯一id以及分布式id的业务需求

1、在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识
2、如在美团点评的金融、支付、餐饮、酒店;猫眼电影等产品的系统中数据日渐增长,对数据分库分表后需要有一个唯一id来标识一条数据或消息;
3、特别一点的如订单、骑手、优惠券也都需要有唯一id做标识;
4、此时一个能够生成全局唯一id的系统是非常必要的。

1.2 id生成规则部分硬性要求

1.全局唯一:不能出现重复的id号,既然是唯一标识,这是最基本的要求;
2.趋势递增:在MySQL的InnoDB引擎中使用的是聚集索引,由于多数RDBBMS使用Btree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能
3.单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求
4.信息安全:如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,需要ID无规则不规则,让竞争对手不好猜。
5.含时间戳:这样就能够在开发中快速了解这个分布式id的生成时间

1.3 ID号生成系统的可用性要求

1、高可用:发一个获取分布式ID的请求,服务器就要保证99.999%的情况下给我创建一个唯一分布式ID;
2、低延迟:发一个获取分布式ID的请求,服务器就要快,极速;
3、高QPS:假如并发一口气10万个创建分布式ID请求同时杀过来,服务器要顶得住且一下子成功创建10万个分布式ID;

二、一般通用方案

1、UUID

1.1 是什么

mysql 雪花id自生成 mysql雪花算法索引_算法


(如果只是考虑唯一性,OK)

1.2 But

mysql 雪花id自生成 mysql雪花算法索引_算法_02

2、数据库自增主键

2.1 单机

mysql 雪花id自生成 mysql雪花算法索引_算法_03

2.2 集群分布式

mysql 雪花id自生成 mysql雪花算法索引_spring cloud_04

3、基于Redis生成全局id策略

3.1 因为redis是单线的天生保证原子性,可以使用原子操作INCR和INCRBY来实现

3.2 集群分布式

mysql 雪花id自生成 mysql雪花算法索引_云原生_05

三种方案优缺点:
uuid:只有唯一性,趋势递增
mysql:唯一性,递增
redis:虽然五个算法思想满足,但是维护麻烦,如果整个系统不需要redis技术,但是为了生成id而使用redis来搭建,有点不划算(维护哨兵模式。。。)

三、snowflake(雪花算法)

Twitter的分布式自增ID算法snowflake

1、概述


2、结构

mysql 雪花id自生成 mysql雪花算法索引_算法_06


mysql 雪花id自生成 mysql雪花算法索引_算法_07


mysql 雪花id自生成 mysql雪花算法索引_算法_08

3、源码

github上有,是Scale语言写的,现在有人参考写出了java版本

4、工程落地经验
4.1 糊涂工具包

https://github.com/looly/hutool/

4.2 springboot整合雪花算法

4.2.1 pom

mysql 雪花id自生成 mysql雪花算法索引_spring cloud_09

4.2.2 核心代码IdGeneratorSnowflake

@Slf4j
@Component
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(“当前机器的worker获取失败”,e);
        workerId = NetUtil.getLocalhostStr().hastCode();
      } 
   }
   
   public synchronized long snowflakeId(){
     return snowflake.nextId();
   }

   public synchronized long snowflakeId(long workerId,long datacenterId){
      Snowflake snowflake = IdUtil.createSnowflake(workerId,datacenterId);
      return snowflake.nextId();
   }
  
   public static void main(String[] args){
      System.out.println(new IdGeneratorSnowflake().snowflakeId());
   }
}

5、优缺点

mysql 雪花id自生成 mysql雪花算法索引_Cloud_10

四、其它补充

ps:如果实在考虑到雪花算法的时钟回拨问题,业内有以下两种解决方案。

1、百度开源的分布式唯一Id生成器UidGenerator
2、Leaf – 美团点评分布式ID生成系统