存储拆分后,如何解决唯一主键问题?

news2024/11/23 21:35:07

在单库单表时,业务 ID 可以依赖数据库的自增主键实现,现在我们把存储拆分到了多处,如果还是用数据库的自增主键,就会出现主键重复的情况。

所以我们不得不面对的一个选择,就是ID生成器,使用一个唯一的字符串,来标识一条完整的记录。

这时候,不能使用md5或者sha1来对整个记录做摘要,因为我们后续还要改动这个记录。也不能使用单机的计数器,因为计数器容易重启清零,也会存在多台机器上的数值重复,这违背了无状态服务的建设目标。

UUID

虽然UUID在大多数语言中都有相关的类库,但除非迫不得以,我们一般不会使用它。UUID虽然不会重复,但它非常的长,长的让人望而生畏。

标准的UUID有5个部分组成:8-4-4-4-12,一共32个十六进制字符。因此,一共是128位。当把UUID作为数据库的索引时,会因为它没有顺序性造成索引的随机分布和因为数据量巨大造成查询性能降低。

  • 且无序会造成每一次UUID数据的插入都会对主键的b+树进行很大的修改, 会产生离散 IO,从而产生性能瓶颈。

同时,UUID也是不可读的,如果你把它打印在纸质的订单上,并不是一个好的主意。UUID同时还有信息安全的隐患,它的数据计算里有MAC地址的参与,比较知名的是,曾被用于寻找梅丽莎病毒的制作者位置。

MySQL8以后

MySQL 8.0 推出了函数 UUID_TO_BIN,它可以把 UUID 字符串:

  • 通过参数将时间高位放在最前,解决了 UUID 插入时乱序问题;
  • 去掉了无用的字符串"-",精简存储空间;
  • 将字符串其转换为二进制值存储,空间最终从之前的 36 个字节缩短为了 16 字节。

同时还提供了 BIN_TO_UUID,支持将二进制值反转为 UUID 字符串,不用担心 UUID 的性能和存储占用的空间问题,相关的插入性能测试,结果如下表所示:

由于UUID_TO_BIN转换为的结果是16 字节,仅比自增 ID 增加 8 个字节,最后存储占用的空间也仅比自增大了 3G。

而且由于 UUID 能保证全局唯一,因此使用 UUID 的收益远远大于自增ID。在海量并发的互联网业务场景下,更推荐 UUID 这样的全局唯一值做主键。

但请牢记:分布式数据库架构,仅用 UUID 做主键依然是不够的。

数据库自增ID

当数据量庞大时,在数据库分库分表后,数据库自增id不能满足唯一id来标识数据;因为每个表都按自己节奏自增,会造成id冲突,无法满足需求

改造时间戳

如果你是单机应用,那么使用时间戳没什么问题,即使不用纳秒,使用毫秒也是足够的。但在分布式环境下面,时间戳同样不是一个好的选择。

即使你在机器安装了 ntpd 时间同步,但由于网络和机器的差异,计算机的时钟总是存在差异,你的时间戳总会出现重复。为了解决这个问题,你需要增加一些其他的标识,比如机器的ID,或者更多细分的信息减少时间的碰撞。

这种自定义的ID生成器,只适合特定的业务,做着做着你就会发现,它本质上是雪花算法的变种

全局ID生成器服务

可以设计一个全局 ID 生成器服务,每次找服务索要主键,这样虽然可以在业务间实现全局唯一,但是完全依赖全局 ID 生成服务,依赖性大,服务一旦宕机,会影响所有相关依赖服务。

例如使用Redis的计数器,原子性自增,好处在于使用内存,并发性能好,但存在数据丢失;自增数据量泄露的问题

雪花算法

Twitter 雪花算法生成后是一个 64bit 的 long 型的数值,默认字符串长度是19位,它分为4个部分,基本保持了自增

包含四个组成部分

不使用:1bit,最高位是符号位,0 表示正,1 表示负,固定为 0

时间戳:41bit,毫秒级的时间戳(41 位的长度可以使用 69 年)

标识位:5bit 数据中心 ID,5bit 工作机器 ID,两个标识位组合起来最多可以支持部署 1024 个节点(2^10 = 1024 个节点)

如果是分布式应用部署应保证每个工作进程的标识位id是不同的

序列号:12bit 递增序列号,表示节点毫秒内生成重复,通过序列号表示唯一,12bit 每毫秒可产生 4096 个 ID

通过序列号 1 毫秒可以产生 4096 个不重复 ID,则 1 秒可以生成 4096 * 1000 = 409w ID

默认的雪花算法是 64 bit,具体的长度可以自行配置。如果希望运行更久,增加时间戳的位数;如果需要支持更多节点部署,增加标识位长度;如果并发很高,增加序列号位数

