谈谈雪花算法的使用(代码片段)

catcher1994 catcher1994     2022-12-01     361

关键词:

背景

618来临之际,为了应对一些突发流量,购买了两台一个月的ECS用来临时对部分项目扩容。其中一个项目有用到雪花算法来生成Id,这个还是挺OK的。

不过发现要在配置文件中手动配置机器码!!配置的时候还要先知道目前配置了那些,这样才可以避免重复。

经过了解,除了会有单机单实例的情况,还会有单机多实例的情况。

这个要人工配置,是徒增工作量的,有点让人难以接受。

针对这个,老黄就做了一点调整,让这个机器码自动生成。

雪花算法基础

关于雪花算法,大部分文章都可以看到这个图。这个图很好的诠释了雪花算法生成Id的几个重要组成部分,这里也不展开具体介绍了。

技术图片

时间戳,工作机器Id,序列号这些位数是可以根据自己的业务场景来进来调整的。

10bit工作机器Id,其实就是上面说到的机器码,雪花算法内部并没有做任何处理,而是交由业务方自己定义,所以业务方需要自己保证这个的唯一性。

大部分情况,会把它分为5bit数据中心标识和5bit机器Id。这样的话可以支持32个数据中心和32个机器Id。

换句话说就是,一个业务可以在一个数据中心部署32个实例,最多部署的32个数据中心。正常来说,大部分项目,都不会需要部署这么多实例。。。

考虑到内网的IP段基本上是固定的,同一个应用基本上也会在连续的IP上面部署。

所以这里老黄最后采用的是本地IP地址取余做为机器Id,机器的HostName取余做为默认的数据中心Id。

下面来看看具体的实现。

简单实现

自动获取机器Id和数据中心Id。

