百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

浅谈几种常见的分布式ID

wptr33 2025-03-05 22:04 24 浏览

在分布式环境下,如何对某对象做唯一标识是个很常规的问题。本文讨论几种常见做法,供大家参考。

1. UUID
UUID是可以生成时间、空间上都独一无二的值,其本质是随机+规则组合而成的。即使在两个独立的服务器上生成UUID,其预期值也是不同的。以MySQL为例,说明下UUID。

格式

在MySQL中,UUID值是一个128位的数字,表示为以下格式的十六进制数字的utf8字符串:
aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee。其得到的随机值由5个部分组成,且分隔符位为:中划线。其各部分含义如下:


前三组值是时间戳换算过来的;
第四组值是暂时性保持时间戳的唯一性。例如,使用夏令时;
第五组值是一个IEE 802的节点标识值,它是空间上唯一的。若后者不可用,则用一个随机数字替换。假如主机没有网卡,或者我们不知道如何在某系统下获得机器地址,则空间唯一性就不能得到保证,即使这样出现重复值的几率还是非常小的。


在MySQL环境中多次调用或执行得到的后两组值相同,若把mysqld服务器关闭,重新启动之后,会发现第四组的组与未重启前的值发生变化,然后一直不变化,只要重新启动mysqld服务就会发生变化。另外,对于同一台机器,第五组值始终不会发生变化。

优点

使用UUID作为主键具有以下优点:

UUID值在表,数据库甚至在服务器上都是唯一的,允许您从不同数据库合并行或跨服务器分发数据库。

UUID值不会公开有关数据的信息,因此在URL中使用更安全。

可以在避免往返数据库服务器的任何地方生成UUID值。它也简化了应用程序中的逻辑。

缺点

除了优势之外,UUID值也存在一些缺点:

存储UUID值(16字节)比整数(4字节)或甚至大整数(8字节)占用更多的存储空间。

调试似乎更加困难,想象一下WHERE id ='
9d6212cf-72fc-11e7-bdf0-f0def1e6646c'和WHERE id = 10哪个舒服一点?


使用UUID值可能会导致性能问题,因为它们的大小和没有被排序。

数据库案例:MySQL

在MySQL中,就内置了对UUID的支持。在使用上需注意若干问题。

作为主键问题

UUID()函数产生的值,并不适合作为InnoDB引擎表的主键。因为格式无序,作为索引组织表存储会带来管理上的不小开销。

格式问题

在MySQL中,可以使用UUID()来生成主键,但是用MySQL的UUID()函数 ,生成的UUID是36位的,其中包含32个字符以及4个分隔符(-),往往这个分隔符对我们来说是没有用的,可以使用MySQL自带的REPLACE函数去掉分隔符。

内置函数支持

在MySQL中,可以以紧凑格式(BINARY)存储UUID值,并通过以下功能显示人机可读格式(VARCHAR):UUID_TO_BIN、BIN_TO_UUID、IS_UUID。需要注意,UUID_TO_BIN(),BIN_TO_UUID()和IS_UUID()函数仅在MySQL 8.0或更高版本中可用。

- UUID_TO_BIN()函数将UUID从人类可读格式(VARCHAR)转换成用于存储的紧凑格式(BINARY)格式

- BIN_TO_UUID()函数将UUID从紧凑格式(BINARY)转换为人类可读格式(VARCHAR)

- IS_UUID()函数则可用来判断参数是有效的字符串格式UUID。


2. NanoID

UUID 是软件开发中最常用的通用标识符之一。然而,在过去的几年里,其他的竞品挑战了它的存在。其中,NanoID 是 UUID 的主要竞争对手之一。但是,这两者之间的主要区别很简单。它归结为键所使用的字母表。由于 NanoID 使用比 UUID 更大的字母表,因此较短的 ID 可以用于与较长的 UUID 相同的目的。
优点

更小

NanoID 只有 108 个字节那么大。与 UUID 不同,NanoID 的大小要小 4.5 倍,并且没有任何依赖关系。此外,大小限制已用于将大小从另外 35% 减小。大小减少直接影响数据的大小。例如,使用 NanoID 的对象小而紧凑,能够用于数据传输和存储。随着应用程序的增长,这些数字变得明显起来。

更安全

在大多数随机生成器中,它们使用不安全的 Math.random()。但是,NanoID 使用 crypto module 和 Web Crypto API,意味着 NanoID 更安全。此外,NanoID 在 ID 生成器的实现过程中使用了自己的算法,称为 统一算法,而不是使用“随机 % 字母表” random % alphabet。

更快

NanoID既快速又紧凑,NanoID 比 UUID 快 60%。与 UUID 字母表中的 36 个字符不同,NanoID 只有 21 个字符。

更多语言

