关于雪花算法:雪花算法

一.雪花算法组成部分雪花算法应用64位long类型的数据存储id1.第一位占用1bit,其值始终是0,没有理论作用。 2.工夫戳占用41bit,准确到毫秒,总共能够包容约69年的工夫。 3.工作机器id占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,做多能够包容1024个节点。 4.序列号占用12bit,每个节点每毫秒0开始一直累加,最多能够累加到4095,一共能够产生4096个ID。二.雪花算法的实现次要依赖于数据中心ID和数据节点ID两个参数1.确定位数调配2.工夫戳左移3.机器ID左移4.序列号5.位或运算留神:1.工夫戳的递增性:每次生成ID时,须要确保工夫戳是递增的,以保障ID的全局唯一性。2.时钟同步:因为雪花算法重大依赖服务器时钟,因而须要确保所有服务器的时钟是同步的,以防止产生反复的ID。3.机器ID的唯一性:每台机器都应该有惟一的机器ID,以确保在同一时刻,不同的机器能够生成不同的ID。三.雪花算法的长处:1.能满足高并发分布式系统环境下ID不反复2.基于工夫戳,能够保障根本有序递增3.不依赖第三方的库或者中间件4.生成效率极高四.雪花算法的毛病1.依赖零碎工夫:雪花算法生成ID的过程中依赖于零碎工夫,如果零碎时钟被回调或者扭转,可能会导致ID抵触或者反复。2.时钟回拨问题:如果零碎时钟呈现回拨景象,即以后工夫戳小于上一次生成ID的工夫戳,雪花算法会抛出异样或生成反复的ID.3.机器ID和数据中心ID的限度:雪花算法中,机器ID和数据中心ID的位数是固定的,别离占用5位。这意味着最多只能反对1024个节点(包含数据中心和工作节点的组合)。4.ID长度和精度问题:雪花算法生成的ID是一个64位的long型数字。留神:在Web开发中须要跟js打交道,而js反对最大的整型范畴为53位,超过这个范畴就会失落精度,53之内能够间接由js读取,超过53位就须要转换成字符串能力保障js解决正确。

March 2, 2024 · 1 min · jiezi

关于雪花算法:分布式系统ID的唯一性雪花算法

