浅谈postgre-sql uuid生成方法的细节

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 浅谈postgre-sql uuid生成方法的细节

前言


    最近在工作中编写业务sql的时候,突然对于gen_random_uuid() 这个方法比较好奇,他在高并发的情况下是否拥有强一致性的特点(就是保证主键唯一性),趁着感兴趣研究了一波,发现有不少有意思的东西可以讨论,所以出了这篇文章来聊聊。


前提条件


我估计很多读者根本不知道postgreSql是啥玩意,个人起初接触这个数据库也很别扭,并且这个名字很难记,所以业内人士一般叫读这块数据库为:post-gres-s-q-l,个人比较习惯叫做 pg-sql,关于这一款数据个人认为几个比较突出的特点:

  1. 完全开源,基于社区维护,并且社区较为活跃。
  2. NoSQL :JSON,JSONB,XML,HStore原生支持,NoSQL数据库的外部数据包装器
  3. 自从mysql被甲骨文收购之后,mysql的原作者也有参与其中,可以看到不少mysql的影子,比如OLTP和MVCC的实现。

然而遗憾的是虽然postgresql看起来全面强于mysql但是不如mysql流行,并且mysql看上去是有很多令人诟病的历史遗留问题,但是依然不可否认他依然是现在的主流数据库。好了关于pg-sql这款数据库就唠叨到这里,今天的主题不是介绍这个数据库,所以我们来看下重点关于postgre-sql生成uuid的方法。


文章目的


    关于本文,我们将会讨论下面几个话题:

  • Gen_random_uuid()怎么来的?

PostgreSQL 13: 新增内置函数Gen_random_uuid()生成UUID数据,换句话说这个版本之前需要用手动的安装形式

  • uuid_generate_v4() 有没有可能重复?

答案是肯定的,哪怕是sql原始的gen_randowm_uuid方法也是存在重复的可能性的,但是存在某些“特殊条件”,下面来一起探讨一下原因。

  • 对比gen_randowm_uuid()函数和uuid_generate_v4函数的实现差异。

差异主要是生成随机数的方式上,其他工作基本一致。


1. Gen_random_uuid()怎么来的?



    如果postgre-sql的版本使用的是13之前,会抛出下面的问题:


function gen_random_uuid() does not exist


如果想要能够使用此方法,需要使用如下的命令,也就是使用 pgcrypto :


CREATE EXTENSION pgcrypto;


下面是postgresql-sql 12版本,会出现如下的提示。


# SELECT gen_random_uuid();
ERROR:  function gen_random_uuid() does not exist
LINE 1: select gen_random_uuid();
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
# CREATE EXTENSION pgcrypto;
CREATE EXTENSION
# SELECT gen_random_uuid();
           gen_random_uuid            
--------------------------------------
 19a12b49-a57a-4f1e-8e66-152be08e6165
(1 row)


但是需要注意的是13版本添加的并不是这个库,而是依赖于OSSP库的uuid函数。其实就是gen_random_uuid_v4()这个函数,下面我们来看下这个函数的介绍。


1.1 gen_random_uuid_v4()官方介绍


函数有什么作用不必多说,下面是关于官方的介绍:


We create a uuid_t object just once per session and re-use it for all  
  operations in this module.  OSSP UUID caches the system MAC address and  
  other state in this object.  Reusing the object has a number of benefits:  
 saving the cycles needed to fetch the system MAC address over and over,  
 reducing the amount of entropy we draw from /dev/urandom, and providing a  
 positive guarantee that successive generated V1-style UUIDs don't collide.  
 (On a machine fast enough to generate multiple UUIDs per microsecond,  
  or whatever the system's wall-clock resolution is, we'd otherwise risk  
  collisions whenever random initialization of the uuid_t's clock sequence  
  value chanced to produce duplicates.)


如果看不懂,下面是谷歌翻译之后的介绍:


