赞
踩
分布式ID是指在分布式系统中用于唯一标识每个元素的数字或字符串。在分布式系统中,各个节点或服务可能独立运行在不同的服务器、数据中心或地理位置,因此需要一种机制来确保每个生成的ID都是全局唯一的,以避免ID冲突。
以下是分布式ID的一些关键特点:
全局唯一性:分布式ID必须保证在全系统中的唯一性,即使在大规模分布式环境中也能确保没有重复。
高可用性:分布式ID的生成机制需要高可用,确保在任何时候都能生成ID。
高性能:ID生成过程应该快速且对系统性能影响小。
高并发:在高并发场景下,分布式ID生成机制应能支持大量ID的生成。
无单点依赖:分布式ID的生成不应依赖于单个中心服务,以避免成为系统瓶颈。
易于分配:分布式ID应易于在各个节点上分配和生成。
可扩展性:随着系统规模的扩大,ID生成机制应能够水平扩展以满足需求。
安全性:分布式ID不应包含敏感信息,且不易被预测。
有序性:虽然不是严格要求,但在某些场景下,有序的ID可以帮助优化数据库存储和查询性能。
MongoDB内置分布式id是指在MongoDB数据库中,有一个内置的机制可以生成全局唯一的、递增的分布式id。这个分布式id被称为ObjectId。每当在MongoDB中创建一个新文档时,都会自动生成一个ObjectId作为该文档的唯一标识符。
mongodb分布式id思想有点类似于雪花算法。
ObjectId是一个12字节的唯一标识符,由以下三个部分组成:
由于ObjectId是全局唯一的,因此可以在分布式系统中使用它作为文档的唯一标识符,而不需要进行复杂的分布式id生成和管理。
对于一个特定的id,比如6641a6afda7b897ba34d5a81
前4个字节(8个十六进制),即6641a6af,将十六进制转为10进制的1715578543,单位为秒数,再乘以1000得到时间戳毫秒数,用js计算得到的即为生成id的时间(精确到秒)
最后3个字节(6个十六进制),即4d5a81,表示一个计数器,用于保证在同一秒产生的id不重复。3个字节,总共有3*8位,最大可表示2^24=16777216,一千六百多万,绝对够用的。
网上大部分都是说这个id只保证在同一个集合(表)里是唯一的,在不同集合是没有保证的。也就是说,假设有A,B,C三张表,自动生成的id保证在三张表内部是唯一的,但不同表之间的id可以重复。针对这个说法,笔者做了一个演示。
循环1w次,每次循环生成表1的id和表2的id,分别把生成id放到一个有序的集合里。
最后发现两个集合没有交集,也就是说,两个表的id不会重复,生成的id是全集合唯一的。
- public void testUid() {
- Set<String> set1 = new LinkedHashSet<>();
- Set<String> set2 = new LinkedHashSet<>();
- for (int i = 0; i < 10000; i++) {
- Table1 t = new Table1();
- table1Repository.insert(t);
- set1.add(t.getId());
-
- Table2 t2 = new Table2();
- table2Repository.insert(t2);
- set2.add(t2.getId());
- }
-
- System.out.println(set1);
- System.out.println(set2);
- System.out.println("两个表id交集" + Sets.intersection(set1, set2));
- }
从生成的id, 表1的第一个id为e9,表2的第一个元素为ea,表1的第二个id为eb,表2的第二个元素为ec... 刚好是十六进制的递增顺序。
至于出现这种情况是否为巧合,可能需要从mongodb源码找到答案。
虽然mongodo生成的id是全局唯一的,但过度依赖数据库生成id可能会给数据库带来压力,因此,也可以选择客户端api在应用程序内部生成id,再设置到数据库里。(如下为java版本相关API,存放于org.mongodb.bson依赖)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。