雪花算法和UUID

news2024/10/6 12:24:17

目录

  • 雪花算法
    • 概念
    • 优点和不足
      • 优点:
      • 缺点:
      • 解决方案
      • 代码示例
  • UUID
    • 优点与不足
      • 优点
      • 不足
  • 两种算法的比较
    • 应用场景区别

雪花算法

概念

雪花算法是一个分布式id生成算法,它生成的id一般情况下具有唯一性。由64位01数字组成,第一位是符号位,始终为0。接下来的41位是时间戳字段,根据当前时间生成。然后中间的10位表示机房id+机器id,也可以是单独的机器id。最后12位是序列号。
在这里插入图片描述

优点和不足

优点:

全局唯一: 雪花算法生成的 ID 是全局唯一的,即使在分布式系统中也能保证 ID 的唯一性。
有序: 雪花算法生成的 ID 是有序的,可以根据时间戳进行排序。
高效: 雪花算法的生成速度非常快,可以满足高并发场景的需求。

缺点:

依赖时间: 雪花算法依赖时间戳,如果系统时间出现问题,可能会导致 ID 重复。

解决方案

百度的UidGenerator:Java实现, 基于Snowflake算法的唯一ID生成器。

  • UidGenerator 会在生成 ID 之前对时间戳进行校验,确保时间戳是递增的。
  • 如果发现时间戳出现回拨,则会抛出异常,拒绝生成 ID。

代码示例

public class SnowFlake {

    // 数据中心(机房) id
    private long datacenterId;
    // 机器ID
    private long workerId;
    // 同一时间的序列
    private long sequence;

    public SnowFlake(long workerId, long datacenterId) {
        this(workerId, datacenterId, 0);
    }

    public SnowFlake(long workerId, long datacenterId, long sequence) {
        // 合法判断
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
                timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);

        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.sequence = sequence;
    }

    // 开始时间戳(2021-10-16 22:03:32)
    private long twepoch = 1634393012000L;

    // 机房号,的ID所占的位数 5个bit 最大:11111(2进制)--> 31(10进制)
    private long datacenterIdBits = 5L;

    // 机器ID所占的位数 5个bit 最大:11111(2进制)--> 31(10进制)
    private long workerIdBits = 5L;

    // 5 bit最多只能有31个数字,就是说机器id最多只能是32以内
    private long maxWorkerId = -1L ^ (-1L << workerIdBits);

    // 5 bit最多只能有31个数字,机房id最多只能是32以内
    private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

    // 同一时间的序列所占的位数 12个bit 111111111111 = 4095  最多就是同一毫秒生成4096个
    private long sequenceBits = 12L;

    // workerId的偏移量
    private long workerIdShift = sequenceBits;

    // datacenterId的偏移量
    private long datacenterIdShift = sequenceBits + workerIdBits;

    // timestampLeft的偏移量
    private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    // 序列号掩码 4095 (0b111111111111=0xfff=4095)
    // 用于序号的与运算,保证序号最大值在0-4095之间
    private long sequenceMask = -1L ^ (-1L << sequenceBits);

    // 最近一次时间戳
    private long lastTimestamp = -1L;


    // 获取机器ID
    public long getWorkerId() {
        return workerId;
    }


    // 获取机房ID
    public long getDatacenterId() {
        return datacenterId;
    }


    // 获取最新一次获取的时间戳
    public long getLastTimestamp() {
        return lastTimestamp;
    }


    // 获取下一个随机的ID
    public synchronized long nextId() {
        // 获取当前时间戳,单位毫秒
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            System.err.printf("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",
                    lastTimestamp - timestamp));
        }

        // 去重
        if (lastTimestamp == timestamp) {

            sequence = (sequence + 1) & sequenceMask;

            // sequence序列大于4095
            if (sequence == 0) {
                // 调用到下一个时间戳的方法
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            // 如果是当前时间的第一次获取,那么就置为0
            sequence = 0;
        }

        // 记录上一次的时间戳
        lastTimestamp = timestamp;

        // 偏移计算
        return ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        // 获取最新时间戳
        long timestamp = timeGen();
        // 如果发现最新的时间戳小于或者等于序列号已经超4095的那个时间戳
        while (timestamp <= lastTimestamp) {
            // 不符合则继续
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        SnowFlake worker = new SnowFlake(1, 1);
        long timer = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            worker.nextId();
        }
        System.out.println(System.currentTimeMillis());
        System.out.println(System.currentTimeMillis() - timer);
    }

}

UUID

UUID是一个128位(16字节)长度的标识符,通常以 36 个字符的字符串形式表示。能够在分布式系统中生成全局唯一标识。它可以实现基于随机数生成,不依赖于时间戳或其他信息。

优点与不足

优点

  • 全局唯一
  • 随机无序

不足

  • 1、占用更多的存储空间uuid 是一个 128 位的二进制数,通常以 36 个字符的字符串形式表示,占用了很多的存储空间,比一般的整数型主键要大得多。这会增加数据库的磁盘占用,降低查询效率,影响性能。
  • 2、主键是包含索引的,然后mysql的索引是通过b+树来实现的,每一次新的UUID数据的插入,为了查询的优化,都会对索引底层的b+树进行修改,因为UUID数据是无序的。所以每一次UUID数据的插入都会对主键地的b+树进行很大的修改,这一点很不好。 插入完全无序,不但会导致一些中间节点产生分裂。

举例:
假设一个 B+ 树的叶子节点可以存储 10 个数据。
如果使用自增 ID 作为主键,插入数据的顺序是 1、2、3、4、5…,那么叶子节点的填充率会比较均匀,页分裂的次数会比较少。
如果使用 UUID 作为主键,插入数据的顺序可能是 10、5、1、7、3…,那么叶子节点的填充率会比较不均匀,一些叶子节点可能很快被填满,而另一些叶子节点可能仍然很空,页分裂的次数会比较多。

两种算法的比较

在这里插入图片描述

应用场景区别

UUID 更适合需要全局唯一标识,但不需要顺序性的场景,例如数据库记录、文件、用户等。
雪花算法 更适合需要顺序性 ID,并且需要高性能 ID 生成器的场景,例如消息队列、订单号、流水号等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1831543.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kubernetes集群中如何利用北极星因果指标设置正确的POD规格——CPU篇

在 Kubernetes 容量规划中&#xff0c;追求的是集群的稳定性和资源使用效率之间的平衡&#xff1a; 资源分配过多会造成浪费。 资源分配过少则会导致用户请求时延上升&#xff0c;影响集群的稳定性。 背景 公众号之前翻译了一篇 Sysdig 的文章&#xff0c;Kubernetes 容量规…

玩转nRF52840-DK开发套件(2)

介绍如何在Windows操作系统上使用Arm Keil MDK。Arm Keil MDK附带Arm C/C编译器和Vision集成开发环境&#xff08;IDE&#xff09;&#xff0c;以及所有nRF5SDK的版本提供了现成的Keil项目。 1. 安装最新的 nRF5 SDK. 链接&#xff1a;nRF5 SDK - nordicsemi.com 点击Download&…

泰迪智能科技董事长张良均荣获“2024年广东软件风云榜新锐企业家”

6月13日&#xff0c;在广州举办2024年粤港澳软件产业高质量发展大会、第十二届粤港云计算大会暨第七届粤港澳ICT大会。大会以“培育信息技术新质生产力&#xff0c;打造粤港澳发展创新引擎”为主题&#xff0c;研讨基础软件、云计算、人工智能等新一代技术的新态势、新应用&…

14.编写自动化测试(上)

标题 一、如何编写测试1.1 一些概念1.2 测试函数剖析1.3 使用assert!宏检查结果1.4 使用assert_eq!和assert_ne!宏来测试相等1&#xff09; assert_eq!2&#xff09; assert_ne! 1.5 使用 should_panic 检查 panic 二、将 Result<T, E> 用于测试 一、如何编写测试 1.1 一…

解决外网404:清除DNS缓存并配置host主机使用知名公共DNS服务

在 Windows 上清除/刷新 DNS 缓存 对于所有Windows版本&#xff0c;清除DNS缓存的过程都是相同的。你需要使用管理员权限打开命令提示符并运行ipconfig /flushdns。 浏览器清除DNS缓存 大多数现代的Web浏览器都有一个内置的DNS客户端&#xff0c;以防止每次访问该网站时…

vscode字符多行自动增长插件。

多行字符自动增长插件CharAutoIncre 当你使用shiftalt选中了多行,并输入了’1’,这时这几行都变成了’1’. 这时你可以选中&#xff08;shift左键&#xff09;为’1’的这几行, 接下来按下shiftaltq此时’1’变为了’12345’自增长的样式。 同时本插件支持字符’a-z,A-Z’。 目…

高考没考好焦虑怎么选计算机专业!一篇告诉你,推荐三个风口专业!想学计算机怎么选大学专业

高考成绩揭晓&#xff0c;几家欢喜几家愁。对于那些未能如愿考取理想分数的同学来说&#xff0c;未来似乎蒙上了一层阴影。尤其是在计算机专业如此热门的今天&#xff0c;低分考生是否还有机会在这个领域找到一席之地&#xff1f;本文将为你揭秘&#xff0c;即使高考成绩不理想…

Nature Microbiology丨VITA单细菌转录组测序技术助力深入解析奶牛瘤胃微生物组功能异质性

瘤胃微生物组一直以来都是研究相对不足但又极其复杂的微生物生态系统之一。瘤胃微生物能够有效降解植物纤维&#xff0c;将其转化为高质量的蛋白质产品&#xff0c;在这一过程中&#xff0c;由于微生物强烈的发酵&#xff0c;还会产生大量气体&#xff0c;其成分主要包括二氧化…

