3

【业务学习】简述ID生成器

 3 years ago
source link: https://segmentfault.com/a/1190000040633600
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

大家好,好久不见,时隔一年终于又拾起了写博客这件事。
在我们日常工作中,我们常需要用全局唯一ID作为数据库主键,或者用于生成订单id,用于生成商品ID等等。本篇主要介绍我们常见的ID生成器的方式:利用数据库生成和雪花算法。

利用数据库生成ID

自增ID达成目的

利用MYSQL自增主键的特性来构造ID生成器。首先生成一张ID生成器表,每次我们需要生成ID的时候在这个表里插入一行记录,获取到这行记录生成的主键id,就可以拿到一个全局唯一id,基本满足需求。

| idctime12021-09-05 12:00:0022021-09-05 12:01:00

那么有的盆友们会说了,这个方法肯定会影响性能啊,每次请求都需要去连接DB获取id,伤不起啊。没关系,我们优化一下。我们采用分段请求,即每次请求一段ID(例如20个ID)缓存到本地,这样就只需要等本地ID使用完了再去请求了,增加了性能。到这又有朋友说了,每次批量插入数据性能还是不行,而且在多业务方同时使用的时候性能更差,这怎么办呢?别着急,往下看。
我们可以将表设计成类似下表这个结构。

biz_tag(业务线)max_idstep(每次申请ID数)update_timeapp100010002021-09-05 12:00:00pc200010002021-09-05 12:00:00

从上表我们可以看出,每次我们请求ID的时候的大概流程是这样的:获取到当前的max_id -> 拿业务线标识申请(max_id,max_id + step]之间的id -> id使用完 -> 重新发起流程。 这样DB的压力就会小很多,但是呢,在生产环境中也会存在一些问题:例如:

- 系统性能依赖DB的更新,如果更新DB出现尖刺,服务性能将收到影响
- 强依赖DB的可用性,DB一旦出现宕机将整个不可用

对于以上两个问题,我们有以下解决思路:

  1. 预处理,当本地队列使用百分之七十的时候就去申请后新的ID(比例根据业务需求设置)
  2. 在本地缓存一个队列作为“备胎”,当服务不可用且正常队列用完时可以使用“备胎”进行工作,并且不断的去申请新的队列。

如果我们服务的会出现突增流量的情况,我们也可以动态的调整每次申请的id数,设定适配业务的算法去调整这个step,具体的算法此处不再赘述。

当然,业界使用数据库去生成DB的方式有很多,在如何保障可用性上做了很多的优化,因为这种方式最终需要强依赖DB

它给每台机器分配一个唯一标识,然后通过时间戳+标识+自增实现全局唯一ID。这种方式好处在于ID生成算法完全是一个无状态机,无网络调用,高效可靠。这种方法也是我们业务中所常见的方式,下面我们来看看我们采用的的52位和64位的ID怎么生成。

64bit

42b timestamp + 8b counter + 8b countspace + 6b serverid

  • timestamp:毫秒级时间戳
  • counter: 毫秒内的自增counter,取值[0, 255]
  • countspace:标识counterspace,同一个业务方下可能有不同的counterspace,此6bit不同
  • serverid:服务器id,全球唯一

52bit

32bit timestamp + 16bit counter + 4bit server_id

  • timestamp:秒级时间戳
  • counter: 秒级自增counter
  • serverid:服务器id,全球唯一

通过以上两种规则即可实现分布式ID的生成,当然,业界还有很多种不同的规则,但是都是一个道理,大家可以按照自己的需求去处理。

欢迎对本系列文章感兴趣的读者订阅我们的公众号,关注博主下次不迷路~
image.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK