唯一ID的设计

2023-01-08  本文已影响0人  菜鸡前端

一、背景概述

在应用程序中,很多时候会用到全局唯一的id,比如用户ID,订单ID等等,因此在架构设计中,全局唯一的id生成服务作为公共基础服务是整个项目的基石之一。然而,设计一个满足不重复、高性能、高可用的分布式id服务并不容易:

二、设计方案

2.1 UUID 方案

UUID是通用唯一识别码(Universally Unique Identifier)的缩写,基于当前时间、计数器(counter)和硬件标识(通常为网卡的MAC地址)等数据计算生成的,因此可以做到全局唯一。Java本身提供UUID类,因此使用UUID可以满足不重复、高性能、高可用三方面的要求。

因此,此方案非常适合对id无顺序、无长度和无纯数字要求的场景,比如在分布式应用场景中,为了排查问题方便,多个服务之间会使用一个唯一id串起来整个请求的链路,比如对于TCP长连接协议的服务端,需要一个连接id标识每个连接。

2.2 数据库自增

利用数据库的自增特性,以 MySQL 举例,利用给字段设置 auto_increment_increment 和auto_increment_offset 来保证ID自增,且全局唯一。

因此,此方案仅适用对性能要求不高,且必须为纯数字递增的场景,如用户id。

2.3 类snowflake方案

snowflake是Twitter以划分命名空间来生成ID的一种算法,在实际应用中我们可以借鉴其算法模型生成满足自己要求的全局唯一id。
snowflake算法把时间戳,工作机器id,序列号组合在一起。总共64bit,设计如下:


image.pngimage.png

snowflake 只是提供了一种算法思路,因此呢,我们可以根据业务的实际情况来调整各段所占的bit数,比如机器id不需要使用 10 位,可以预留更多的位数给自增数使用。因此应该灵活变通。

因此,此方案适用于在UUID不能满足的场景下,可以优先考虑的方案,如订单号,聊天消息id等等。

2.4 redis自增操作方案

利用 redis 的原子自增操作(incr命令)生成一个自增的序列,由于redis本身为单线程工作模式(6.0版本支持多线程,但是目前还属于beta版本,预计2020年5月才正式发布),因此可以天然的保证不会存在重复,而且redis本身的高性能,可以满足性能要求。

因此,此方案适用于生成QQ号这样纯数字,且递增,并对性能有较高要求的场景,但是依赖redis,需要考虑与其他业务共用redis存在的问题,比如持久化可能会影响redis性能。

2.5 类美团 Leaf方案

美团的 Leaf 方案使用本地缓存+MySQL实现高性能、高可用且全局唯一的纯数字id,在业务实现过程中可以借鉴其设计思路。
在第2种方案中,我们知道基于MySQL的方案最大问题是性能问题,因此美团Leaf进行了优化,应用服务到数据库取id的时候,每次不再是只取一个id,而是取一个范围的id,称之为步长,假如为1000,那么只有当这1000个值使用完后才会再去访问数据库,因此提升了性能。
数据库设计一张id_table的表,如下:
[图片上传失败...(image-6dafe0-1673276567734)]

应用程序通过以下两条sql语句完成取值:

Begin
UPDATE table SET max_id=max_id+step WHERE biz_tag=xxx
SELECT max_id, step FROM table WHERE biz_tag=xxx
Commit

由于应用程序是拿到一个步长范围内的id值,因此在应用程序中还需要进行id的分配,因此,应用程序需要通过锁/CAS的方式保证id分配时不因为并发而出现重复。所有对开发人员有较强的要求。为了避免每个开发人员/模块重复造轮子,因此可以将此服务独立出来。架构设计演变为如下:


image.pngimage.png

Leaf服务可以通过集群提升服务的性能和增加可用性。
此外美团还提供了双buffer思想,进一步提升服务性能,即在Leaf服务内,当第一个步长值快要使用完毕之前,异步去数据库取下一个步长的值,这样不会存在当Leaf的id值分配完了,再去数据库取值出现性能问题。
目前,美团的Leaf已经开源,在我的业务使用时,此方案并没有开源,因此我个人参照此思路实现了我们业务的Leaf服务,主要需要考虑的是并发问题导致的id分配重复,另外双buffer思想实现起来非常繁琐,如果对性能要求不是非常极致,可以不考虑,而是通过3节点的Leaf服务即可满足。

1)纯数字
2)趋势递增
3)只依赖数据库,因为几乎所有服务都需要数据库,相当于未增加第三方依赖。
4)满足高性能和高可用的要求。

因此,适用的场景是对性能要求很高,且为趋势递增的纯数字场景,而且不能因为任何原因而丢失数据导致ID重复的场景,如用户的id号。

三、总结

以上提供了5种最常见和实用的唯一id生成方案,可以根据自己的业务实际情况进行选择,总体原则是选实现最简单的,只要能满足业务需要即可,越复杂的方案越容易出错。

上一篇 下一篇

猜你喜欢

热点阅读