共计 1486 个字符,预计需要花费 4 分钟才能阅读完成。
引言
大家好,好久不见,时隔一年终于又拾起了写博客这件事。
在咱们日常工作中,咱们常须要用全局惟一 ID 作为数据库主键,或者用于生成订单 id,用于生成商品 ID 等等。本篇次要介绍咱们常见的 ID 生成器的形式:利用数据库生成和雪花算法。
利用数据库生成 ID
自增 ID 达成目标
利用 MYSQL 自增主键的个性来结构 ID 生成器。首先生成一张 ID 生成器表,每次咱们须要生成 ID 的时候在这个表里插入一行记录,获取到这行记录生成的主键 id,就能够拿到一个全局惟一 id,根本满足需要。
| id | ctime | |
---|---|---|
1 | 2021-09-05 12:00:00 | |
2 | 2021-09-05 12:01:00 |
尝试进阶
那么有的盆友们会说了,这个办法必定会影响性能啊,每次申请都须要去连贯 DB 获取 id,伤不起啊。没关系,咱们优化一下。咱们采纳分段申请,即每次申请一段 ID(例如 20 个 ID)缓存到本地,这样就只须要等本地 ID 应用完了再去申请了,减少了性能。到这又有敌人说了,每次批量插入数据性能还是不行,而且在多业务方同时应用的时候性能更差,这怎么办呢?别着急,往下看。
咱们能够将表设计成相似下表这个构造。
biz_tag(业务线) | max_id | step(每次申请 ID 数) | update_time |
---|---|---|---|
app | 1000 | 1000 | 2021-09-05 12:00:00 |
pc | 2000 | 1000 | 2021-09-05 12:00:00 |
从上表咱们能够看出,每次咱们申请 ID 的时候的大略流程是这样的:获取到以后的 max_id -> 拿业务线标识申请(max_id,max_id + step] 之间的 id -> id 应用完 -> 从新发动流程。这样 DB 的压力就会小很多,然而呢,在生产环境中也会存在一些问题:例如:
- 零碎性能依赖 DB 的更新,如果更新 DB 呈现尖刺,服务性能将收到影响
- 强依赖 DB 的可用性,DB 一旦呈现宕机将整个不可用
对于以上两个问题,咱们有以下解决思路:
- 预处理,当本地队列应用百分之七十的时候就去申请后新的 ID(比例依据业务需要设置)
- 在本地缓存一个队列作为“备胎”,当服务不可用且失常队列用完时能够应用“备胎”进行工作,并且一直的去申请新的队列。
如果咱们服务的会呈现突增流量的状况,咱们也能够动静的调整每次申请的 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 的生成,当然,业界还有很多种不同的规定,然而都是一个情理,大家能够依照本人的需要去解决。
关注咱们
欢送对本系列文章感兴趣的读者订阅咱们的公众号,关注博主下次不迷路~