我们每个会话只创建一个 uuid_t 对象,并为所有人重新使用它本模块中的操作。 OSSP UUID 缓存系统 MAC 地址和此对象中的其他状态。 
重用对象有很多好处:
1. 节省一遍又一遍地获取系统 MAC 地址所需的周期,
2. 减少我们从 /dev/urandom 中提取的熵量,并提供一个积极保证连续生成的 V1 风格的 UUID 不会发生冲突。
(在足够快的机器上每微秒生成多个 UUID,或者无论系统的时钟分辨率是多少,否则我们会冒险
每当随机初始化 uuid_t 的时钟序列时发生冲突值机会产生重复。)


翻译之后发现依然比较拗口,个人其实也看不懂,所以这里又找了一篇文章,下面简单说明一下这篇文章的内容和含义。

参考文章:Is Postgres's uuid_generate_v4 securely random?

问题:这位老哥的大致问题就是他使用了postgresql v4版本的uuid() 来生成一个access token的密钥令牌,并且询问是否线程安全(uuid是否唯一),以及是否需要使用应用端保证唯一性,这正好符合这篇文章的主题。

下面是分析之后的个人总结出来的答案(每个人理解能力不同,不一定完全正确):

  1. 首先,uuid_generate_v4 依赖uuid-ossp这个库,并且13版本的postgres的uuid是依赖此实现的。
  2. OSSP(版本1.6.2)源代码表明,该代码在类Unix系统(Windows上的CryptGenRandom())上使用**/dev/urandom** ,以及基于当前时间、进程ID的可靠性较差的PRNG,和 C 库 rand() 函数,但是对于这三个结果使用了异或操作,可以极大避免重复,使用 /dev/urandom 足以保证强随机性
  3. 但是如果/dev/urandom因为某些原因失败(例如,该进程当时已用完可用文件描述符),则库将回退到仅使用弱 PRNG ,而不会发出警告 ,这就很恐怖了,这样随机性和可能性大大提高,如果此时出现并发使用同一个时钟节点。

总结来说就是,基于上面三个点,虽然uuid-ossp在通常情况下可以保证强唯一性,但是存在退化为弱唯一性的可能性,甚至最坏的情况是使用机器的时钟点来生成uuid造成重复uuid,所以这位答主最终的建议是:谨慎建议不要依赖 PostgreSQL 生成的 UUID 的强随机性,而是在应用程序端明确使用强随机源


有读者会问PRNG是啥?伪随机数生成器 (pseudo random number generator,PRNG ),又被称为确定性随机比特生成器 (deterministic random bit generator,DRBG ),[1]是一个生成数字序列的算法,其特性近似于随机数序列的特性。PRNG生成的序列并不是真随机,因此它完全由一个初始值决定,这个初始值被称为PRNG的随机种子(seed,但这个种子可能包含真随机数)。尽管接近于真随机的序列可以通过硬件随机数生成器生成,但伪随机数生成器因为其生成速度和可再现的优势,在实践中也很重要。[2]

话外题:其实很多的策略游戏就是用了伪随机数的算法。


1.2 小结


通过上面的铺垫,我们大致了解了uuid_generate_v4() 的基本实现,下面我们来进行一个简单的总结。

产生情况:

  1. 如果机器在同一个微秒产生多个uuid就会出现重复的情况,并且**/dev/urandom**  失效的时候。
  2. 没有定义HAVE_UUID_OSSP,则需要调用操作系统的uuid_generate_time或uuid_generate_random来产生UUID。
  3. 绝大多数情况下如果仅仅只是需要一个随机数的生成函数,官方更加建议使用pgcrypto的gen_random_uuid()。

2. 对比gen_random_uuid()uuid_generate_v4()



没错,这个也是参考文章的,并且对比了很多资料发现下面这个答案简洁明了:

参考文章:PostgreSQL 生成 UUID 的两种不同方式:gen_random_uuid 与 uuid_generate_v4s