总结:雪花算法并不是一成不变的,可以根据系统内具体场景进行定制

SnowFlake 算法的优点:

  1. 高性能高可用:生成时不依赖于数据库,完全在内存中生成
  2. 高吞吐:每秒钟能生成数百万的自增 ID
  3. ID 自增:存入数据库中,索引效率高

SnowFlake 算法的缺点: 依赖与系统时间的一致性,如果系统时间被回调,或者改变,可能会造成 ID 冲突或者重复

适用场景

因为雪花算法有序自增,保障了 MySQL 中 B+ Tree 索引结构插入高性能

所以,日常业务使用中,雪花算法更多是被应用在数据库的主键 ID 和业务关联主键

存在的问题

机器标识位一致

标识位重复的情况下,雪花 ID 也可能会重复,比如:

  • 服务通过集群的方式部署,其中部分机器标识位一致

时钟回拨的问题

为什么会有时钟回拨问题

  • 有人篡改了宿主机的系统时间
  • 集群中可能会进行整体的时钟同步,从而修改机器的本地时间

时钟回拨对雪花算法的影响

如果篡改了本地时间,那就有风险产生重复的ID,而且无法满足趋势递增了。

解决思路

  • 方案一:想办法探测到时钟回拨,然后做出对应的策略
  • 方案二:探索一种ID生成的方式,不完全依靠时间戳来保证雪花算法,或者直接使用别的策略替代时间戳

JS的坑

值得注意的是,雪花算法在JavaScript中有一个坑。后端在返回ID的时候,需要使用String类型代替Long类型,否则会产生预想不到的错误。

这是因为。在JavaScript中,存在两种数字。Number和BigInt。最常用的,就是number。

最大的Number,叫做Number.MAX_SAFE_INTEGER,它的值为:

  • 2^53-1 或者
  • +/- 9,007,199,254,740,991

众所周知,Java中的Long,是64位的。Js中的这个安全Integer,完全达不到Java中定义的长度。

这就是万恶的IEEE_754规范,它在Long长度大于17位时会出现精度丢失的问题。

常见实现方案

百度(uid-generator)

uid-generator是由百度技术部开发,项目地址:uid-generator

uid-generator是基于Snowflake算法实现的,与原始的snowflake算法不同在于,uid-generator支持自定义时间戳、工作机器ID和序列号等各部分的位数,而且uid-generator中采用用户自定义workId的生成策略。

uid-generator需要与数据库配合使用,需要新增一个WORKER_NODE表。 当应用启动时会向数据库表中去插入一条数据,插入成功后返回的自增ID就是该机器的workId数据由hostport组成。

美团(Leaf)

github地址:Leaf

美团的Leaf也是一个分布式ID生成框架。它非常全面,即支持号段模式,也支持snowflake模式。

号段模式:依赖于数据库,但是区别于数据库主键自增的模式。假设100为一个号段100,200,300,每取一次可以获得100个ID,性能显著提高。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/360753.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c++提高篇——stack容器

一、stack容器的基本概念 stack是一种先进后出(FILO)的数据结构,它只有一个出口。栈中只有顶端的元素才可以被外界使用。因此该容器不能有遍历行为。基本的结构如下: stack容器有些像手枪子弹的弹夹,其数据的出入栈可以以弹夹为参考。 二、…

redis-cluster集群搭建

安装redis所需环境 yum install -y gcc-c yum install -y wget 创建文件夹 cd / mkdir redis/redis-cluster/7001 cd redis/redis-cluster mkdir 7002 7003 7004 7005 7006 7007 7008下载redis压缩包并解压安装 wget https://download.redis.io/redis-stable.tar.gz tar -…

从0开始写Vue项目-SpringBoot整合Mybatis-plus实现登录、注册功能

1.从0开始写Vue项目-环境和项目搭建_慕言要努力的博客-CSDN博客 2. 从0开始写Vue项目-Vue2集成Element-ui和后台主体框架搭建_慕言要努力的博客-CSDN博客 3. 从0开始写Vue项目-Vue页面主体布局和登录、注册页面_慕言要努力的博客-CSDN博客 一、前言 在之前我们以及搭建好了基…

线上问题诊断指南

内容概要 诊断工具介绍工具可用情况偶现或已现问题诊断思路 硬件资源观测 top top可以看整个系统cpu、内存的使用情况,以及在各个进程上的情况,如下: $ top top - 13:14:07 up 2 days, 6:38, 0 users, load average: 1.65, 0.59, 0.27…

知识库:在医疗行业的知识管理有着怎样的意义与实际影响?

