irpas技术客

mongoDB之ObjectId_你认识小汐吗_mongodb objectid

大大的周 4621

mongoDB之ObjectId 一、ObjectId介绍

????我们在使用mongodb插入数据时,每个document中必须有一个_id字段,且可以是任意类型,但如果没有单独设置_id字段,mongo会自动生成一个_id字段,类型是ObjectId,查看数据显示如下:

{ "_id": ObjectId("61cd13eb5b834a603764af44"), "age": 12, "name": "zhangsan", "classId": "61c16dffbd33627bc4fbbafe" }

????“61cd13eb5b834a603764af44”这个24位的字符串,实际上是由一组十六进制的字符构成,总共用了12字节的存储空间。相比MYSQL int类型的4个字节,MongoDB确实多出了很多字节。但是按照现在的设备配置,多出的字节数并不会成为瓶颈,这也体现了体现MongoDB空间换时间的设计思想。

二、ObjectId组成

ObjectId是一个12个字节的BSON数据,分成四个部分,其中:

前4个字节表示时间戳;接下来的3个字节是机器标识码;紧接的两个字节由进程id组成(PID);最后三个字节是自增计数器生成的随机数;

时间戳

????将刚才生成的objectid的前4位进行提取“61cd13eb”,然后按照十六进制转为十进制,变为“1640829931”,这个数字就是一个精确到秒时间戳。

机器标识码

????接下来的三个字节就是“5b834a”,这三个字节是所在主机的唯一标识符,一般是机器主机名的散列值,这样就确保了不同主机生成不同的机器hash值,确保在分布式中不造成冲突,这也就是在同一台机器生成的objectId中间的字符串都是一模一样的原因。

进程PID

????上面的【机器标识码】是为了确保在不同机器产生的objectId不冲突,而pid就是为了在同一台机器不同的mongodb进程产生了objectId不冲突,接下来的“6037”两位就是产生objectId的进程标识符。

自增计数器

????前面的九个字节是保证了一秒内不同机器不同进程生成objectId不冲突,这后面的三个字节“64af44”是一个自动增加的计数器,用来确保在同一秒内产生的objectId也不会发现冲突,允许256的3次方等于16777216条记录的唯一性。

????ObjectId的这个主键生成策略,很好解决了在分布式环境下高并发情况主键唯一性问题。

三、ObjectId常见问题 ObjectId的值总体上呈递增趋势,但不是绝对的

????ObjectId前4个字节存的是时间戳,而时间是递增的,所以ObjectId总体保证递增的顺序。 ????存储的时间戳只精确到秒,在同一台机器不同的MongoDB进程,同一秒内生成的ObjectId,进程ID小的会排在大的前面。存在这种情况,进程ID大的先生成ObjectId,但还是会排在进程ID小的后面。所以ObjectId递增不是绝对的。

ObjectId在一秒内生成的数量是有限的

????3个字节所能表达的最大的整数:2^24-1。所以一个MongoDB进程,在一秒内最多能生成 2^24-1 个ObjectId。从目前机器的性能来看,要超过这个限制几乎是不可能的。

ObjectId的唯一性

????ObjectId近似唯一,理论上会出现很小概率(1/(2^24-1))的重复情况,这取决于MongoDB驱动实现ObjectId方式。以C#官方驱动来说,构成ObjectId的计数器,C#使用Interlocked.Increment实现,保证了同一MongoDB进程在同一秒内生成的多个ObjectId的计数器是累加的,从而保证了生成的ObjectId是唯一的。 ????不过,有些版本的驱动是使用了随机数作为计数器,这种情况下并不能保证生成的ObjectId是唯一的。所以,除非你使用的是一个非常老的版本,或者很小众的驱动,否则都不需要为重复的ObjectId担心。


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #mongodb #ObjectId