首先是关于这两个函数的直接区别:

  • gen_random_uuid()扩展提供pgcrypto
  • uuid_generate_v4()扩展提供uuid-ossp

从这篇参考文章得出的根本结论就是:

  • uuid_generate_v4() 使用 arc4random 来确定随机部分。
  • gen_random_uuid() 使用fortuna代替实现。

关于这两个算法区别这里就不再进行展开了,有条件的可以看一下下面的维基的链接介绍,如果访问不了也可以自行上网查阅资料,都是一些比较理论化的东西,这里就不再继续深入追究了。

参考文章:en.wikipedia.org/wiki/RC4#RC…


总结


    用这篇文章其实是想告诉各位,对待数据库的uuid生成方法需要结合实际的业务是否需要保证uuid的强唯一性,如果需要则强烈建议不要依赖数据库的实现方式,特别是在并发量十分高的情况下,是十分不可靠的。

最后如果发现有任何错误欢迎指正。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
分布式计算 安全 Hadoop
HBase启动时有进程webUI不显示HRegionServer各种情况解决方案
HBase启动时有进程webUI不显示HRegionServer各种情况解决方案
647 0
|
Go 开发工具 C语言
flutter项目打包.exe文件发布windows版
目录 发布windows版 1.为现有的 Flutter 应用程序添加桌面支持 2..创建main_desktop.dart文件 3.hover安装和环境配置 4.初始化,并打包 坑1
1821 0
flutter项目打包.exe文件发布windows版
|
存储 网络安全
分布式存储glusterfs详解
1.什么是glusterfs glusterfs是一个开源分布式文件系统,具有强大的横向扩展能力,可支持数pb存储容量和数千客户端,通过网络互联成一个并行的网络文件系统,具有可扩展性、高性能、高可用等特点 常用资源:
1122 0
分布式存储glusterfs详解
|
4月前
|
人工智能 程序员 Apache
程序员必备!这款离线 GenAI 工具让你本地跑模型超简单 12.2k star
Google AI Edge Gallery 是 Google 推出的移动端实验应用,支持 Android 和 iOS,可在本地离线运行生成式 AI 模型,保护隐私且无需网络。支持图像提问、Prompt 实验室、AI 聊天等功能,提供多种模型下载与性能分析,适合开发者调试和 AI 爱好者使用。项目开源,已在 GitHub 获得 12.2k star,具备良好的扩展性和实用性。
670 0
|
自然语言处理 算法 BI
Baum-Welch算法
Baum-Welch算法是一种用于隐马尔可夫模型(HMM)的训练算法,通过期望最大化(EM)框架迭代估计模型参数,直至收敛。该算法主要应用于语音识别、生物信息学和自然语言处理等领域,通过优化初始状态概率、状态转移概率和观测概率,提高模型对观测数据的拟合度。尽管存在局部最优和计算复杂性等挑战,但仍是HMM参数估计的重要工具。
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
15964 114
|
人工智能 Kubernetes API
3分钟掌握合同比对,思通数科开源工具让法律审查更高效
思通数科AI多模态平台提供开放API,支持与法律机构常用的ERP、CRM等企业系统集成。平台具备Docker、Kubernetes兼容性,支持二次开发和模块扩展,使用户能灵活应对不同业务需求。
|
安全 大数据 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(3-2):渗透测试行业术语扫盲)作者——LJS
网络空间安全之一个WH的超前沿全栈技术深入学习之路(3-2):渗透测试行业术语扫盲)作者——LJS
|
人工智能 弹性计算 自然语言处理
通义万相AI创作绘画产品方案产品体验
本次我有幸接触并体验了阿里云通义万相这一创新的AI绘画工具方案。该方案它是在利用人工智能技术,为用户提供创新、便捷的绘画创作体验。在体验过程中,我主要关注了产品的易用性、功能性、创新性、用户体验及方案本身等方面。
518 3