当前位置: 首页 > news >正文

分库分表之后如何设计主键ID(分布式ID)?

文章目录

    • 1、数据库的自增序列+步长方案
    • 2、分表键结合自增序列
    • 3、UUID
    • 4、雪花算法
    • 5、redis的incr方案
    • 总结

在进行数据库的分库分表操作后,必然要面临的一个问题就是主键id如何生成,一定是需要一个全局的id来支持,所以分库分表之后,首当其冲的问题就是设计一个适合的主键id方案。简单的说就是分库分表之后所谓的分布式ID如何生成

当然主键id方案也是五花八门,我个人的看法是没有最好的方案,只有最适合的方案

1、数据库的自增序列+步长方案

前提:假如分表的数量不是很多或者比较固定
在数据库的自增序列(Auto-increment)中,步长(Step Value)是指每次自增操作后ID增加的数值。步长的设置可以用于控制ID的增长速度和分配方式

比如最常见的就是单步长,步长设置为1。每次插入新记录时,自增字段的值都会比上一个记录的值大1

那么假设当前我们分了三张表,可以将步长设置为3,表1的id就会是1,4,7 表2是2,5,8 表3是3,6,9

这个方案的好处是不需要其它操作,实现起来比较简单,也能达到性能的目标,而且又可以使用数据库本身的自增序列的优点长处

但是缺点也很明显,首先分表的数量必须是固定的,步长也是固定的,将来如果数据量又上来了就不好继续拆分表。而且在实际业务中,大部分需要分表的情况数据量都是比较大的,所以这个方案只适合极少部分场景

2、分表键结合自增序列

将业务相关的键(如用户名、时间戳等)与自增序列结合生成唯一ID,比如用户名+ID
或者每个分表有个唯一标识,比如表A分三张表A1、A2、A3,那么分别的ID就是A1_1, A2_1。。。等

这个方案的优点也很明显,生成的ID与业务逻辑紧密相关,便于理解和查询,且业务键和自增序列的组合使得ID生成逻辑相对简单,易于维护,后续的扩展增加分表等也相对简单

缺点:
当需要进行跨表操作时,由于并不知道数据在哪张表(分表标识的场景,如果是业务键信息+自增ID,可能需要额外的转换或关联操作)中,联合查询就需要额外的逻辑来处理。并且如果需要对分表进行合并或拆分,由于ID的结构,数据迁移可能会比较复杂。而且说到底其实这个并没有很好的解决高并发场景

3、UUID

每次聊到分布式主键或者分库分表,UUID总是离不开话题,我见过大多数人的第一反应也是说UUID。UUID也有几种不同的算法可以获得,这里就不过多赘述。作为主键,它几乎可以保证全局唯一性,而且确实是非常方便。
但是他的缺点就是长度较长,占用的空间又大,性能确实很一般。而且最最最重要的是它不具有有序性,这个是很致命的问题,会导致B+树索引在写的时候有过多的随机写操作,这里详细解释一下
UUID导致的随机写操作,作为主键在写入操作时通常会导致B+树的插入(Insert)操作而不是有序的追加(Append)操作,这会将整个B+树的节点读到内存里面,然后在插入这个节点后,再将整个节点回写到磁盘,这个操作在记录数据占用空间较大的情况下会显著降低性能

  1. 随机性:UUID是随机生成的,这意味着每次生成的UUID值在整个数据空间内是均匀分布的
  2. 索引页分裂:当UUID作为主键索引时,由于其随机性,新插入的记录很可能会落在不同的索引页上,导致索引页频繁分裂和合并
  3. 写入放大:随机写操作可能导致写入放大,因为每次写入都可能需要写入新的索引页,而不是简单地在现有页上追加
  4. 磁盘I/O增加:随机写操作会增加磁盘I/O操作,因为磁盘头需要移动到不同的位置进行写入,这比顺序写入效率低
  5. 缓存失效:由于UUID的随机性,数据库缓存可能频繁失效,因为缓存页可能很快被新的随机UUID值替换

