一、合理的全局唯一Id的一些要求
1. 全局唯一
2. 趋势递增
- MySQL中的InnerDB存储引擎使用的是聚簇索引,多数使用Btree的数据结构来存储索引,在主键的选择上,我们尽可能选择有序的唯一id
3. 单调递增
- 保证下一个id一定大于上一个id,例如事务版本号,排序等场景
4. 信息安全
- 如果id连续的,恶意用户的爬取工作就会很容易做到,在一些应用场景下需要id无规则不规则
5. 含时间戳
二、分布式全局唯一Id还需要哪些要求
- 高可用:获取分布式的唯一id,服务器要保证99.999%的情况下可以生成唯一id
- 低延时:获取一个唯一id请求,要快速生成,极快
- 高QPS:在并发场景下,服务器可以同时创建上万个唯一id
三、常见的几种生成唯一Id方式
1. 通过java.util.UUID生成
System.out.println(UUID.randomUUID());
- 只需使用replace替换掉符号,即可使用,性能非常高,没有网络消耗
- 但是,UUID生成的id为字符串,字符串作为Id占用空间大,并且由于无序,索引效率比整型低,入数据库性能差,MySQL建议使用较短的主键id,不推荐使用
2. 通过MySQL的auto-increment自增字段和replace into实现
- 从1开始,基本可以做到连续递增,只能保证每个表唯一
- 但是,不能保证全局唯一,无法保证信息安全,分布式系统不合适使用
3. 基于Redis生成全局id策略
- 利用redis的原子性,通过Incr,设置步长基本可以满足
- 但是,复杂性太高,需要严重依赖第三方服务,而且代码配置繁琐,需要引入Redis集群
4. 雪花算法
- SnowFlake可以按照时间有序生成
- SnowFlake生成的id结果为64bit的整数,为一个Long型
- 分布式系统中不会产生id碰撞,由workerId和datecenter区分,效率很高
4.1 雪花算法的核心组成部分
- 1位符号位
- 41位时间戳位
- 10位工作进程位
- 2^10 = 1024,可以部署1024个结点,5位workerId和5位datacenter
- 12位序列号位
- 2^12-1 = 4095,即每个时间戳可以生成4095个唯一id
4.2 如何使用
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.7</version>
</dependency>
public class SnowFlakeService
{
private long workerId = 1;
private long datacenter = 1;
private Snowflake snowflake = IdUtil.createSnowflake(workerId,datacenter);
{
workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
System.out.println(workerId);
}
public long getSnowflakeId(){
return snowflake.nextId();
}
public long snowflakeId(long workerId,long datacenterId){
Snowflake snowflake = IdUtil.createSnowflake(workerId, datacenterId);
return snowflake.nextId();
}
public static void main(String[] args) {
SnowFlakeService snowFlakeService = new SnowFlakeService();
System.out.println(snowFlakeService.getSnowflakeId());
}
}