卧槽!又一个Java学习神器
分布式 ID, 我们可能都听过分布式系统,分布式,分布式 ID 可能比较少,因为业务,方向以及系统维护的方面出发,现在的互联网中的项目,多数都需要一个全局且唯一,有增量趋势的 标识 。目前用的可能是 MySQL 的自增主键,UUID,时间戳等,但是对于日益增长的消息系统,点评,支付等具体操作,都需要一个稳定,全局唯一,且有明显自增趋势的 ID 作为唯一标识。
一个分布式全局 ID 的硬性要求
其中信息安全,可能有的小伙伴不太了解,你每次请求获取的 ID(查询操作),这个如果是递增,我们就能直观的判断出有信息,多少人,这是第多少个等,这属于敏感信息泄露的范畴, 安全还是很重要的;
规则我们确定之后,我们就要求生成这个 ID 系统的要求,之前是对于生成 单个一个 ID 的要求,
对 ID 系统生成的可用性要求因为是存在于分布式系统的,那也就是我们比较熟悉的,
高可用:发起一个获取分布式 ID 的请求时,必须保证服务器在 99.999%的时候给我创建成功
低延迟: 获取分布式 ID,服务器响应快速,不能有高延迟,会有误差
高并发: 一秒钟可以获取 10 万左右的 ID,而且要成功,服务器要扛得住
情景再现:面试中,对于面试者做过的项目,面试官一般会采用聊集群,QPS 等情况验证,项目的真实性, 其中分布式 ID 就属于具体实现了,一般会问:
你们项目是,分布式微服务,集群化部署,电商的这个系统中对于订单,支付等 全局 ID 是如何生成的?
雪花算法 snowFlake;
现在系统常用的 ID 生成方式:数据库自增,UUID ,时间戳;Redis 集群
(1) 数据库自增(mysql 自增)其中数据库自增,对于单体系统,后台系统用的比较多,因为并发小,使用人数也少,适合于小系统,QPS 一般几十到一百左右的,
缺点:对于数据敏感的场景不宜使用, 且支撑不了分布式场景,自增之后还是会还原为原来的数值
(2) UUIDUUID 用的是比较普遍的一个 ID, 因为全局唯一,但是它存在很多的问题
UUID 的缺点:
无序,且无法预测生成顺序,无法有效的呈现递增趋势
存储,字段很长,耗费数据库资源,对于特点环境存在一些问题,
优点:只剩下全局唯一了
(3)时间戳一般可以使用时间戳加具体的业务 ID 来规定,但是用的也比较少
(4)基于 Redis 集群生成策略因为 Redis 特性是基于单线程,所以用它生成 ID 操作是原子性的,集群化可以实现,
通过设备集群的增长步长,起始值,就可以
比如 Redis 集群有五台机器, 可以初始化为每台 Redis 的值 1,2,3,4,5;步长是 5;
各个 Redis 生成的 Id 为:
A:1,6,11,16,21,...B:2,7,12,17.22,...C:3,8,13,18,23,...D:4,9,14,19,24,...E:5,10,15,20,25,...
虽然可以实现,但是配置 Redis 集群后, 要实现数据丢失怎么办,key 的失效时间等等, 不是不能做,是杀鸡焉用牛刀 ,对的;
然后就到了我们今天的主题:
(5)Twitter 开源的 snowflake;Snowflake(雪花) 是一项服务,用于为 Twitter 内的对象(推文,直接消息,用户,集合,列表等)生成唯一的 ID。这些 IDs 是唯一的 64 位无符号整数,它们 基于时间 ,而不是顺序的。完整的 ID 由时间戳,工作机器编号和序列号组成。当在 API 中使用 JSON 数据格式时,请务必始终使用 id_str 字段而不是 id,这一点很重要。这是由于处理 JSON 的 Javascript 和其他语言计算大整数的方式造成的。如果你遇到 id 和 id_str 似乎不匹配的情况,这是因为你的环境已经解析了 id 整数,并在处理的过程中仔细分析了这个数字。
Twitter 的分布式雪花算法 SnowFlake,经测试 snowflake 每秒能够产生 26 万 个自增可排序的 ID1、twitter 的 SnowFlake 生成 ID 能够按照时间有序生成 2、SnowFlake 算法生成 id 的结果是一个 64bit 大小的整数,为一个 Long 型(转换成字符串后长度最多 19).3、分布式系统内不会产生 ID 碰撞(由 datacenter 和 workerld 作区分)并且效率较高。
分布式系统中,有一些需要使用全局唯一 ID 的场景,生成 ID 的基本要求
1.在分布式的环境下必须全局且唯一。
对比2.一般都需要单调递增,因为一般唯一 ID 都会存到数据库,而 Intodb 的特性就是将内容存储在主键索引树上的叶子节点,而且是从左往右,递增的,所以考虑到数据库性能,一般生成的 id 也最好是单调递增。为了防止 ID 冲突可以使用 36 位的 UUID,但是 UUID 有一些缺点,首先他相对比较长,另外 UUID-般是无序的
snowflake 是中可以用 69 年是否成立?
雪花算法可以高度唯一和可用性时间长:作比较, 41 位的 1 二进制数字,对于十进制来说,是多少呢;十进制的数字是: 2199023255551 https://tool.lu/hexconvert/ 进制转换的工具箱
我做了个 demo 来证明:
其中主要设置的是 10 位的工作进程位;-
一般分为数据中心和机器位
生成 snowFlake 的 ID我们以 springboot 的项目来构建这个 snowFlake 的 ID 生成,
依赖:
<!-- hutool关于sonwFlake的使用 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
<version>5.6.0</version>
</dependency>
复制代码
这里我们表示的是 Java 代码库中,hutool 的类库,调用已经封装好的 IdUtil 就好。
package com.generate;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* 生成全局ID
* 雪花算法Tiwwer
*/
@Component
@Slf4j
public class SnowFlakeUtil {
//主要配置工作位十位,其中5位是机器位(节点或者是具体哪台机器),5位数数据中心
private Long workerID = 0L;
private Long datecenter = 1L;
private Snowflake snowflake = IdUtil.createSnowflake(workerID, datecenter);
@PostConstruct
private void init() {
try {
//当前机器的IP
workerID = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
log.info("当前机器的workerID{}", workerID);
} catch (Exception e) {
log.warn("获取机器ID失败", e);
workerID = Long.valueOf(NetUtil.getLocalhost().hashCode());
log.info("当前机器workID", workerID);
}
}
//简单版本
public synchronized Long createSnowFlakeID() {
//生成的ID加锁synchronized
return snowflake.nextId();
}
//全局版本的
public synchronized long showFlakeID(long workId, long datacenterID) {
Snowflake snowflake = IdUtil.createSnowflake(workerID, datecenter);
return snowflake.nextId();
}
public static void main(String[] args) {
System.out.println(new SnowFlakeUtil().createSnowFlakeID());
// 1401136955063926784
}
}
这里是简单的一个版本,与真实项目中有差异,差异主要是体现在参数配置中,
虽然雪花算法可以生成,唯一且自增的 ID ,但是它也存在问题,是关于时间戳的;
总结:优点:1.不依赖与第三方系统(MySQL,Redis 等),稳定性,生成 ID 的性能非常高
2.毫秒数在高位,自增序列在低位,整个 ID 都是有趋势递增的;
缺点:依赖于机器时钟,也就是对表时间,如果机器回拨,会导致重复 ID 生成;
这种情况一般会发生在分布式环境中,每台机器上的时钟不可能完全同步,有时候会出现不是全局递增的情况
但是对于中小公司,此缺点可以忽略, 一般会要求趋势递增,并不会严格要求递增;
snowFlake 的优化对于时钟回拨的情况,国内的大厂也修复了这个雪花算法的问题,比如
百度开源的 Uid GeneratorLeaf--美团点评分布式生成 ID两者都是在雪花算法的基础上,优化和改进;
适用于
对于普通公司,200 人上下的,体制主要对于研发人员,都可以使用 snowFlake, 配置具体 ID 生成,规定其中位数的默认值,
尤其是对于时钟回拨的,(时间一直在走),重点在配置,选择,处理异常,就可以完成。
2021最新全套Java资料,完整面试题及答案(都整理成文档),有很多干货,包含mysql,netty,spring,线程,spring cloud、JVM、源码、算法,详细的学习规划图等资料,需要获取这些内容的朋友请私信我:学习
,