主键的生成到底用什么生成策略合适?有什么优劣吗?

为什么要用雪花id代替数据库自增id?


在数据库设计中,我尝尝在想主键的id应该怎么设置好?为什么这样设置?

  • 先讨论一下什么时候使用数据库自增id合适

    1. 单表设计,数据量不大,不需要考虑分库分表
    2. 业务对ID连续性有较高要求:某些业务场景下可能需要ID是严格递增的,例如按时间顺序排序的需求,此时自增ID更加直观和方便。
  • 再讨论一下什么时候使用雪花id合适 (如果还不清楚什么是雪花id的话可以在下面了解下)

    1. 全局唯一:雪花ID结合时间戳、工作机器ID和序列号,可以在分布式系统中生成全局唯一的ID。

    2. 趋势有序:虽然不是严格递增,但雪花ID的时间戳部分使得生成的ID具有大致的时间趋势,有助于提升某些查询性能。

    3. 可扩展性:由于雪花ID的设计考虑到了分布式环境,所以能够轻松应对分库分表、多数据中心部署等情况下的ID生成需求。

    4. 无锁生成:雪花ID生成过程快速且无锁(时间戳序列号防重复),适合高并发场景下大量生成ID的需求。

1.什么是雪花算法


雪花 ID(Snowflake ID)是用于分布式系统中生成唯一 ID 的算法,在分布式环境下高效地生成全局唯一的 ID

雪花 ID 的结构如下所示:

一共是8个字节,64bit,对应后端的long类型的数据,这四个部分代表:

  1. 符号位:最高位是符号位,始终为 0,1 表示负数,0 表示正数,ID 都是正整数,所以固定为 0。
  2. 时间戳部分:由 41 位组成,精确到毫秒级。可以使用该 41 位表示的时间戳来表示的时间可以使用 69 年。
  3. 节点 ID 部分:由 10 位组成,用于表示机器节点的唯一标识符。在同一毫秒内,不同的节点生成的 ID 会有所不同。
  4. 序列号部分 :由 12 位组成,用于标识同一毫秒内生成的不同 ID 序列。在同一毫秒内,可以生成 4096 个不同的 ID。(无锁化)

网上有很多雪花算法的代码,这里就不再赘述了

2.雪花算法有什么问题


虽然雪花算法是一种被广泛采用的分布式唯一 ID 生成算法,但它也存在以下几个问题:

  1. 时间回拨问题 :雪花算法生成的 ID 依赖于系统的时间戳,要求系统的时钟必须是单调递增的。如果系统的时钟发生回拨,可能导致生成的 ID 重复。时间回拨是指系统的时钟在某个时间点之后突然往回走(人为设置),即出现了时间上的逆流情况。
  2. 时钟回拨带来的可用性和性能问题:由于时间依赖性,当系统时钟发生回拨时,雪花算法需要进行额外的处理,如等待系统时钟追上上一次生成 ID 的时间戳或抛出异常。这种处理会对算法的可用性和性能产生一定影响。
  3. 节点 ID 依赖问题:雪花算法需要为每个节点分配唯一的节点 ID 来保证生成的 ID 的全局唯一性。节点 ID 的分配需要有一定的管理和调度,特别是在动态扩容或缩容时,节点 ID 的管理可能较为复杂。

3.如何解决时钟回拨问题

百度 UidGenerator 框架中解决了时间回拨的问题,并且解决方案比较经典

UidGenerator 介绍 :UidGenerator 是百度开源的一个分布式唯一 ID 生成器,它是基于 Snowflake 算法的改进版本。与传统的 Snowflake 算法相比,UidGenerator 在高并发场景下具有更好的性能和可用性。它的实现源码在:github.com/baidu/uid-g...

**UidGenerator 是这样解决时间回拨问题的:UidGenerator 的每个实例中,都维护一个本地时钟缓存,用于记录当前时间戳。**这个本地时钟会定期与系统时钟进行同步,如果检测到系统时钟往前走了(出现了时钟回拨),则将本地时钟调整为系统时钟。

4.众所周知的UUID代替雪花算法可以吗?

如果单从唯一性来考虑的话,那么 UUID 和雪花 ID 的效果是一致的,二者都能保证分布式系统下的数据唯一性,但是即使这样,也不建议使用 UUID 替代雪花 ID,因为这样做的问题有以下两个:

  1. 可读性问题:UUID 内容很长,但没有业务含义,就是一堆看不懂的"字母"。
  2. Mysql底层索引页分裂问题 :UUID是无序的,在生成聚簇索引的时候,会造成索引页分裂,性能低,相比较雪花算法是唯一且增量有序,不会造成索引页分裂的问题

5.总结与思考

我在一些评论区看到一些评论,我也想讲一下我个人的思考

通过组合主键的方式确保全局唯一id,先不说这种生成方式是long类型还是String类型,

如果以后需要进行数据合并或者数据分片,这样子组合主键会麻烦到什么程度呢


雪花算法的id是不连续,但是雪花算法是增量有序,即后一个id一定比前面一个id的值要大

这样不会导致插入类似Mysql这种数据库进行索引页分裂的操作

如果一定是要连续的业务场景,那当然雪花算法并不适合

6.分享一些网友的热评

相关推荐
摇滚侠几秒前
《SpringBoot 3:入门与应用实战》第 14 章 打包与部署 Spring Boot 应用打包 阅读笔记 41
spring boot·笔记·后端
海浪仙人掌3 分钟前
应收账款分析如何操作?应收账款分析有哪些注意事项?
数据库·人工智能
Elastic 中国社区官方博客6 分钟前
在 Elasticsearch 中回填时间序列数据:通过批量 API 加载数月的历史指标数据
大数据·运维·数据库·人工智能·elasticsearch·搜索引擎·全文检索
Horn Still Sounds11 分钟前
Linux网络并发服务器模型与SQLite数据库学习笔记
linux·服务器·数据库
昵称画40 分钟前
POC验证怎么设计用例?不走过程的实操要点
大数据·数据库·人工智能·低代码·excel
TDengine (老段)1 小时前
TDengine Catalog 与元数据缓存
大数据·数据库·物联网·缓存·时序数据库·tdengine
CarIise1 小时前
MySQL数据库表关系与多表查询:从表间关系设计到JOIN联表查询
数据库·mysql
网络工程小王2 小时前
【LLM开发实验】FastAPI 学习笔记
数据库·笔记·学习·mysql·fastapi
阿拉斯攀登2 小时前
MQ消息积压问题排查:消费卡顿、堆积、消费速度优化
后端
阿拉斯攀登2 小时前
无人售货机库存异步更新方案:解决高并发下单库存卡顿问题
后端