但是呢,自增id就不会有这个问题

  1. 顺序性:自增ID是顺序生成的,每次插入新记录时,ID值都是前一个记录ID值的下一个整数
  2. 顺序写入:顺序生成的ID保证了新记录可以顺序地写入索引树,减少了索引页的分裂和合并
  3. 写入效率:顺序写入可以提高写入效率,因为新记录通常可以追加到现有的索引页上,而不是写入新的索引页
  4. 磁盘I/O减少:顺序写入减少了磁盘I/O操作,因为磁盘头不需要频繁移动到不同的位置。
  5. 缓存效率:顺序写入提高了缓存效率,因为新记录可以被顺序地写入缓存页,减少了缓存失效的可能性
  6. 索引优化:由于自增ID的顺序性,数据库可以更有效地优化索引结构,例如通过延迟索引页的分裂
  7. 数据局部性:自增ID有助于保持数据的局部性,新记录更有可能与现有记录存储在相邻的磁盘块上,这有助于提高查询性能
    所以UUID的效率大打折扣

4、雪花算法

说到uuid,那么肯定就会想到大名鼎鼎的雪花算法(Twitter的Snowflake算法),这实际是一种分布式ID生成器。它将时间戳、数据中心id或者机器id、序列号、位运算等结合来生成一个全局唯一的ID,

通常,一个雪花算法生成的ID可以分为以下几部分:

  • 第1位:未使用,固定为0。 第2到第41位:时间戳,41位可以提供69年的时间(从2016年开始)
  • 第42到第51位:数据中心ID,10位可以提供1024个数据中心。这个可根据实际业务调整
  • 第52到第61位:机器ID,10位可以提供1024个机器。这个可根据实际业务调整
  • 第62到第64位:序列号,12位可以提供4096个序列号。在每个时间戳内,序列号从0开始自增,直到达到最大值(通常是4095),然后等待下一个时间戳的到来。如果时间戳发生回拨,算法会等待直到时间戳再次递增,以避免生成重复的ID

优点:

  1. 全局唯一性:雪花算法生成的ID是全局唯一的,适用于分布式系统
  2. 高性能:算法简单,生成ID速度快,对性能影响小
  3. 趋势递增:由于ID中包含了时间戳,生成的ID是递增的,这有助于优化数据库索引和缓存
  4. 信息丰富:ID中包含了时间戳、数据中心ID、机器ID和序列号,可以提供丰富的信息
  5. 避免热点:由于序列号是在一个机器上独立生成的,避免了对中心ID生成服务的依赖,减少了热点问题
  6. 可定制性:可以根据需要调整数据中心ID和机器ID的位数,以适应不同的分布式规模。
  7. 容错性:算法可以容忍一定程度的机器ID重复或回拨,具有一定的容错性

缺点:

  1. 依赖机器时钟:算法依赖于机器的时钟,如果时钟回拨,可能会导致ID重复或生成负数。
  2. 时钟回拨问题:如果服务器的时钟发生回拨,可能会生成重复的ID。
  3. 序列号限制:序列号在一个时间片内是有限的,如果生成速度非常快,可能会耗尽序列号。
  4. 数据中心和机器ID分配:需要预先分配数据中心ID和机器ID,并确保它们不会重复。
  5. ID解析复杂:解析ID以获取时间戳、数据中心ID、机器ID等信息相对复杂。
  6. ID长度固定:由于ID由多个部分组成,其长度是固定的,可能不如某些其他方法灵活。
  7. ID生成间隔限制:由于依赖时间戳,如果系统时间变化过快,可能会在短时间内生成相同的ID。
  8. 时间戳精度限制:时间戳的精度限制了ID生成的频率,如果需要更高频率的ID生成,可能需要优化算法

通过上面可以看到雪花算法其实也比较长,但是它是递增的,相对来说很友好

但是要注意,每毫秒每个机器最多4096个序列,虽然这个并发绝大部分业务来说已经够用,如果有极端场景可能需要关注一下

其次就是时钟回拨问题,比如分布式不同的机器有时间同步,如果哪一天同步校正时间的时候将时间往前回拨了,这个时候要么会产生重复的ID,要么等待时间戳重新到达历史记录点然后再生成,所以也需要重点关注一下

5、redis的incr方案

Redis 的 INCR 命令用于将键的整数值原子性地递增。使用 Redis 作为分布式ID生成器时,INCR 命令可以提供一种简单的方式来生成唯一的递增ID,我个人是比较推崇这个方案的

优点比较明确,简单易用,性能稳定性都很不错。INCR操作是原子的,我们不需要再去考虑并发的冲突,redis帮我们解决了问题,并且redis速度很快,也很灵活和易于监控

