唯一ID生成算法剖析
- 唯一性:生成的ID全局唯一,在特定范围内冲突概率极小
- 有序性:生成的ID按某种规则有序,便于数据库插入及排序
- 可用性:可保证高并发下的可用性
- 自主性:分布式环境下不依赖中心认证即可自行生成ID
- 安全性:不暴露系统和业务的信息
- 基于时间戳&时钟序列生成
- 基于名字空间/名字的散列值 (MD5/SHA1) 生成
- 基于随机数生成
- 多台机器不同初始值、同步长自增
- 批量缓存自增ID
- 时钟回拨解决方案
- 本文便分别对这些算法进行讲解及分析。
- 无需网络,单机自行生成
- 速度快,QPS高(支持100ns级并发)
- 各语言均有相应实现库供直接使用
- String存储,占空间,DB查询及索引效率低
- 无序,可读性差
- 根据实现方式不同可能泄露信息
1.UUID的格式
2.UUID版本
- 版本1 - 基于时间的UUID:主要依赖当前的时间戳及机器mac地址,因此可以保证全球唯一性
- 版本2 - 分布式安全的UUID:将版本1的时间戳前四位换为POSIX的UID或GID,很少使用
- 版本3 - 基于名字空间的UUID(MD5版):基于指定的名字空间/名字生成MD5散列值得到,标准不推荐
- 版本4 - 基于随机数的UUID:基于随机数或伪随机数生成,
- 版本5 - 基于名字空间的UUID(SHA1版):将版本3的散列算法改为SHA1
3.UUID各版本优缺点
- 优点:能基本保证全球唯一性
- 缺点:使用了Mac地址,因此会暴露Mac地址和生成时间
- 优点:能保证全球唯一性
- 缺点:很少使用,常用库基本没有实现
- 优点:不同名字空间或名字下的UUID是唯一的;相同名字空间及名字下得到的UUID保持重复。
- 缺点:MD5碰撞问题,只用于向后兼容,后续不再使用
- 优点:实现简单
- 缺点:重复几率可计算
- 优点:不同名字空间或名字下的UUID是唯一的;相同名字空间及名字下得到的UUID保持重复。
- 缺点:SHA1计算相对耗时
- 版本 1/2 适用于需要高度唯一性且无需重复的场景;
- 版本 3/5 适用于一定范围内唯一且需要或可能会重复生成UUID的环境下;
- 版本 4 适用于对唯一性要求不太严格且追求简单的场景。
4.UUID结构及生成规则
版本2 - 分布式安全的UUID:
- 版本3/5 - 基于名字空间的UUID (MD5/SHA1):
- 将命名空间 (如DNS、URL、OID等) 及名字转换为字节序列;
- 通过MD5/SHA1散列算法将上述字节序列转换为16字节哈希值 (MD5散列不再推荐,SHA1散列的20位只使用其15~00位);
- 将哈希值的 3~0 字节置于UUID的15~12位;
- 将哈希值的 5~4 字节置于UUID的11~10位;
- 将哈希值的 7~6 字节置于UUID的09~08位,并用相应版本号覆盖第9位的高4位 (同版本1位置);
- 将哈希值的 8 字节置于UUID的07位,并用相应变体值覆盖其高2位 (同版本1位置);
- 将哈希值的 9 字节置于UUID的06位 (原时钟序列位置);
- 将哈希值的 15~10 字节置于UUID的05~00位 (原节点值位置)。
- 版本4 - 基于随机数的UUID:
- 生成16byte随机值填充UUID。重复机率与随机数产生器的质量有关。若要避免重复率提高,必须要使用基于密码学上的假随机数产生器来生成值才行;
- 将变体值及版本号填到相应位置。
5.多版本伪码
// 版本 1 - 基于时间的UUID:
gen_uuid() { struct uuid uu; // 获取时间戳 get_time(&clock_mid, &uu.time_low); uu.time_mid = (uint16_t) clock_mid; // 时间中间位 uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; // 时间高位 & 版本号 // 获取时钟序列。在libuuid中,尝试取时钟序列+1,取不到则随机;在python中直接使用随机 get_clock(&uu.clock_seq);// 时钟序列+1 或 随机数 uu.clock_seq |= 0x8000;// 时钟序列位 & 变体值 // 节点值 char node_id[6]; get_node_id(node_id);// 根据mac地址等获取节点id uu.node = node_id; return uu;
} // 版本4 - 基于随机数的UUID:
gen_uuid() { struct uuid uu; uuid_t buf; random_get_bytes(buf, sizeof(buf));// 获取随机出来的uuid,如libuuid根据进程id、当日时间戳等进行srand随机 uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;// 变体值覆盖 uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;// 版本号覆盖 return uu;
} // 版本5 - 基于名字空间的UUID(SHA1版):
gen_uuid(name) { struct uuid uu; uuid_t buf; sha_get_bytes(name, buf, sizeof(buf));// 获取name的sha1散列出来的uuid uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;// 变体值覆盖 uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x5000;// 版本号覆盖 return uu;
}
(左滑查看完整代码)
- 并发性不好
- 数据库写压力大
- 数据库故障后不可使用
- 存在数量泄露风险
1. 数据库水平拆分,设置不同的初始值和相同的步长
- 根据扩容考虑决定步长
- 增加其他位标记区分扩容
2.批量生成一批ID
- 将ID生成交给少量服务器,并关闭时钟同步。
- 直接报错,交给上层业务处理。
- 如果回拨时间较短,在耗时要求内,比如5ms,那么等待回拨时长后再进行生成。
- 如果回拨时间很长,那么无法等待,可以匀出少量位(1~2位)作为回拨位,一旦时钟回拨,将回拨位加1,可得到不一样的ID,2位回拨位允许标记三次时钟回拨,基本够使用。如果超出了,可以再选择抛出异常。
- 要求生成全局唯一且不会重复ID,不关心顺序 —— 使用基于时间的UUID(如游戏聊天室中不同用户的身份ID)
- 要求生成唯一ID,具有名称不可变性,可重复生成 —— 使用基于名称哈希的UUID(如基于不可变信息生成的用户ID,若不小心删除,仍可根据信息重新生成同一ID)
- 要求生成有序且自然增长的ID —— 使用数据库自增ID(如各业务操作流水ID,高并发下可参考优化方案)
- 要求生成数值型无序定长ID —— 使用雪花算法(如对存储空间、查询效率、传输数据量等有较高要求的场景)
唯一ID生成算法剖析相关推荐
- node 生成随机头像_唯一ID生成算法剖析
引在业务开发中,大量场景需要唯一ID来进行标识:用户需要唯一身份标识:商品需要唯一标识:消息需要唯一标识:事件需要唯一标识-等等,都需要全局唯一ID,尤其是分布式场景下.唯一ID有哪些特性或者说要求呢 ...
- java 唯一id生成算法_唯一ID生成算法剖析
在业务开发中,大量场景需要唯一ID来进行标识:用户需要唯一身份标识:商品需要唯一标识:消息需要唯一标识:事件需要唯一标识-等等,都需要全局唯一ID,尤其是分布式场景下. 唯一ID有哪些特性或者说要求呢 ...
- 唯一ID生成算法剖析,看看这篇就够了
本文转载自腾讯技术工程 引 在业务开发中,大量场景需要唯一ID来进行标识:用户需要唯一身份标识:商品需要唯一标识:消息需要唯一标识:事件需要唯一标识-等等,都需要全局唯一ID,尤其是分布式场景下. 唯 ...
- c#随机数生成编号_忘掉 Snowflake,感受一下性能高出587倍的全局唯一ID生成算法...
今天我们来拆解 Snowflake 算法,同时领略百度.美团.腾讯等大厂在全局唯一 ID 服务方面做的设计,接着根据具体需求设计一款全新的全局唯一 ID 生成算法.这还不够,我们会讨论到全局唯一 ID ...
- 微信用户全局唯一标识_忘掉 Snowflake,感受一下性能高出587倍的全局唯一ID生成算法...
今天我们来拆解 Snowflake 算法,同时领略百度.美团.腾讯等大厂在全局唯一 ID 服务方面做的设计,接着根据具体需求设计一款全新的全局唯一 ID 生成算法.这还不够,我们会讨论到全局唯一 ID ...
- snowflake做主键 自增_忘掉 Snowflake,感受一下性能高出 587 倍的全局唯一 ID 生成算法...
今天我们来拆解 Snowflake 算法,同时领略百度.美团.腾讯等大厂在全局唯一 ID 服务方面做的设计,接着根据具体需求设计一款全新的全局唯一 ID 生成算法.这还不够,我们会讨论到全局唯一 ID ...
- mysql序列号生成_忘掉 Snowflake,感受一下性能高出587倍的全局唯一ID生成算法
今天我们来拆解 Snowflake 算法,同时领略百度.美团.腾讯等大厂在全局唯一 ID 服务方面做的设计,接着根据具体需求设计一款全新的全局唯一 ID 生成算法.这还不够,我们会讨论到全局唯一 ID ...
- 忘掉 Snowflake,感受一下性能高出587倍的全局唯一ID生成算法
今天我们来拆解 Snowflake 算法,同时领略百度.美团.腾讯等大厂在全局唯一 ID 服务方面做的设计,接着根据具体需求设计一款全新的全局唯一 ID 生成算法.这还不够,我们会讨论到全局唯一 ID ...
- 微信用户全局唯一标识_分布式系统的唯一ID生成算法对比
在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识. 那么如何实现全局唯一id呢?有以下几种方案. (1)方案一:独立数据库自增id 这个方案就是说你的系统每次要生成一个id,都是往一个独立库 ...
最新文章
- YOLO算法史上最全综述:从YOLOv1到YOLOv5
- flaskr 报错及其修改
- Github上Pandas,Numpy和 Scipy三个库中20个最常用的函数
- java final 方法重载_java方法重载和覆写的定义,static和final修饰符的讲解,java面试题...
- 利用Android Camera2 的照相机api 实现 实时的图像采集与预览
- 黑马程序员-面向对象-06天-5(单例设计模式)
- Docker-Compose快速搭建Oracle-11G系统
- 学习腾讯的hover效果
- 软件发布的版本缩写含义RC 、RTM
- MEF 编程指南(二):定义可组合部件和契约
- 编程实现二叉树的遍历
- MIDAS分布应用程序中的几个问题
- [实操记录]mysql5.7如何恢复被删除数据
- Cobbler自动化安装系统2
- spring-aop常用切点表达式
- 删除 Windows 文件资源管理器左侧 OneDrive 图标
- Linux 软中断机制分析
- PostgreSQL数据库统计信息——examine_attribute单列预分析
- 2018暑假集训Day1
- R-第七章|因子分析
热门文章
- 有什么办法可以预防网页被劫持
- ES7、ES8、ES9、ES10、ES11 新特性 总结
- 斐讯n1遥控器app(支持休眠和唤醒)——WiFi篇
- 园区3D可视化三维展示系统解决方案
- OBS录屏软件无法打开的问题,无法捕获到游戏画面的问题
- 倍福--运动中修改速度
- 将毫秒值(currentTimeMillis)转换为(年-月-日 时-分-秒)的形式,只需一行代码
- js 微信公众号开发chooseWXPay:fail, the permission value is offline verifying
- 广东高考成绩及录取分数线揭晓
- LabVIEW代码中常见的错误