作者 l 会点代码的大叔(CodeDaShu)
在分布式系统中,有一些场景需要使用全局唯一 ID ,可以和业务场景有关,比如支付流水号,也可以和业务场景无关,比如分库分表后需要有一个全局唯一 ID,或者用作事务版本号、分布式链路追踪等等,好的全局唯一 ID 需要具备这些特点:
那么分布式场景下有哪些生成唯一 ID 的方案呢?
01
利用数据库生成
先说最容易理解的方案,利用数据库的自增长序列生成:数据库生成唯一主键,并通过服务提供给其他系统;如果是小型系统,数据总量和并发量都不是很大的情况下,这种方案足够支撑。
如果每次生成一个 ID 可能会对数据库有压力,可以考虑一次性生成 N 个 ID 放入缓存中,如果缓存中的 ID 被取光,再通过数据库生成下一批 ID 。
02
利用其他组件/软件/中间件生成
利用 Redis / MongoDB / zookeeper 生成:Redis 利用 incr 和 increby ;MongoDB 的 ObjectId;zk 通过 znode 数据版本;都可以生成全局的唯一标识码。
我们用 MongoDB 的 ObjectId 来举例:
{"_id": ObjectId("5d47ca7528021724ac19f745")}
MongoDB 的 ObjectId 共占 12 个字节,其中:
不管是老版本还是新版本,MongoDB 的 ObjectId 至少都可以保证集群内的唯一,我们可以搭建一个全局唯一 ID 生成的服务,利用 MongoDB 生成 ObjectId 并对外提供服务(MongoDB 的各语言驱动都实现了 ObjectId 的生成算法)。
03
UUID
这个是分布式架构中,生成唯一标识码最常用的算法。为了保证 UUID 的唯一性,生成因素包括了MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素;UUID 有多个版本,每个版本的算法不同,应用范围也不同:
public class CreateUUID {
public static void main(String[] args) {
String uuid = UUID.randomUUID().toString();
System.out.println("uuid : " + uuid);
uuid = UUID.randomUUID().toString().replaceAll("-","");
System.out.println("uuid : " + uuid);
}
}
04
Snowflake
如果希望 ID 可以本地生成,但是又不要和 UUID 那样无序,可以考虑使用 Snowflake 算法(Twitter开源)。
SnowFlake 算法生成 ID 是一个 64 bit 的整数,包括:
在Java中,SnowFlake 算法生成的 ID 正好可以用 long 来进行存储。
此外,还有很多优秀的互联网公司也提供了唯一 ID 生成的方案或框架,比如美团开源的 Leaf ,百度开源的 UidGenerator 等等。
@Resource
private UidGenerator uidGenerator;
@Test
public void testSerialGenerate() {
// Generate UID
long uid = uidGenerator.getUID();
System.out.println(uidGenerator.parseUID(uid));
}