缺点呢就是业务ID的生成强依赖于redis的服务,如果redis服务挂了宕机了之类的,将会导致业务也不可用,并且在高并发下压力就会给到redis这边,因为所有的ID生成请求都会发送到redis
所以这个方案最重要的就是保护redis的安全,虽然实际redis很少宕机,但是如果遇到了还是非常头疼的问题,所以redis的持久化机制、高可用方案等也是很重要的

总结

总结一下,方案很多,还是得根据实际业务来,脱离业务谈方案其实有点耍流氓的意思,每个方案都有优缺点。不过要是非要真的想一劳永逸的解决这个问题,而且业务体量确实有这么大,雪花算法确实也许是最优的解决办法

相关文章:

分库分表之后如何设计主键ID(分布式ID)?

文章目录 1、数据库的自增序列步长方案2、分表键结合自增序列3、UUID4、雪花算法5、redis的incr方案总结 在进行数据库的分库分表操作后,必然要面临的一个问题就是主键id如何生成,一定是需要一个全局的id来支持,所以分库分表之后,…...

秋招突击——6/28、6.29——复习{数位DP——度的数量}——新作{}

文章目录 引言复习数位DP——度的数量个人实现参考实现 总结 引言 头一次产生了那么强烈的动摇,对于未来没有任何的感觉的,不知道将会往哪里走,不知道怎么办。可能还是因为实习吧,再加上最近复习也没有什么进展,并不知…...

Spring Boot中使用Thymeleaf进行页面渲染

Spring Boot中使用Thymeleaf进行页面渲染 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨如何在Spring Boot应用中使用Thymeleaf模板引擎进行页面…...

恢复策略(下)-事务故障后的数据库恢复、系统故障后的数据库恢复(检查点技术)、介质故障后的数据库恢复

一、数据库恢复-事务故障 系统通过对事物进行UNDO操作和REDO操作可实现故障后的数据库状态恢复 1、对于发生事务故障后的数据库恢复 恢复机制在不影响其他事务运行的情况下,强行回滚夭折事务,对该事务进行UNDO操作,来撤销该事务已对数据库…...

如何知道docker谁占用的显卡的显存?

文章目录 python环境安装nvidia-htop查看pid加一个追踪总结一下【找到容器创建时间】使用说明示例 再总结一下【用PID找到容器创建时间,从而找到谁创建的】使用说明示例 python环境安装nvidia-htop nvidia-htop是一个看详细的工具。 pip3 install nvidia-htop查看…...

wps linux node.js 加载项开发,和离线部署方案

环境准备 windwos 安装node.js 安装VSCode 安装wps linux 安装node.js 安装VSCode 安装wps 通过npm 安装wpsjs SDK 使用npm安装wpsjs npm install -g wpsjs 创建一个项目 wpsjs create WPS-Addin-PPT 创建项目会让你选择2个东西: 1:选择你的文…...

红队内网攻防渗透:内网渗透之内网对抗:横向移动篇Kerberos委派安全非约束系约束系RBCD资源系Spooler利用

红队内网攻防渗透 1. 内网横向移动1.1 委派安全知识点1.1.1 域委派分类1.1.2 非约束委派1.1.2.1 利用场景1.1.2.2 复现配置:1.1.2.3 利用思路1:诱使域管理员访问机器1.1.2.3.1 利用过程:主动通讯1.1.2.3.2 利用过程:钓鱼1.1.2.4 利用思路2:强制结合打印机漏洞1.1.2.5 利用…...

nginx上传文件限制

默认限制 Nginx 限制文件大小可以通过 client_max_body_size 指令来设置,该指令通常在 http、server 或 location 块中设置,如果不设置,默认上传大小为1M。 修改上传文件限制 要修改Nginx的文件上传大小限制,你需要编辑Nginx的配…...

76. 最小覆盖子串(困难)

76. 最小覆盖子串 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转:76. 最小覆盖子串 2.详细题解 在s中寻找一个最短的子串,使之包含t中的所有字符,t中可能存在多个相同字符,寻找的子串也应至少含有…...

K8S 集群节点扩容

环境说明: 主机名IP地址CPU/内存角色K8S版本Docker版本k8s231192.168.99.2312C4Gmaster1.23.1720.10.24k8s232192.168.99.2322C4Gwoker1.23.1720.10.24k8s233(需上线)192.168.99.2332C4Gwoker1.23.1720.10.24 当现有集群中的节点资源不够用&…...

AI大模型技术在音乐创造的应用前景

大模型技术在音乐创作领域具有广阔的应用前景,可以为音乐家、作曲家和音乐爱好者提供以下方面的帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 音乐创作辅助:大模型可以帮助音乐家和作曲家生成旋律、和声…...