NanoID 支持 14 种不同的编程语言,它们分别是:C#、C++、Clojure 和 ClojureScript、Crystal、Dart & Flutter、Deno、Go、Elixir、Haskell、Janet、Java、Nim、Perl、PHP、带字典的 Python、Ruby、Rust、Swift。

更好兼容性

它还支持 PouchDB、CouchDB WebWorkers、Rollup 以及 React 和 Reach-Native 等库。我们可以使用 npx nanoid 在终端中获得唯一 ID。在 JavaScript 中使用 NanoID 唯一的要求是要先安装 NodeJS。

自定义字母

NanoID 的另一个现有功能是它允许开发人员使用自定义字母表。我们可以更改文字或 id 的大小。在下面的示例中,我将自定义字母表定义为 ABCDEF1234567890,并将 Id 的大小定义为 12。

import { customAlphabet } from 'nanoid';

const nanoid = customAlphabet('ABCDEF1234567890', 12);

model.id = nanoid();

没有第三方依赖

由于 NanoID 不依赖任何第三方依赖,随着时间的推移,它能够变得更加稳定自治。从长远来看,这有利于优化包的大小,并使其不太容易出现依赖项带来的问题。

数据库案例-ShardingSphere

原生数据库产品,大多没有支持NanoID,但可通过外部方式引用进来。例如在开源项目 Apache ShardingSphere 中可通过规则的配置,在其分片表中使用 NanoID作为主键生成器。参考如下配置

CREATE SHARDING TABLE RULE t_order(

RESOURCES(ds_3307,ds_3308),

SHARDING_COLUMN=order_id,TYPE(NAME=hash_mod,PROPERTIES("sharding-count"=4)),

KEY_GENERATE_STRATEGY(COLUMN=order_id,TYPE(NAME=NanoID,PROPERTIES("worker-id"=123)))

);

CREATE TABLE t_order (


user_id int NOT NULL,

status varchar(50) DEFAULT NULL,

PRIMARY KEY (order_id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3. SnowFlake

分布式系统中ID生成方案,比较简单的是UUID(Universally Unique Identifier,通用唯一识别码),但是其存在两个明显的弊端:一、UUID是128位的,长度过长;二、UUID是完全随机的,无法生成递增有序的UUID。而现在流行的基于 Snowflake 雪花算法的ID生成方案就可以很好地解决了UUID存在的这两个问题。

原理

Snowflake 雪花算法,由Twitter提出并开源,可在分布式环境下用于生成唯一ID的算法。该算法生成的是一个64位的ID。在同一个进程中,它首先是通过时间位保证不重复,如果时间相同则是通过序列位保证。同时由于时间位是单调递增的,且各个服务器如果大体做了时间同步,那么生成的主键在分布式环境可以认为是总体有序的,这就保证了对索引字段的插入的高效性。例如 MySQL 的 Innodb 存储引擎的主键。

格式
使用雪花算法生成的主键,二进制表示形式包含 4 部分,从高位到低位分表为:1bit 符号位、41bit 时间戳位、10bit 工作进程位以及 12bit 序列号位。

符号位(1bit)

预留的符号位,恒为零。

时间戳位(41bit)

41 位的时间戳可以容纳的毫秒数是 2 的 41 次幂,一年所使用的毫秒数是:365 * 24 * 60 * 60 * 1000。通过计算可知:Math.pow(2, 41) / (365 * 24 * 60 * 60 * 1000L); 结果约等于 69.73 年。Apache ShardingSphere 的雪花算法的时间纪元从 2016 年 11 月 1 日零点开 始,可以使用到 2086 年,相信能满足绝大部分系统的要求。

工作进程位(10bit)

该标志在 Java 进程内是唯一的,如果是分布式应用部署应保证每个工作进程的 id 是不同的。该值默认为0,可通过属性设置。

序列号位(12bit)

该序列是用来在同一个毫秒内生成不同的 ID。如果在这个毫秒内生成的数量超过 4096 (2 的 12 次幂),那么生成器会等待到下个毫秒继续生成。

优点

使用SnowFlake的优点是其空间占用更小,且具备一定有序性,这对于类似MySQL数据库是比较友好的。

缺点

因为其生成策略需参考当前时间,当服务器时钟回拨会导致产生重复序列,因此默认分布式主键生成器提供了一个最大容忍的时钟回拨毫秒数。如果时钟回拨的时间超过最大容忍的毫秒数阈值,则程序报错;如果在可容忍的范围内,默认分布式主键生成器会等待时钟同步到最后一次主键生成的时间后再继续工作。最大容忍的时钟回拨毫秒数的默认值为 0,可通过属性设置。

数据库案例-ShardingSphere

原生数据库产品,大多没有支持SnowFlake,但可通过外部方式引用进来。例如在开源项目 Apache ShardingSphere 中可通过规则的配置,在其分片表中使用 SnowFlake作为主键生成器。参考如下配置

CREATE SHARDING TABLE RULE t_order(

RESOURCES(ds_3307,ds_3308),

SHARDING_COLUMN=order_id,TYPE(NAME=hash_mod,PROPERTIES("sharding-count"=4)),

KEY_GENERATE_STRATEGY(COLUMN=order_id,TYPE(NAME= Snowflake,PROPERTIES("worker-id"=123)))

);

CREATE TABLE t_order (

order_id varchar(50) NOT NULL,

user_id int NOT NULL,

status varchar(50) DEFAULT NULL,

PRIMARY KEY (order_id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

相关推荐

oracle数据导入导出_oracle数据导入导出工具

关于oracle的数据导入导出,这个功能的使用场景,一般是换服务环境,把原先的oracle数据导入到另外一台oracle数据库,或者导出备份使用。只不过oracle的导入导出命令不好记忆,稍稍有点复杂...

继续学习Python中的while true/break语句

上次讲到if语句的用法,大家在微信公众号问了小编很多问题,那么小编在这几种解决一下,1.else和elif是子模块,不能单独使用2.一个if语句中可以包括很多个elif语句,但结尾只能有一个else解...

python continue和break的区别_python中break语句和continue语句的区别

python中循环语句经常会使用continue和break,那么这2者的区别是?continue是跳出本次循环,进行下一次循环;break是跳出整个循环;例如:...

简单学Python——关键字6——break和continue

Python退出循环,有break语句和continue语句两种实现方式。break语句和continue语句的区别:break语句作用是终止循环。continue语句作用是跳出本轮循环,继续下一次循...

2-1,0基础学Python之 break退出循环、 continue继续循环 多重循

用for循环或者while循环时,如果要在循环体内直接退出循环,可以使用break语句。比如计算1至100的整数和,我们用while来实现:sum=0x=1whileTrue...

Python 中 break 和 continue 傻傻分不清

大家好啊,我是大田。今天分享一下break和continue在代码中的执行效果是什么,进一步区分出二者的区别。一、continue例1:当小明3岁时不打印年龄,其余年龄正常循环打印。可以看...

python中的流程控制语句:continue、break 和 return使用方法

Python中,continue、break和return是控制流程的关键语句,用于在循环或函数中提前退出或跳过某些操作。它们的用途和区别如下:1.continue(跳过当前循环的剩余部分,进...

L017:continue和break - 教程文案

continue和break在Python中,continue和break是用于控制循环(如for和while)执行流程的关键字,它们的作用如下:1.continue:跳过当前迭代,...

作为前端开发者,你都经历过怎样的面试?

已经裸辞1个月了,最近开始投简历找工作,遇到各种各样的面试,今天分享一下。其实在职的时候也做过面试官,面试官时,感觉自己问的问题很难区分候选人的能力,最好的办法就是看看候选人的github上的代码仓库...

面试被问 const 是否不可变?这样回答才显功底

作为前端开发者,我在学习ES6特性时,总被const的"善变"搞得一头雾水——为什么用const声明的数组还能push元素?为什么基本类型赋值就会报错?直到翻遍MDN文档、对着内存图反...

2023金九银十必看前端面试题!2w字精品!

导文2023金九银十必看前端面试题!金九银十黄金期来了想要跳槽的小伙伴快来看啊CSS1.请解释CSS的盒模型是什么,并描述其组成部分。答案:CSS的盒模型是用于布局和定位元素的概念。它由内容区域...

前端面试总结_前端面试题整理

记得当时大二的时候,看到实验室的学长学姐忙于各种春招,有些收获了大厂offer,有些还在苦苦面试,其实那时候的心里还蛮忐忑的,不知道自己大三的时候会是什么样的一个水平,所以从19年的寒假放完,大二下学...

由浅入深,66条JavaScript面试知识点(七)

作者:JakeZhang转发链接:https://juejin.im/post/5ef8377f6fb9a07e693a6061目录由浅入深,66条JavaScript面试知识点(一)由浅入深,66...

2024前端面试真题之—VUE篇_前端面试题vue2020及答案

添加图片注释,不超过140字(可选)1.vue的生命周期有哪些及每个生命周期做了什么?beforeCreate是newVue()之后触发的第一个钩子,在当前阶段data、methods、com...

今年最常见的前端面试题,你会做几道?

在面试或招聘前端开发人员时,期望、现实和需求之间总是存在着巨大差距。面试其实是一个交流想法的地方,挑战人们的思考方式,并客观地分析给定的问题。可以通过面试了解人们如何做出决策,了解一个人对技术和解决问...