分布式ID生成方法的超详细分析(全)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 目录前言1. UUID2. 数据库自增3. 数据库集群4. 数据库号段5. redis模式6. 雪花算法7. 其他总结前言关于什么是分布式ID数据量不是很多的时候,单一个数据库表可以支撑其业务,即使数据在大也可以主从复制到一定量的数据时,实现分库分表的时候,就需要一个全局唯一的ID,订单的编号就是分布式ID关于上面牵扯到的主从复制可看我之前的文章进行查缺补漏关于主从复制的超详细解析(全)关于数据库的分布式ID可看我之前在Mycat种提及到具体都有如下:在实现分库分表的情况下,数据库自增主

前言

关于什么是分布式ID

数据量不是很多的时候,单一个数据库表可以支撑其业务,即使数据在大也可以主从复制
到一定量的数据时,实现分库分表的时候,就需要一个全局唯一的ID,订单的编号就是分布式ID

关于上面牵扯到的主从复制
可看我之前的文章进行查缺补漏
关于主从复制的超详细解析(全)

关于数据库的分布式ID可看我之前在Mycat种提及到

具体都有如下

在实现分库分表的情况下,数据库自增主键已无法保证自增主键的全局唯一。为此,Mycat 提供了全局 sequence

  • 本地文件

优点:本地加载,读取速度较快
缺点:抗风险能力差,Mycat 所在主机宕机后,无法读取本地文件

  • 数据库方式

利用数据库一个表 来进行计数累加。但是并不是每次生成序列都读写数据库,这样效率太低。Mycat 会预加载一部分号段到 Mycat 的内存中,这样大部分读写序列都是在内存中完成的。如果内存中的号段用完了 Mycat 会再向数据库要一次

  • 时间戳方式

全局序列ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加) 换算成十进制为 18 位数的
long 类型,每毫秒可以并发 12 位二进制的累加。
优点:配置简单
缺点:18 位 ID 过长

而涉及到程序上实现的分布式ID可看下面的文章
可通过UUID、雪花算法等

1. UUID

具体UUID是什么以及可看我之前的文章
java之UUID.randomUUID().toString()详细解析(全)
这里直接push过来

UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,主要是让让分布式系统中的所有元素,都能有唯一的辨识信息。

  • 为了提高效率,常用的UUID可缩短至16位比特数值
  • 使用UUID的一个好处是可以为新的服务创建新的标识符

==源码==
生成的UUID标识符16位具体信息如下:

  • (1)当前日期和时间,值第一部分与时间有关(如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同)
  • (2)时钟序列
  • (3)全局唯一的IEEE机器识别号(如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得)
 public static UUID randomUUID() {
       
        SecureRandom ng = Holder.numberGenerator;
        byte[] randomBytes = new byte[16];
        ng.nextBytes(randomBytes);
        randomBytes[6]  &= 0x0f;  /* clear version        */
        randomBytes[6]  |= 0x40;  /* set to version 4     */
        randomBytes[8]  &= 0x3f;  /* clear variant        */
        randomBytes[8]  |= 0x80;  /* set to IETF variant  */
        return new UUID(randomBytes);
}

==通过randomUUID().toString()生成==
随机生成UUID的标识符是UUID类中的方法
而UUID.randomUUID().toString()是javaJDK提供的一个自动生成主键的方法

