前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >全局id如何生成?

全局id如何生成?

作者头像
名字是乱打的
发布2021-12-24 08:52:04
1.5K0
发布2021-12-24 08:52:04
举报
文章被收录于专栏:软件工程

很多时候我们都需要生成一个全局id用于数据存储的主键,那么如何生成一个全局id呢?有哪些方法?优缺点是啥?

0.redis自增主键

直接用redis原理性的自增命令 incr(key),获取一个自增主键.

  • 优点:简单快捷,原子性,支持分布式系统
  • 缺点:引入第三方中间件,需要考虑数据安全性问题(比如持久化,或者如果内存满了数据被淘汰了,重新计数会不会对你的系统有影响呢?)
1.数据库自增id

我们需要一个单独的表给我们专门生成自增id,每次到这个专门生成id的表里插入一条数据拿回id,带着这个id去新增自己分表数据;

  • 优点:方便简单,谁都会用;
  • 缺点: 1.单库生成自增id,要是高并发的话,就会有瓶颈的;(对于高并发的负载,InnoDB 在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热点,因为所有的插入都发生在这里,并发插入会导致间隙锁竞争) 2.如果别人爬取统计咱们的id,有可能会分析出咱们的业务量和运营情况;
2.uuid

eg:UUID.randomUUID().toString().replace(“-”, “”) -> sfsdf23423rr234sfdaf

  • 优点:本地生成,不要基于数据库来了;
  • 缺点:uuid太长了,作为主键性能太差了 (不像自增主键一样有明显的顺序性,1增加了记录位置计算成本,2增加了页分裂的可能,增加了移动记录的成本),不适合用于主键。

适合的场景:如果你是要随机生成个什么文件名了,编号之类的,你可以用uuid,但是作为主键是不能用uuid的

3.获取系统当前时间

这个就是获取当前时间即可,但是问题是,并发很高的时候,比如一秒并发几千,会有重复的情况,这个是肯定不合适的。如果单独使用基本就不用考虑了。

适合的场景:一般如果用这个方案,是将当前时间跟很多其他的业务字段拼接起来,作为一个id,如果业务上你觉得可以接受,那么也是可以的。你可以将别的业务字段值跟当前时间拼接起来,组成一个全局唯一的编号,订单编号,时间戳 + 用户id + 业务含义编码

4.snowflake算法

twitter开源的分布式id生成算法,就是把一个64位的long型的id,1个bit是不用的符号位,剩下的用其中的41 bit作为毫秒数,用10 bit作为工作机器id(5位机房id加五位机器id),12 bit作为序列号,也不是特别复杂,咱们画一下图就知道了

eg:

代码语言:javascript
复制
1 bit:不用,为啥呢?因为二进制里第一个bit为如果是1,那么都是负数,但是我们生成的id都是正数,所以第一个bit统一都是0

41 bit:表示的是时间戳,单位是毫秒。41 bit可以表示的数字多达2^41 - 1,也就是可以标识2 ^ 41 - 1个
毫秒值,换算成年就是表示69年的时间。

10 bit:记录工作机器id,代表的是这个服务最多可以部署在2^10台机器上哪,也就是1024台机器。
但是10 bit里5个bit代表机房id,5个bit代表机器id。意思就是最多代表2 ^ 5个机房(32个机房),
每个机房里可以代表2 ^ 5个机器(32台机器)。

12 bit:这个是用来记录同一个毫秒内产生的不同id,12 bit可以代表的最大正整数是2 ^ 12 - 1 = 4096,
也就是说可以用这个12bit代表的数字来区分同一个毫秒内的4096个不同的id

64位的long型的id,64位的long -> 二进制
4.1 雪花算法的坑:
  • 1.id的时间戳部分只能表示69年,不过一般一个系统也很难超过这个限制。
  • 2.雪花算法依赖系统的时间一致性,如果系统时间被回调,可能会出现id重复导致主键冲突的情况。另外分布式系统中,各节点的时间并不能保证完全同步,所以有可能出现分布式系统中不能出现完全递增的情况。

第一个问题就不说了,直接说第二个问题解决方案;

  • 1.先采用惰性方式,即我们会保存一个系统已使用的最新的时间戳,如果当前时间小于已使用的时间戳(即时钟回拨)那就睡个几毫秒,然后再次获取当前时间,如果还是有回拨现象采用下面2
  • 2.备用workid方案,主要思路,snowflake算法给workerId预留了10位,即workId的取值范围为[0, 1023],事实上实际生产环境不大可能需要部署1024个分布式ID服务,所以:将workerId取值范围缩小为[0, 511],[512, 1023]这个范围的workerId当做备用workerId。workId为0的备用workerId是512,workId为1的备用workerId是513,以此类推……,如果我们0号服务产生了时钟回拨的问题,我们就用其备用服务512去生成id,如果我们认为两套备用服务依然不可靠,可以继续分区,但是这样的话我们可以用的workid就变少了。 时钟回拨问题原文可以看=====>雪花算法增强
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/12/21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0.redis自增主键
  • 1.数据库自增id
  • 2.uuid
  • 3.获取系统当前时间
  • 4.snowflake算法
  • 4.1 雪花算法的坑:
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档