首页 > 其他分享 >分布式ID

分布式ID

时间:2023-12-09 23:23:42浏览次数:36  
标签:UUID 数据库 生成 号段 ID 分布式

1.分布式ID

什么是 ID?

  日常开发中,我们需要对系统中的各种数据使用 ID 唯一表示,比如用户 ID 对应且仅对应一个人,商品 ID 对应且仅对应一件商品,订单 ID 对应且仅对应一个订单。

  简单来说,ID 就是数据的唯一标识

什么是分布式 ID?

  分布式 ID 是分布式系统下的 ID。

举一个例子:

  在分库之后, 数据遍布在不同服务器上的数据库,数据库的自增主键已经没办法满足生成的主键唯一了。我们如何为不同的数据节点生成全局唯一主键呢?

  这个时候就需要生成分布式 ID了。

分布式 ID 需要满足哪些要求?

一个最基本的分布式 ID 需要满足下面这些要求:

  • 全局唯一:ID 的全局唯一性肯定是首先要满足的!
  • 高性能:分布式 ID 的生成速度要快,对本地资源消耗要小。
  • 高可用:生成分布式 ID 的服务要保证可用性无限接近于 100%。
  • 方便易用:拿来即用,使用方便,快速接入!

一个比较好的分布式 ID 还应保证:

  • 安全:ID 中不包含敏感信息。
  • 有序递增:如果要把 ID 存放在数据库的话,ID 的有序性可以提升数据库写入速度。并且,很多时候 ,我们还很有可能会直接通过 ID 来进行排序。
  • 有具体的业务含义:生成的 ID 如果能有具体的业务含义,可以让定位问题以及开发更透明化(通过 ID 就能确定是哪个业务)。
  • 独立部署:也就是分布式系统单独有一个发号器服务,专门用来生成分布式 ID。这样就生成 ID 的服务可以和业务相关的服务解耦。不过,这样同样带来了网络调用消耗增加的问题。总的来说,如果需要用到分布式 ID 的场景比较多的话,独立部署的发号器服务还是很有必要的。
 

2.分布式 ID 常见解决方案

(1)数据库

数据库主键自增

  这种方式就比较简单直白了,就是通过关系型数据库的自增主键产生来唯一的 ID。

  • 优点:实现起来比较简单、ID 有序递增、存储消耗空间小
  • 缺点:支持的并发量不大、存在数据库单点问题(可以使用数据库集群解决,不过增加了复杂度)、ID 没有具体业务含义、安全问题(比如根据订单 ID 的递增规律就能推算出每天的订单量,商业机密啊! )、每次获取 ID 都要访问一次数据库(增加了对数据库的压力,获取速度也慢)
MySQL 可以修改自增的起始值和每次增长的步长
假设我有 db1、db2 和 db3,我就可以分别设置这三个库中表的自增起始值为 1、2、3,
然后自增步长都是 3,这样就可以实现自增了。

数据库号段模式

  数据库主键自增这种模式,每次获取 ID 都要访问一次数据库,ID 需求比较大的时候,肯定是不行的。

  如果我们可以批量获取,然后存在在内存里面,需要用到的时候,直接从内存里面拿就舒服了!这也就是我们说的 基于数据库的号段模式来生成分布式 ID。

  数据库的号段模式也是目前比较主流的一种分布式 ID 生成方式。像滴滴开源的Tinyid就是基于这种方式来做的。不过,TinyId 使用了双号段缓存、增加多 db 支持等方式来进一步优化。

  • 优点:ID 有序递增、存储消耗空间小、避免了每次生成ID都要访问数据库,提高性能
  • 缺点:存在数据库单点问题(可以使用数据库集群解决,不过增加了复杂度)、ID 没有具体业务含义、安全问题(比如根据订单 ID 的递增规律就能推算出每天的订单量,商业机密啊! )

NoSQL(Redis)

  一般情况下,NoSQL 方案使用 Redis 多一些。我们通过 Redis 的 incr 命令即可实现对 id 原子顺序递增。

  为了提高可用性和并发,我们可以使用 Redis Cluster。也可以使用开源的 Redis 集群方案Codis.   除了高可用和并发之外,我们知道 Redis 基于内存,我们需要持久化数据,避免重启机器或者机器故障后数据丢失。Redis 支持两种不同的持久化方式:快照(snapshotting,RDB)只追加文件(append-only file, AOF)。 并且,Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。
  • 优点:性能不错并且生成的 ID 是有序递增的
  • 缺点:和数据库主键自增方案的缺点类似

(2)算法

UUID

  UUID 是 Universally Unique Identifier(通用唯一标识符) 的缩写。UUID 包含 32 个 16 进制数字(8-4-4-4-12)。JDK 就提供了现成的生成 UUID 的方法,一行代码就行了。

UUID.randomUUID()

  不同的版本对应的 UUID 的生成规则是不同的。