public class ThreadDemo4 {
    public static void main(String[] args) {
        //创建ArrayList集合
      List<String> list = new ArrayList<>();

        for (int i = 0; i <30; i++) {

            new Thread(()->{
                //向集合添加内容
                list.add(UUID.randomUUID().toString());
                //从集合获取内容
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

代码截图
在这里插入图片描述

2. 数据库自增

前言中也有提及到数据库的方式,但是mycat的方式是放一定的序列到内存中,如果宕机之后,前面的序列不会更改,但是刚开始的序列号和之前的序列号会断开,也可以保证高可用

这种数据库的自增是通过数据库种的auto_increment,

用它来实现分布式服务风险比较大

3. 数据库集群

改进上面单个数据库自增的模式,因为怕宕机
那就多加入一个从机,实现主从复制或者是双主模式等

具体的规则就是设置一个起始值和步长值,实现两个mysql的不一样值
具体设置的方法为:

set @@auto_increment_offset = 1;     -- 起始值
set @@auto_increment_increment = 2;  -- 步长

但是如果突然加进来第三个服务器,前面两个序列号就都要重改,也比较麻烦

4. 数据库号段

从数据库批量的获取自增ID,每次从数据库取出一个号段范围,生成的自增ID加载到内存中

这与一开始前言所提及到的mycat比较相像
但是mycat是已经把一部分号段放置到内存中
而这里是在数据库取一部分,再放置到内存中,逻辑不一样

加入号段之后,在每个号段还要加上乐观锁(在数据库表中增加一个version字段),防止高并发的数据量
关于这部分乐观锁可看我之前的文章补充一些知识点,这里就不再赘述
java中各类锁的机制详细解析(全)

不会频繁的访问数据库,对数据库的压力小很多,因为有了缓存在内存中了

5. redis模式

利用redis的 incr命令实现ID的原子性自增

考虑到redis持久化的问题。redis有两种持久化方式RDB和AOF:

(1)RDB会定时打一个快照进行持久化,假如连续自增但redis没及时持久化,而这会Redis挂掉了,重启Redis后会出现ID重复的情况。

(2)AOF会对每条写命令进行持久化,即使Redis挂掉了也不会出现ID重复的情况,但由于incr命令的特殊性,会导致Redis重启恢复的数据时间过长。

6. 雪花算法

指定机器 & 同一时刻 & 某一并发序列,是唯一的。据此可生成一个64 bits的唯一ID(long)

组成部分(64bit)
1.第一位 占用1bit,其值始终是0,没有实际作用。
2.时间戳 占用41bit,精确到毫秒,总共可以容纳约69年的时间。
3.工作机器id 占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,做多可以容纳1024个节点。
4.序列号 占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID。

SnowFlake算法在同一毫秒内最多可以生成多少个全局唯一ID呢: 同一毫秒的ID数量 = 1024 X 4096 = 4194304

==最核心的是中间的10位工作机器ID的分配,做到自动生成workID,避免运维人员的去分配==

关于雪花算法详细分析可看这篇文章
理解分布式id生成算法SnowFlake

7. 其他

关于其他的自增,分布式ID,各大公司都有其一套的的算法
比如:

  • 滴滴出品(TinyID)

数据库中保存了可用的id号段,tinyid会将可用号段加载到内存中,之后生成id会直接内存中产生

  • 百度 (Uidgenerator)

百度的雪花算法是通过数据库来生成workID

  • 美团(Leaf)

美团是通过Zookeeper持久顺序节点的特性自动对snowflake节点配置wokerID

总结

方法 优点 缺点
UUID 1.容易实现,产生快。2.ID唯一。3.无需要中心化服务器。4.不会泄露商业机密 1.可读性过差。2.占用空间过多。3.影响数据库性能
数据库自增 实现简单,ID单调自增,数值类型查询速度快。 单点存在宕机风险,无法扛住高并发场景。
数据库集群 解决DB单点问题 不利于后续扩容,单点压力也会更大不适合高并发
数据库号段 解决单点压力 抗风险能力差,没有集群
redis中的icncr 原子性自增保证不重复 RDB挂掉后出现重复,AOF挂掉重启时间长
雪花算法 所有生成的id按时间趋势递增。不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。可以根据自身业务特性分配bit位,非常灵活。 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2天前
|
算法 关系型数据库 MySQL
分布式唯一ID生成:深入理解Snowflake算法在Go中的实现
在分布式系统中,确保每个节点生成的 ID 唯一且高效至关重要。Snowflake 算法由 Twitter 开发,通过 64 位 long 型数字生成全局唯一 ID,包括 1 位标识位、41 位时间戳、10 位机器 ID 和 12 位序列号。该算法具备全局唯一性、递增性、高可用性和高性能,适用于高并发场景,如电商促销时的大量订单生成。本文介绍了使用 Go 语言的 `bwmarrin/snowflake` 和 `sony/sonyflake` 库实现 Snowflake 算法的方法。
10 1
分布式唯一ID生成:深入理解Snowflake算法在Go中的实现
|
3月前
|
算法 Go
[go 面试] 雪花算法与分布式ID生成
[go 面试] 雪花算法与分布式ID生成
|
16天前
|
NoSQL 算法 关系型数据库
分布式 ID 详解 ( 5大分布式 ID 生成方案 )
本文详解分布式全局唯一ID及其5种实现方案,关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
分布式 ID 详解 ( 5大分布式 ID 生成方案 )
|
16天前
|
存储 缓存 监控
解决分布式系统演进过程中数据一致性问题的方法
【10月更文挑战第24天】解决分布式系统演进过程中数据一致性问题是一个复杂而又重要的任务。需要综合运用多种方法和技术,根据具体的系统需求和场景,选择合适的解决方案。同时,不断地进行优化和改进,以适应不断变化的分布式系统环境。
36 4
|
20天前
|
程序员
后端|一个分布式锁「失效」的案例分析
小猿最近很苦恼:明明加了分布式锁,为什么并发还是会出问题呢?
28 2
|
3月前
|
运维 安全
基于simulink的分布式发电系统自动重合闸的建模与仿真分析
本课题研究配电系统中分布式电源接入后的自动重合闸问题,着重分析非同期重合闸带来的冲击电流及其影响。通过Simulink搭建模型,仿真不同位置及容量的分布式电源对冲击电流的影响,并对比突发性和永久性故障情况。利用MATLAB2022a进行参数设置与仿真运行,结果显示非同期重合闸对系统安全构成挑战,需通过优化参数提升系统性能。
|
4月前
|
存储 NoSQL Java
通用快照方案问题之通过Sleuth进行耗时分析和链路优化如何解决
通用快照方案问题之通过Sleuth进行耗时分析和链路优化如何解决
42 0
|
4月前
|
消息中间件 Java Nacos
通用快照方案问题之通过Spring Cloud实现配置的自动更新如何解决
通用快照方案问题之通过Spring Cloud实现配置的自动更新如何解决
76 0
|
4月前
|
存储 算法 Java
分布式自增ID算法---雪花算法(SnowFlake)Java实现
分布式自增ID算法---雪花算法(SnowFlake)Java实现
271 0
|
4月前
|
设计模式 安全 NoSQL
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
63 0

热门文章

最新文章