Linux多进程和多线程(一)-进程的概念和创建

进程 进程的概念进程的特点如下进程和程序的区别LINUX进程管理 getpid()getppid() 进程的地址空间虚拟地址和物理地址进程状态管理进程相关命令 ps toppstreekill 进程的创建 并发和并行fork() 父子进程执行不同的任务创建多个进程 进程的退出 exit()和_exit() exit()函数让当…...

熊猫烧香是什么?

熊猫烧香(Worm.WhBoy.cw)是一种由李俊制作的电脑病毒,于2006年底至2007年初在互联网上大规模爆发。这个病毒因其感染后的系统可执行文件图标会变成熊猫举着三根香的模样而得名。熊猫烧香病毒具有自动传播、自动感染硬盘的能力,以及…...

使用Vue3和Tailwind CSS快速搭建响应式布局

### 第一部分:初始化Vue3项目并安装Tailwind CSS 首先,在你的开发环境中打开终端,然后通过Vue CLI来创建一个新的Vue3项目。输入如下命令: vue create my-vue-app 按照提示选择Vue3的相关选项,创建完毕后&#xff0…...

J019_选择排序

一、排序算法 排序过程和排序原理如下图所示&#xff1a; 二、代码实现 package com.itheima.sort;import java.util.Arrays;public class SelectSort {public static void main(String[] args) {int[] arr {5, 4, 3, 1, 2};//选择排序for (int i 0; i < arr.length - 1…...

【linux】vim的使用

目录 一、Vim的基本模式 二、Vim的常见命令 三、Vim的高级用法 四、Vim的进阶使用技巧 在Linux系统中&#xff0c;Vim是一款功能强大的文本编辑器&#xff0c;特别适用于程序员的代码编辑和修改。以下是Vim的详细使用教程&#xff0c;包括其基本模式、常见命令和高级用法。…...

【工具测评】ONLYOFFICE8.1版本桌面编辑器测评:好用!

随着远程工作的普及和数字化办公的发展&#xff0c;越来越多的人开始寻找功能强大、易于使用的办公软件。在这个背景下&#xff0c;ONLYOFFICE 8.1应运而生&#xff0c;成为许多用户的新选择。ONLYOFFICE 8.1是一款办公套件软件&#xff0c;提供文档处理、电子表格和幻灯片制作…...

核方法总结(四)——高斯过程回归学习笔记

一、定义 基于核方法的线性回归模型和传统线性回归一样&#xff0c;可以用未知数据进行预测&#xff0c;但不能确定 预测的可信度。在参考书第二章中可知&#xff0c;基于贝叶斯方法可以实现对未知数据依概率预测&#xff0c;进而可得到预测的可信度。这一方法中&#xff0c;通…...

【Python3的内置函数和使用方法】

目录 Python 特点 Python 中文编码 Python 变量类型 Python列表 Python 元组 元组是另一个数据类型&#xff0c;类似于 List&#xff08;列表&#xff09; Python 字典 Python数据类型转换 Python 运算符 Python算术运算符 Python比较运算符 Python赋值运算符 Pyt…...

递推算法计算信号特征

在线算法&#xff08;在线计算或递推计算&#xff09;能够在不存储全部数据的情况下逐步更新信号的特征信息&#xff0c;非常适合资源受限的单片机应用场景。 用途&#xff1a;单片机边采集&#xff21;&#xff24;&#xff23;边计算&#xff0c;最终将采集的信号特征计算结果…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”

非常好&#xff0c;我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题&#xff0c;统一使用 二重复合函数&#xff1a; z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y))​ 来全面说明。我们会展示其全微分形式&#xff08;偏导…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)

目录 &#x1f50d; 若用递归计算每一项&#xff0c;会发生什么&#xff1f; Horners Rule&#xff08;霍纳法则&#xff09; 第一步&#xff1a;我们从最原始的泰勒公式出发 第二步&#xff1a;从形式上重新观察展开式 &#x1f31f; 第三步&#xff1a;引出霍纳法则&…...

dvwa11——XSS(Reflected)

LOW 分析源码&#xff1a;无过滤 和上一关一样&#xff0c;这一关在输入框内输入&#xff0c;成功回显 <script>alert(relee);</script> MEDIUM 分析源码&#xff0c;是把<script>替换成了空格&#xff0c;但没有禁用大写 改大写即可&#xff0c;注意函数…...