/// <summary>
/// 获取机器Id
/// </summary>
/// <returns></returns>
private int GetWorkerId()

    var workerId = 0;

    try
    
        IPAddress ipaddress = IPAddress.Parse("0.0.0.0");
        NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
        foreach (NetworkInterface ni in interfaces)
        
            if (ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
            
                foreach (UnicastIPAddressInformation ip in
                    ni.GetIPProperties().UnicastAddresses)
                
                    if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    
                        ipaddress = ip.Address;
                        break;
                    
                
            
        
        Console.WriteLine($"ip = ipaddress.ToString()");
        var val = ipaddress.GetAddressBytes().Sum(x => x);
        // 取余
        workerId = val % (int)MaxWorkerId;
    
    catch
    
        // 异常的话,生成一个随机数
        workerId = new Random().Next((int)MaxWorkerId - 1);
    

    return workerId;


/// <summary>
/// 获取数据中心Id
/// </summary>
/// <returns></returns>
private int GetDatacenterId()

    var hostName = Dns.GetHostName();
    Console.WriteLine($"hostname = hostName");
    var val = System.Text.Encoding.UTF8.GetBytes(hostName).Sum(x => x);
    // 取余
    return val % (int)MaxDatacenterId;

生成器的构造函数

public IdGenerator(long datacenterId = -1)

    if (datacenterId == -1)
    
        // default
        datacenterId = GetDatacenterId();
    

    if (datacenterId > MaxDatacenterId || datacenterId < 0)
    
        throw new ArgumentException("非法数据标志ID", nameof(datacenterId));
    

    // 先检验再赋值
    WorkerId = GetWorkerId();
    DatacenterId = datacenterId;

    Console.WriteLine($"w = WorkerId");
    Console.WriteLine($"d = DatacenterId");

这里的数据中心可以让使用方自己定义,默认-1的话,会根据HostName去生成一个。

这里给一个自定义的可选标识,主要还是考虑到了单机多实例,即一个IP上面部署多个实例。

虽然这个时候还是要考虑人工配置,不过已经从多机变成单机了,也算是一点简化。毕竟大部分情况下也不会建议在同一个机器部署多个一样的项目。

默认情况下的使用,IdGenerator对象要全局唯一,做成单例即可。

IdGenerator generator = new IdGenerator();

Parallel.For(0, 20, x =>

    Console.WriteLine(generator.NextId()); 
);

Console.WriteLine("Hello World!");
System.Threading.Thread.Sleep(1000 * 60);

下面运行多个容器来模拟。

技术图片

可以看到机器Id和数据中心Id都是没有重复的。

在运行一次。

技术图片

也是同样的。

不足与展望

目前这种做法在应用实例少,机器数量少的情况下是基本可以满足使用要求的了。老黄公司目前也就不到30台服务器,所以怎么都是够用的。

但是依靠IP和HostName,随着实例或机器的数量增多,没有办法保证它们取余算出来的一定是唯一的。

在这种情况下就需要考虑引用第三方存储(Redis或数据库)来保证这个的唯一性了。

下面是本文的示例代码:

SnowflakeDemo

雪花算法生成的id,前端无法使用(代码片段)

由于前端Number类型长度不够,所以雪花算法生成的ID,传递给前端就会精度丢失。解决方案:@ConfigurationpublicclassJacksonConfig@Bean@Primary@ConditionalOnMissingBean(ObjectMapper.class)publicObjectMapperja 查看详情

java实现雪花算法(snowflake)-生成永不重复的id(源代码+工具类)使用案例(代码片段)

雪花算法是由Twitter公司开源的snowflake(雪花)算法。1、雪花算法的原理雪花算法会生成一个64位的二进制数据,为一个Long型。(转换成字符串后长度最多19),其基本结构:第一位:为未使用第二部分:41位为毫秒级时间(41位... 查看详情

java实现雪花算法(snowflake)-生成永不重复的id(源代码+工具类)使用案例(代码片段)

雪花算法是由Twitter公司开源的snowflake(雪花)算法。1、雪花算法的原理雪花算法会生成一个64位的二进制数据,为一个Long型。(转换成字符串后长度最多19),其基本结构:第一位:为未使用第二部分:41位为毫秒级时间(41位... 查看详情

springboot中使用雪花算法生成雪花id(代码片段)

目录1、什么是雪花算法2、雪花算法的优缺点3、springboot项目中使用雪花算法使用1、什么是雪花算法雪花算法(Snowflake)是一种生成全局唯一ID的算法,由Twitter公司开发。它可以在分布式系统中生成全局唯一的ID,... 查看详情

mybatis-plus--使用雪花算法生成主键id--使用/分析(代码片段)

原文网址:MyBatis-Plus--使用雪花算法生成主键ID--使用/分析_IT利刃出鞘的博客-CSDN博客简介说明    本文介绍MyBatis-Plus如何使用其自带的雪花算法生成主键ID。MyBatis-Plus自带的雪花算法MyBatis-Plus自带雪花算法MyBatis-Plus默认使用... 查看详情

雪花算法(代码片段)

...间戳、UUID都不是很可靠。为此,Twitter提出了一种名为“雪花算法”的算法来生成分布式全局唯一ID的算法算法介绍“雪花算法”生成的ID为\\(64\\)位整数,其中,前\\(41\\)位(\\(64\\)位整数第一位表示符号位,不作为开始位)表示... 查看详情

结合redis在spring架构体系中使用雪花算法(代码片段)

...。这里记录下在工作中我结合Redis在Spring架构体系中使用雪花算法生成分布式ID的方式。一、代码部分importlombok.extern.slf4j.Slf4j;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.s 查看详情

id生成算法-雪花算法(snowflake)及代码实现(代码片段)

文章目录前言一、ID生成算法对比二、雪花算法原理三、java实现结尾前言唯一ID可以标识数据的唯一性,在分布式系统中生成唯一ID的方案有很多,常见的方式大概有以下三种:依赖数据库,使用如MySQL自增列或Orac... 查看详情

雪花算法原理解析(代码片段)

...拆分,设置初始值和相同的自增步长。批量申请自增ID。雪花算法。百度UidGenerator算法(基于雪花算法实现自定义时间戳)。美团Leaf算法(依赖于数据库,ZK)。  本文主要介绍SnowFlake算法,是Twitter开源的分布式id生成算法。  其... 查看详情

id生成器雪花算法和雪花算法的sony实现(代码片段)

1雪花算法首先确定我们的数值是64位,int64类型,被划分为四部分,不含开头的第一个bit,因为这个bit是符号位。用41位来表示收到请求时的时间戳,单位为毫秒,然后五位来表示数据中心的id,然后再五位来表示机器的实例id,... 查看详情

oracleid生成算法——雪花算法(代码片段)

背景近几日,被主键ID生成折磨的不太行,于是就在寻找一种合适的主键生成策略,选择一种合适的主键生成策略,可以大大降低主键ID的维护成本。主键ID生成方法最常用的4种主键ID生成方法UUID:全局唯一性&... 查看详情

oracleid生成算法——雪花算法(代码片段)

背景近几日,被主键ID生成折磨的不太行,于是就在寻找一种合适的主键生成策略,选择一种合适的主键生成策略,可以大大降低主键ID的维护成本。主键ID生成方法最常用的4种主键ID生成方法UUID:全局唯一性&... 查看详情

[算法与数据结构]谈谈线性查找法~(代码片段)

[算法与数据结构]一文详解线性查找法~📅前言一、📝算法基础知识1、什么是算法2、算法的五大特性二、📈线性查找法1、举例阐述2、实现线性查找法3、使用泛型4、升级改造5、使用自定义类6、循环不变量三、Ὄ... 查看详情

[算法与数据结构]谈谈线性查找法~(代码片段)

[算法与数据结构]一文详解线性查找法~📅前言一、📝算法基础知识1、什么是算法2、算法的五大特性二、📈线性查找法1、举例阐述2、实现线性查找法3、使用泛型4、升级改造5、使用自定义类6、循环不变量三、Ὄ... 查看详情

6-9雪花算法与新增功能(代码片段)

新增工具类:/***Twitter的分布式自增ID雪花算法**/@ComponentpublicclassSnowFlake/***起始的时间戳*/privatefinalstaticlongSTART_STMP=1609459200000L;//2021-01-0100:00:00/***每一部分占用的位数*/privatefinalstaticlongSEQUEN 查看详情

分布式全局唯一id解决方案(雪花算法)(代码片段)

...自增ID机制适合作分布式ID吗Redis集群实现分布式ID的利弊雪花算法(SonwFlake)使用糊涂工具包实现雪花算法优缺点:为什么需要分布式全局唯一ID以及分布式ID的业务需求在复杂分布式系统中,往往需要对大量的数据和消息进... 查看详情

javatwitter雪花算法(代码片段)

查看详情

厉害了,美女同事用单例模式实现了雪花算法!(代码片段)

点击关注公众号,Java干货及时送达雪花算法雪花算法适用于生成全局唯一的编号,比如数据库主键id,订单编号等至于为什么叫雪花算法,是因为科学家通过研究认为自然界中不存在两片完全相同的雪花,所... 查看详情