版本 1 : UUID 是根据时间和节点 ID(通常是 MAC 地址)生成;
版本 2 : UUID 是根据标识符(通常是组或用户 ID)、时间和节点 ID 生成;
版本 3、版本 5 : 版本 5 - 确定性 UUID 通过散列(hashing)名字空间(namespace)标识符和名称生成;
版本 4 : UUID 使用随机性
  • 优点:可以做到全局唯一、生成速度比较快、简单易用
  • 缺点:存储消耗空间大(32 个字符串,128 位)、 不安全(基于 MAC 地址生成 UUID 的算法会造成 MAC 地址泄露)、无序(非自增)、没有具体业务含义、需要解决重复 ID 问题(当机器时间不对的情况下,可能导致会产生重复 ID)

Snowflake(雪花算法)

  Snowflake 是 Twitter 开源的分布式 ID 生成算法。Snowflake 由 64 bit 的二进制数字组成,每一部分存储的数据都有特定的含义:

  • sign(1bit):符号位(标识正负),始终为 0,代表生成的 ID 为正数。
  • timestamp (41 bits):一共 41 位,用来表示时间戳,单位是毫秒,可以支撑 2 ^41 毫秒(约 69 年)
  • datacenter id + worker id (10 bits):一般来说,前 5 位表示机房 ID,后 5 位表示机器 ID(实际项目中可以根据实际情况调整)。这样就可以区分不同集群/机房的节点。
  • sequence (12 bits):一共 12 位,用来表示序列号。 序列号为自增值,代表单台机器每毫秒能够产生的最大 ID 数(2^12 = 4096),也就是说单台机器每毫秒最多可以生成 4096 个 唯一 ID。

  在实际项目中,我们一般也会对 Snowflake 算法进行改造,最常见的就是在 Snowflake 算法生成的 ID 中加入业务类型信息。

  • 优点:生成速度比较快、生成的 ID 有序递增、比较灵活(可以对 Snowflake 算法进行简单的改造比如加入业务 ID)
  • 缺点:需要解决重复 ID 问题(ID 生成依赖时间,在获取时间的时候,可能会出现时间回拨的问题,也就是服务器上的时间突然倒退到之前的时间,进而导致会产生重复 ID)、依赖机器 ID 对分布式环境不友好(当需要自动启停或增减机器时,固定的机器 ID 可能不够灵活)。
解决时间回拨:使用最后一次时间戳:
  当检测到系统时钟发生回拨时,可以通过记录下当前毫秒内最后一次生成的时间戳,然后在回拨结束后使用这个时间戳继续生成ID。
  这样做的好处是尽可能保证了ID的唯一性,但可能会引入一定量的时间偏移。而且需要保证系统在时钟回拨结束后尽快切换回正确的时间。

(3)开源框架

# UidGenerator(百度)

  UidGenerator是百度开源的一款基于 Snowflake(雪花算法)的唯一 ID 生成器。不过,UidGenerator 对 Snowflake(雪花算法)进行了改进,生成的唯一 ID 组成如下:

 自 18 年后,UidGenerator 就基本没有再维护了。

# Leaf(美团)

  Leaf是美团开源的一个分布式 ID 解决方案 。

  Leaf 提供了 号段模式Snowflake(雪花算法) 这两种模式来生成分布式 ID。并且,它支持双号段,还解决了雪花 ID 系统时钟回拨问题。不过,时钟问题的解决需要弱依赖于 Zookeeper(使用 Zookeeper 作为注册中心,通过在特定路径下读取和创建子节点来管理 workId) 。

  Leaf 的诞生主要是为了解决美团各个业务线生成分布式 ID 的方法多种多样以及不可靠的问题。

  Leaf 对原有的号段模式进行改进,比如它这里增加了双号段避免获取 DB 在获取号段的时候阻塞请求获取 ID 的线程。简单来说,就是我一个号段还没用完之前,我自己就主动提前去获取下一个号段。

# Tinyid(滴滴)

  Timyid是滴滴开源的一款基于数据库号段模式的唯一 ID 生成器。

Tinyid 有哪些亮点呢?

  基于数据库号段模式的简单架构方案,在这种架构模式下,我们通过 HTTP 请求向发号器服务申请唯一 ID。负载均衡 router 会把我们的请求送往其中的一台 tinyid-server。

这种方案有什么问题呢?主要有 2 个问题:

  • 获取新号段的情况下,程序获取唯一 ID 的速度比较慢。
  • 需要保证 DB 高可用,这个是比较麻烦且耗费资源的。

除此之外,HTTP 调用也存在网络开销。

Tinyid 的原理比较简单,其架构如下图所示:

相比于基于数据库号段模式的简单架构方案,Tinyid 方案主要做了下面这些优化:

  • 双号段缓存:为了避免在获取新号段的情况下,程序获取唯一 ID 的速度比较慢。 Tinyid 中的号段在用到一定程度的时候,就会去异步加载下一个号段,保证内存中始终有可用号段。
  • 增加多 db 支持:支持多个 DB,并且,每个 DB 都能生成唯一 ID,提高了可用性。
  • 增加 tinyid-client:纯本地操作,无 HTTP 请求消耗,性能和可用性都有很大提升。

Tinyid 的优缺点这里就不分析了,结合数据库号段模式的优缺点和 Tinyid 的原理就能知道。

# IdGenerator(个人)

  IdGenerator也是一款基于 Snowflake(雪花算法)的唯一 ID 生成器。

IdGenerator 有如下特点:

  • 生成的唯一 ID 更短;
  • 兼容所有雪花算法(号段模式或经典模式,大厂或小厂);
  • 原生支持 C#/Java/Go/C/Rust/Python/Node.js/PHP(C 扩展)/SQL/ 等语言,并提供多线程安全调用动态库(FFI);
  • 解决了时间回拨问题,支持手工插入新 ID(当业务需要在历史时间生成新 ID 时,用本算法的预留位能生成 5000 个每秒);
  • 不依赖外部存储系统;
  • 默认配置下,ID 可用 71000 年不重复。

IdGenerator 生成的唯一 ID 组成如下:

  • timestamp (位数不固定):时间差,是生成 ID 时的系统时间减去 BaseTime(基础时间,也称基点时间、原点时间、纪元时间,默认值为 2020 年) 的总时间差(毫秒单位)。初始为 5bits,随着运行时间而增加。如果觉得默认值太老,你可以重新设置,不过要注意,这个值以后最好不变。
  • worker id (默认 6 bits): 机器 id,机器码,最重要参数,是区分不同机器或不同应用的唯一 ID,最大值由 WorkerIdBitLength(默认 6)限定。如果一台服务器部署多个独立服务,需要为每个服务指定不同的 WorkerId。
  • sequence (默认 6 bits):序列数,是每毫秒下的序列数,由参数中的 SeqBitLength(默认 6)限定。增加 SeqBitLength 会让性能更高,但生成的 ID 也会更长。

标签:UUID,数据库,生成,号段,ID,分布式
From: https://www.cnblogs.com/cjhtxdy/p/17891922.html

相关文章

  • mysql set column sha2(uuid(),512) as column default value via trigger
    mysql>showcreatetablet3;+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------......
  • 如何不是用 width 和 height 控制 svg 的渲染大小?
    除了使用width和height属性控制SVG的渲染大小外,还可以使用以下方法:使用CSS样式:可以通过设置CSS的width和height属性来控制SVG的渲染大小。例如,设置SVG元素的样式为width:100px;height:100px;。使用viewBox属性:viewBox属性定义了SVG的可视区域,在该区域内进行缩放和裁剪。可以通过......
  • GridFS上传&下载文件
     首先我们先说上传文件到GridFs;上传文件到GridFs上相对比较简单,只需要GridFsTemplate的store方法;    1.上传文件        如果文件为String类型则我们需要将其转化为inputstream的流对象,然后在调用store方法,如果需要返回字符串类型则可以使用tostring方法;InputStre......
  • [Codeforces] CF1703E Mirror Grid
    CF1703EMirrorGrid题意给定一个\(n\timesn\(n\le100)\)的01矩形,求至少修改多少次后能使矩形旋转0°,90°,180°,270°后所形成的矩形都完全相同。思路吸纳分为两种情况讨论:\(n\)为奇数那么会出现这种情况:(以\(5\times5\)为例)如上图,我们就可以将其分为五个部分,每个......
  • Android OpenGl ES 3.0 学习笔记
    titleOpenGLES3.0DrawTriangleJava->JNI:(1)Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetRenderType(100,100)Java->MyGLRenderContext:GetInstance()Java->MyGLRenderContext:SetRenderType(100)noterightofNativeTriangle:GLBaseSample......
  • 个人使用的IDEA插件,强烈推荐
    1google-java-format代码自动格式化简介:google-java-format插件可以帮助我们不通过对应的快捷键就可以实现特定方式下自动格式化代码。2Translation简介:翻译插件,支持google翻译、百度翻译、有道翻译。使用:快捷键Ctrl+Shift+O3KeypromoterX简介:KeyPromoterX是一个提示插件......
  • IntelliJ IDEA下载安装,以及关联gitee
    https://www.jetbrains.com.cn/ 点击下载IntelliJIDEAUltimate旗舰版(收费)IntelliJIDEACommunity社区版(免费)安装根据需要选择选项 在设置中找到插件,安装gitee插件。  ......
  • Meta、Midjourney、DALL-E 3、 Adob​​e Firefly 绘图对比
    Meta刚刚推出了新的人工智能图像生成器。但它有多好呢?我将其与Midjourney、DALL-E3和AdobeFirefly的10个图像类别进行了比较。结果如下:写实照片提示:一位戴着蓝色围巾的快乐年轻女子在圣托里尼度假、白色建筑和蓝色圆顶的特写镜头2.风景照片提示:无人机航拍波拉波拉岛令人惊......
  • Solidity基本语法学习3
    文档:https://solidity-by-example.org/视频教程:https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p说明:本文内容:Enum,struct,datalocation,function,ViewandPureFunction,ErrorEnum(枚举)Solidity支持枚举,这对modelch......
  • Unreliable Guide To Locking 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/kernel-hacking/locking.htmlRusty'sRemarkablyUnreliableGuidetoKernelLocking作者RustyRussell简介欢迎阅读Rusty'sRemarkablyUnreliableGuidetoKernelLockingissues。本文档描述了LinuxKernel2.6中的锁定系统......