✅分布式ID生成方案都有哪些?

典型回答

在单体应用中,我们可以通过数据库的主键ID来生成唯一的ID,但是如果数据量变大,就需要进行分库分表,在分库分表之后,如何生成一个全局唯一的ID,就是一个关键的问题。

通常情况下,对于分布式ID来说,我们一般希望他具有以下几个特点:

  • 全局唯一:必须保证全局唯一性,这个是最基本的要求。
  • 高性能&高可用:需要保证ID的生成是稳定且高效的。
  • 递增:根据不同的业务情况,有的会要求生成的ID呈递增趋势,也有的要求必须单调递增(后一个ID必须比前一个大),也有的没有严格要求。

通常,在分布式ID的生成方案主要有以下6种:

  • UUID
  • 数据库自增ID
  • 号段模式
  • 基于Redis 实现
  • 雪花算法
  • 第三方ID生成工具

扩展知识

UUID

UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。

标准的UUID格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12),共32个字符,通常由以下几部分的组合而成:当前日期和时间,时钟序列,全局唯一的IEEE机器识别号

UUID的优点就是他的性能比较高,不依赖网络,本地就可以生成,使用起来也比较简单。


但是他也有两个比较明显的缺点,那就是长度过长和没有任何含义。长度自然不必说,他有32位16进制数字。对于"550e8400-e29b-41d4-a716-446655440000"这个字符串来说,我想任何一个程序员都看不出其表达的含义。一旦使用它作为全局唯一标识,就意味着在日后的问题排查和开发调试过程中会遇到很大的困难。

✅什么是UUID,能保证唯一吗?

用UUID当做分布式ID,存在着不适合范围查询、不方便展示以及查询效率低等问题。

✅uuid和自增id做主键哪个好,为什么?

数据库自增

分布式ID也可以使用数据库的自增ID,但是这种实现中就要求一定是一个单库单表才能保证ID自增且不重复,这就带来了一个单点故障的问题

一旦这个数据库挂了,那整个分布式ID的生成服务就挂了。而且还存在一个性能问题,如果高并发访问数据库的话,就会带来阻塞问题。

号段模式

号段模式是在数据库的基础上,为了解决性能问题而产生的一种方案。他的意思就是每次去数据库中取ID的时候取出来一批,并放在缓存中,然后下一次生成新ID的时候就从缓存中取。这一批用完了再去数据库中拿新的。

而为了防止多个实例之间发生冲突,需要采用号段的方式,即给每个客户端发放的时候按号段分开,如客户端A取的号段是1-1000,客户端B取的是1001-2000,客户端C取的是2001-3000。当客户端A用完之后,再来取的时候取到的是3001-4000。

号段模式的好处是在同一个客户端中,生成的ID是顺序递增的。并且不需要频繁的访问数据库,也能提升获取ID的性能。缺点是没办法保证全局顺序递增,也存在数据库的单点故障问题。

其实很多分库分表的中间件的主键ID的生成,主要采用的也是号段模式,如TDDL Sequence

Redis 实现

基于数据库可以实现,那么基于Redis也是可以的,我们可以依赖Redis的incr命令实现ID的原子性自增。

Redis的好处就是可以借助集群解决单点故障的问题,并且他基于内存性能也比较高。

但是Redis存在数据丢失的情况,无论是那种持久化机制,都无法完全避免。

✅Redis的持久化机制是怎样的?

雪花算法

什么是雪花算法,怎么保证不重复的?

第三方工具

除了以上方案以外,还有一些第三方的工具可以用来实现分布式ID,如百度的UidGenerator、美团的Leaf以及滴滴的Tinyid等等。

这些框架在功能上有的是整合了我们前面提到的多种实现方式,有的是针对不同的方式做了改进,如解决雪花算法的时钟拨回问题等。


原文: https://www.yuque.com/hollis666/xkm7k3/cdfb2w