1.为什么须要分布式全局惟一ID2.ID生成规定局部硬性要求3.ID生成规定的可用性要求4.现有的ID生成策略5.雪花算法ID生成策略 1.为什么须要分布式全局惟一ID在简单的分布式高并发零碎中,往往在一秒之内就会产生海量的数据,而且咱们要对这些数据进行唯一性的标识,且还要保障有序性,在咱们以往的开发应用中,UUID以及自增ID这种生成策略,可能无奈满足一瞬间生成数据的唯一性和有序性,此时一个可能生成全局惟一的ID生成规定是非常重要的。 2.ID生成规定局部硬性要求2.1)全局惟一不呈现反复的ID号,这是对ID最根本的要求。2.2)趋势递增在mysql的InnoDB引擎中应用的是聚簇索引,应用BTree构造来保留数据,用递增的ID能够让BTree不会产生微小的变动来保障写入性能。 当B+Tree插入的主键值为自增的时候:当B+Tree插入的主键值为随机值uuid的时候: 2.1)枯燥递增保障下一个ID的值肯定要大于上一个ID的值,来合乎排序等要求 2.3)信息安全如果ID是自增ID或者某种规定的连续性ID,歹意的扒取工作就比拟容易进行(比方退款接口,轻易输出订单的自增ID。或者支付红包的接口,轻易输出红包的自增ID,以及察看一天ID的增量来判断零碎一天的订单量。)所以在一些利用场景下,须要ID不规则,让这些歹意的扒取工作不好进行。 2.4)含工夫戳这样就能在开发中通过id来理解这条数据的生成工夫 3.ID生成规定的可用性要求3.1)高可用发送一个获取分布式ID的申请,服务器就要99.99999%的状况下给咱们创立一个分布式惟一ID。 3.2)低延时发送一个获取分布式ID的申请,服务器要响应迅速。 3.3)高qps如果一秒钟有十万个申请同时发送给服务器,服务器也要同时创立十万个不同的分布式惟一递增有序ID。 4.现有的ID生成策略 4.1)Uuid长处:能够保障唯一性 毛病:4.1.1)无序,不能生成递增的有序数字。4.1.2)主键过长,不合乎主键越短越好的规定,在where id = ''时候会产生比拟开销。4.1.3)索引B+Tree的决裂(下面曾经介绍过)。 4.2)自增id长处:保障枯燥递增性,有序性。 毛病:4.2.1)ID很容易被人猜出来,不平安4.2.2)单机模式无奈承载高并发量,无奈一秒钟生成几十万个不同的ID,不合乎高qps规定。4.2.3)集群模式,假如第一台数据库id是奇数,第二台id是偶数,这种配置规定十分繁琐,而且如果要扩大到一百多台mysql,不易于扩大。 4.3)基于redis的全局ID策略长处:因为redis底层人造地保障了原子性,所以能够应用incr来操作,而且单机redis的qps就比拟高,能够肯定水平保障高qps。 毛病:在集群模式下,redis和mysql一样,都须要设置不同的增长步长,这种配置形式极为繁琐,而且不易于扩大。 5.雪花算法ID生成策略理解了下面这么多生成策略之后,咱们发现上述生成ID规定均不合乎生成规定,这个时候,雪花算法呈现了! Twitter的分布式雪花算法snowflake,经测试snowflake每秒可能生成26万个自增可排序的id 5.1)雪花算法的数据结构 咱们先来看一下雪花算法的数据结构图: 雪花算法由一个64bit的long类型形成,它将一个long类型拆分成了四个号段,来别离示意不同的值,来保障全局惟一和有序性。 5.2)雪花算法的号段解析 1bit 符号位:不必,二进制中的最高位是符号位,1示意正数,0示意负数生成的id个别都是负数,所以最高符号位为0. 41bit 工夫戳位:用来记录时间,毫秒数。41位能够用来示意2^(41)-1个数字,如果只用来示意负数,那么这个值的范畴就是0~2^(41)-1,减1是因为数字是从0开始算的,而不是1. 2^(41)-1转化成单位年则是(2^(41)-1)/(1000606024365) = 69年 10bit 工作过程位:能够用来示意工作机器id,能够部署在2^(10)=1024个节点,也能够用5位workId(工作机器ID)和5位datacenterId(工作线程Id),也能够多用几位来示意工作机器ID,位数不固定。 12bit序列号位:12位,可示意的最大正整数是 2^12 -1 = 4095,来示意同一机器一时间戳(毫秒)内产生的4095个ID序号。 5.3)雪花算法的优缺点 长处:毫秒数在高位,整个ID都是趋势递增的。不依赖数据库等第三方零碎,以服务的形式部署,稳定性高,合乎高qps,高可用。依据本身业务调配bit位,非常灵活 毛病:依赖机器时钟,如果机器时钟重置,会导致反复ID生成。在单机上递增,然而因为是分布式环境,每台机器上的时钟不同步,有时候会呈现不递增的状况。(不过大抵是递增的,而且齐全能保障趋势递增。) 5.4)雪花算法的代码实现 咱们能够应用糊涂工具生成: <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-captcha</artifactId> <version>${hutool.version}</version></dependency>ID 生成器: package com.example.demo.meeting.util;import cn.hutool.core.lang.Snowflake;import cn.hutool.core.util.IdUtil;import org.apache.commons.lang3.SystemUtils;import org.apache.commons.lang3.RandomUtils;import org.apache.commons.lang3.StringUtils;import org.springframework.context.annotation.Bean;import org.springframework.stereotype.Component;import java.net.Inet4Address;import java.net.UnknownHostException;/** * @author sulingfeng * @title: IdGenerator */@Componentpublic class IdGenerator { public static Snowflake snowflake = IdUtil.createSnowflake(getWorkId(), getDataCenterId()); /** * workId应用IP生成 * @return workId */ private static Long getWorkId() { try { String hostAddress = Inet4Address.getLocalHost().getHostAddress(); int[] ints = StringUtils.toCodePoints(hostAddress); int sums = 0; for (int b : ints) { sums = sums + b; } //咱们能够依据须要自行管制长短 return (long) (sums % 32); } catch (UnknownHostException e) { // 失败就随机 return RandomUtils.nextLong(0, 31); } } /** * dataCenterId应用hostName生成 * @return dataCenterId */ private static Long getDataCenterId() { try { String hostName = SystemUtils.getHostName(); int[] ints = StringUtils.toCodePoints(hostName); int sums = 0; for (int i: ints) { sums = sums + i; } return (long) (sums % 32); } catch (Exception e) { // 失败就随机 return RandomUtils.nextLong(0, 31); } } public synchronized long snowflakeId() { return snowflake.nextId(); }}

May 7, 2022 · 1 min · jiezi