知识库中还可存在一个通常被称作典型方法库的特殊部分。如果对于某些问题的解决途径是肯定和必然的,就可以把其作为一部分相当肯定的问题解决途径直接存储在典型方法库中。这种宏观的存储将构成知识库的另一部分。在使用这部分时,机器推理将只限于选用典…

Android 基础知识4-2.10 GridLayout(网格布局)详解

一、GridLayout(网格布局)概述 GridLayout 布局是 Android 4.0 以后引入的新布局,和 TableLayout(表格布局) 有点类似,不过它功能更多,也更加好用,最大的特点是放置的组件自动占据网格的整个区域,每个组件的…

【Linux】动静态库的制作

​🌠 作者:阿亮joy. 🎆专栏:《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉动静库和静…

RS485通信总线详解

RS485 总线详解 RS-485 是美国电子工业协会(EIA)在 1983 年批准了一个新的平衡传输标准(Balanced Transmission Standard)也称作差分,EIA 刚开始将 RS(Recommended Standard)做为标准的前缀&am…

一文解决Rust字符串:String,str,String,str,CString,CStr

一、str和&str和String的区别 1.存放位置,可变不可变: str来源于Rust本身的数据类型,而String类型来自于标准库。首先看一下str 和 String之间的区别:String是一个可变的、堆上分配的UTF-8的字节缓冲区。而str是一个不可变的…

前端零基础入门-002-集成开发环境

本篇目标 了解市面上常用的前端集成开发环境(ide)掌握 HBuiberX 的使用:下载安装,新建项目、网页、运行网页。 内容摘要 本篇介绍了市面上流行的几款前端集成开发环境(ide),并介绍了 Hbuilde…

华为OD机试 - 按索引范围翻转文章片段(Java) | 机试题算法思路 【2023】

使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:https://blog.csdn.net/hihell/category_12201821.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 按索引范围翻转文章…

【黄啊码】什么是ElasticSearch?它会替代MySQL成为主流吗?如何优化?TP5如何接入ElasticSearch?

什么是ElasticSearch? Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析 引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。 Elasticsearch 的实现原理主要分…

「TCG 规范解读」第8章 TPM工作组 TPM 1.2中 SHA1的使用

可信计算组织(Ttrusted Computing Group,TCG)是一个非盈利的工业标准组织,它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立,并采纳了由可信计算平台联盟(the Trusted Computing Platform Alli…

Windows Server 2008 R2安装onlyoffice【docker】

目录 前言 准备工作 安装docker 安装onlyoffice 常见问题 前言 目前docker for windows只能在windows10/11上安装,其他的windows版本只能使用Docker Toolbox来安装,使用该工具安装的docker其实是借助了Oracle VM VirtualBox虚拟机来运行的&a…

简历的专业技能怎么写?排版需要注意的事项

一、简历的专业技能怎么写? 首先,先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几 天时间学习一下,然后在简历上可以写上自己了解这个技…

使用sshdo限制incoming ssh只能执行指定命令

前言系统管理员经常面临一个问题,如何将用户的incoming ssh限制在一个命令白名单里,达到安全的目的。本文介绍sshdo工具,来实现该功能。仓库地址https://github.com/wanlinwang/sshdo安装tar xzf sshdo-1.1.tar.gz #如果是直接clone仓库则无需…

JVM学习笔记六:运行时数据区之堆

目录 概述 堆空间内部结构 JDK7版本 JDK8版本 堆空间的内存划分 堆空间大小设置参数 概述 Java堆是虚拟机所管理的内存中最大的一块,其在JVM启动时即被创建,并且空间大小也被确定(这里是不考虑Java8之后以本地内存来实现的元空间&…

连续时间信号与离散时间信号

前言 《信号与系统》是一门很难的课,也是许多学校考研要考的专业课,由于每周只有两节课,所以每次上完都要及时的去复习,这里参考的教材是奥本海姆著作,刘海棠译,北京:电子工业出版社&#xff0…

实践数据湖iceberg 第四十课 iceberg的sql运维方式(合并文件、合并元数据、清理历史快照)

系列文章目录 实践数据湖iceberg 第一课 入门 实践数据湖iceberg 第二课 iceberg基于hadoop的底层数据格式 实践数据湖iceberg 第三课 在sqlclient中,以sql方式从kafka读数据到iceberg 实践数据湖iceberg 第四课 在sqlclient中,以sql方式从kafka读数据到…

只因小黑子:SVG

小黑子的SVG复习SFV画布1. 初始SVG2. SVG绘制矩形、圆形和椭圆形2.1 rect 矩形2.2 circle 圆形2.3 ellipse 椭圆4. SVG绘制线条、多边形和多线条4.1 line 线条4.2 polygon 多边形4.3 polyline 多线条5. SVG绘制文本 text6. SVG绘制路径 path7. SVG描边属性8. SVG 模糊和阴影效果…