外观
UUID、雪花算法保证分布式高并发电商系统订单号唯一
引言
在电商系统中,生成唯一的订单号至关重要,这关系到订单的准确追踪、管理和查询。
常用方法
1、数据库自增
原理:在数据库中给某个列设置为自增列,并且给该列设置一个初始值。每当有新的订单生成时,该列的值会自动增加,从而确保每个订单都有一个唯一的编号。
优点:实现简单,易于理解和维护。
缺点:在分布式系统或高并发环境下,数据库自增方式可能会遇到性能瓶颈,且当数据库进行分库分表时,订单号可能会重复。
2、UUID(通用唯一识别码)
原理:UUID 按照开放软件基金会(OSF)指定的标准进行计算,用到了以太网卡地址(MAC)、纳秒级时间、芯片 ID 码等,确保每个生成的 UUID 都是唯一的。
优点:全局唯一,生成简单。
缺点:可读性差,数据库查询效率较低,且 UUID 通常较长,不利于用户记忆和存储。
3、雪花算法(Snowflake)
原理:Twitter 开源的分布式 ID 生成算法,可以产生 64 位的 ID。其中第一位是固定的正数标识,41 位用于存储时间戳,剩下的为机器 ID 和序列号。通过时间戳、机器 ID 和序列号的组合,确保每个 ID 都是唯一的。
优点:生成速度快,全局唯一,适用于分布式系统和高并发环境。
缺点:生成的 ID 较长,不利于用户记忆和存储。
4、时间戳+随机数/自增长数字
原理:使用时间戳作为基础,然后加上随机数或自增长数字来确保唯一性。例如,“2023102912345678”(时间戳)+“987654”(随机数)或自增长数字。
优点:生成简单,可读性强(包含时间信息)。
缺点:在极端情况下(如高并发、大量订单生成时),可能会存在重复的风险。因此,需要确保随机数或自增长数字的位数足够长,以降低重复的概率。
5、自定义规则
原理:根据业务需求自定义订单号的生成规则。例如,可以使用“字母+数字”的组合方式,其中字母代表特定的业务含义(如订单类型、支付类型等),数字则用于确保唯一性。
优点:灵活性强,可以根据业务需求进行定制。
缺点:需要确保自定义规则的复杂性和唯一性足够高,以避免重复和冲突。同时,自定义规则可能不利于后续的维护和扩展。
UUID 介绍
UUID(Universally Unique Identifier,通用唯一识别码)是一种软件建构的标准,也是被开放软件基金会(OSF)的分布式计算环境(DCE)所采纳。UUID 的目的是让分布式系统中的所有元素都能有唯一的识别信息,而不需要通过中央控制端来分配。
UUID 由一组 32 个十六进制的数字组成(总共 36 个字符,包括 4 个连字符),通常被表示为 8-4-4-4-12 的形式,分为五段,形式为:xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx,其中 M 表示 UUID 的版本,N 为 UUID 的变体(Variants)。
UUID 的例子:
123e4567-e89b-12d3-a456-426614174000 这是一个标准的 UUID 格式,用于唯一标识某个对象或实体。
在实际应用中,UUID 的具体值是由算法生成的,确保在全球范围内是唯一的(尽管存在极小的碰撞概率)。UUID 广泛应用于数据库、软件、互联网等领域,用于确保数据的唯一性和一致性。
需要注意的是,虽然 UUID 的格式是固定的,但具体的值(即那些十六进制数字)是随机生成的,因此每次生成的 UUID 都是不同的(除非是通过相同的算法和相同的输入参数生成的)。
雪花算法介绍
雪花算法(Snowflake Algorithm)是 Twitter 开源的一种分布式唯一 ID 生成算法,它生成的 ID 并不是传统意义上的字符串,而是一个 64 位的长整型数字。这个 64 位的数字被划分为多个部分,每个部分都有其特定的含义。
以下是雪花算法生成的 ID 的详细结构和几个例子:
1、雪花算法 ID 的结构
1、符号位(1 位):最高位是符号位,始终为 0,这保证了生成的 ID 为正数。
2、时间戳(41 位):接下来的 41 位用于存储生成 ID 的时间戳,单位是毫秒。这 41 位可以表示的数字多达 2^41-1 个毫秒值,换算成年就是大约 69 年的时间。
3、机器 ID(10 位):再接下来的 10 位用于标识不同的机器或数据中心。这 10 位可以进一步细分为机房 ID(5 位)和机器 ID(5 位),但具体划分可以根据实际需求来调整。不过,总的机器 ID 位数是 10 位,这意味着最多可以支持 1024 台机器(2^10)。
4、序列号(12 位):最后的 12 位用于标识在同一毫秒内生成的不同 ID。这 12 位可以表示的最大正整数是 4095(2^12-1),也就是说,可以用这个 12 位的数字来区分同一个毫秒内的 4096 个不同的 ID。
2、雪花算法的示例
以下是几个雪花算法生成的结果(ID)示例,这些 ID 是 64 位的长整型数字,在十进制下的表示:
ID 示例 1: 十进制表示:6878880016384942081 备注:这个 ID 是假设在某个特定时间戳、某个特定机器 ID(如 1)和某个序列号(如 1)下生成的。
ID 示例 2: 十进制表示:6878880016384942082 备注:这个 ID 与示例 1 几乎相同,但序列号增加了 1,表示在同一毫秒内紧接着生成的下一个 ID。
ID 示例 3: 十进制表示:6878880016385786881 备注:这个 ID 与示例 1 和示例 2 在时间戳上有所不同(假设是下一毫秒),机器 ID 相同,序列号为 1,表示在新的一毫秒内生成的第一个 ID。
ID 示例 4: 十进制表示:6878880017418326017 备注:这个 ID 与前面的示例在时间戳和机器 ID 上都有所不同,表示在不同时间、不同机器上生成的 ID。
上述 ID 示例是假设性的,实际生成的雪花算法 ID 将取决于生成时的具体时间戳、机器 ID 配置和序列号。由于雪花算法生成的 ID 是全局唯一的,因此在实际应用中,每个 ID 都是独一无二的,不会与其他 ID 重复。
另外,由于雪花算法生成的 ID 包含了时间戳信息,因此它们还具有时间有序性,即可以按照 ID 的大小来判断生成的时间先后顺序。这一特性使得雪花算法在分布式系统中具有广泛的应用价值。
3、雪花算法的二进制与十进制
雪花算法生成的结果是 64 位的长整型数字,这是指其在二进制形式下的位数。然而,当将这些二进制数字转换为十进制表示时,其长度并不是固定的 64 位数字,而是取决于该二进制数字在十进制下的具体值。
在二进制系统中,一个 64 位的数字可以表示的最大值是 2^64-1,这是一个非常大的数。但是,在十进制系统中,这个数会被表示为一个远少于 64 位的数字(尽管其实际值仍然是一个 64 位二进制数所能表示的范围内的数)。例如,二进制数“1111111111111111111111111111111111111111”(64 个 1)在十进制下表示为“18446744073709551615”,这是一个 19 位的十进制数。
因此,在理论上,一个 64 位的二进制数可以表示的最大值是 2^64-1,即 18446744073709551615。这个数在十进制下是一个 19 位的数字。但是,雪花算法生成的 ID 并不会每次都达到这个最大值,因此其十进制表示的长度通常会小于 19 位。
总结
雪花算法在正常情况下能够高效地生成全局唯一的 ID。然而,在极端情况下(如时钟回拨、序列号溢出或网络分区等),理论上仍然存在生成重复 ID 的可能性。因此,在使用雪花算法时,需要充分考虑这些潜在风险,并采取相应的措施来降低重复 ID 的概率。