自动化产线设备联网,协同打造5G智慧工厂

1、需求背景 随着信息技术、物联网、人工智能等领域的飞速发展&#xff0c;智慧工厂成为制造业升级和转型的关键方向。在智慧工厂中&#xff0c;产线设备之间的实时通信和协同操作可以提高整个生产流程的自动化水平。 提升生产效率 通过稳定的网络连接&#xff0c;保证设备之…

编码在网络安全中的应用和原理

前言:现在的网站架构复杂&#xff0c;大多都有多个应用互相配合&#xff0c;不同应用之间往往需要数据交互&#xff0c;应用之间的编码不统一&#xff0c;编码自身的特性等都很有可能会被利用来绕过或配合一些策略&#xff0c;造成一些重大的漏洞。 什么是编码&#xff0c;为什…

软件功能测试和性能测试包括哪些测试内容?又有什么联系和区别?

软件功能测试和性能测试是保证软件质量和稳定性的重要手&#xff0c;无论是验证软件的功能正确性&#xff0c;还是评估软件在负载下的性能表现&#xff0c;这些测试都是必不可少的。 一、软件功能测试   软件功能测试是指对软件的各项功能进行验证和确认&#xff0c;确保软件…

51交通灯

一、基本原理 利用51单片机控制各个路口红绿灯及时间显示。 设计的重点&#xff1a; 1、各个路口红绿灯亮灭的规则&#xff0c;暂不考虑左转方向&#xff1b; 2、倒计时的实现&#xff0c;利用单片机的定时器进行计数得到秒信号&#xff1b; 3、时间显示&#xff1a;东西南…

【每日刷题】Day67

【每日刷题】Day67 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 23. 合并 K 个升序链表 - 力扣&#xff08;LeetCode&#xff09; 2. 1189. “气球” 的最大数量 - …

一篇搞定Spring,IOC容器,Bean管理,3.AOP底层原理和实现(收下吧,真的很详细)

1.Spring容器的概念 Spring是一个轻量级的框架&#xff0c;可以解决企业开发的复杂性&#xff0c;让开发效率提升&#xff0c;他核心的两个点是&#xff1a; 1.IOC IOC&#xff1a;在java中&#xff0c;我们程序员一般是去创建一个对象&#xff0c;那么有个问题就是耦合性太…

Apache DolphinScheduler查看版本信息

我找了半天&#xff0c;没有看到版本在哪里。然后我看配置&#xff0c;他要连接数据库&#xff0c;我去他存储数据库的表里面&#xff0c;看到了相关的版本信息。 cd /home/dolphinscheduler/dolphinscheduler/bin/env dolphinscheduler找到了里面的密码 版本是3.1.3

VMware挂载NAS存储异常处理

问题概述 由于非法关机或恢复&#xff0c;NFS存储可能会出现以下问题&#xff1a; 数据存储处于挂起状态或无法正常识别。虚拟机的配置文件或虚拟磁盘仍然注册在异常数据存储上。系统误认为有虚拟机在使用该数据存储。 问题对策 下面是详细的排查步骤和解决对策&#xff1a…

JS 实现Date日期格式的本地化

为了更好的更新多语言日期的显示&#xff0c;所以希望实现日期的本地化格式显示要求&#xff0c;常规的特殊字符型格式化无法满足显示要求&#xff0c;这里整理了几种我思考实现的本地化实现功能。 通过多方查找&#xff0c;总结了实现的思路主要有如下三个方向&#xff1a; 官…

ThinkPHP 的老漏洞仍然被攻击者钟情

研究人员发现安全领域出现了令人不安的趋势&#xff1a;攻击者不仅对新披露的漏洞十分感兴趣&#xff0c;对已知的漏洞也丝毫不放过&#xff0c;尽管有些漏洞已经存在了好些年头&#xff0c;攻击者仍然能够通过老漏洞成功完成攻击。 典型的例子就是 ThinkPHP 远程代码执行漏洞…

同三维T80004EHL-W-4K30 4K HDMI编码器,支持WEBRTC协议

输入&#xff1a;1路HDMI1路3.5音频&#xff0c;1路HDMI环出1路3.5音频解嵌输出 4K30超高清,支持U盘/移动硬盘/TF卡录制&#xff0c;支持WEBRTC协议&#xff0c;超低延时&#xff0c;支持3个点外网访问 1个主流1个副流输出&#xff0c;可定制选配POE供电模块&#xff0c;WEBR…

白酒:茅台镇白酒的文化内涵与传承意义

茅台镇白酒&#xff0c;作为中国的酒文化的代表之一&#xff0c;具有丰富的文化内涵和传承意义。而云仓酒庄豪迈白酒作为茅台镇的品牌之一&#xff0c;更是承载了深厚的文化底蕴和历史积淀。 首先&#xff0c;茅台镇白酒是中国的酒文化的重要组成部分。白酒在中国有着悠久的历史…