继上一篇《MongoDB初窥》之后,想必大家对自动生成的主键objectId有所好奇,为什么会是一个24位的字符串。今天,就对objectId的生成原理做一次比较深入的挖掘。

一、     ObjectId的组成

首先通过终端命令行,向mongodb的collection中插入一条不带“_id”的记录。然后,通过查询刚插入的数据,发现自动生成了一个objectId,4e7020cb7cac81af7136236b。具体操作如图1所示。

图1 插入/查询数据

“4e7020cb7cac81af7136236b”这个24位的字符串,虽然看起来很长,也很难理解,但实际上它是由一组十六进制的字符构成,每个字节两位的十六进制数字,总共用了12字节的存储空间。相比MYSQL int类型的4个字节,MongoDB确实多出了很多字节。不过按照现在的存储设备,多出来的字节应该不会成为什么瓶颈。不过MongoDB的这种设计,体现着空间换时间的思想。官网中对ObjectId的规范,如图2所示。

图2 官网对ObjectId的规范

1)     Time

时间戳。将刚才生成的objectid的前4位进行提取“4e7020cb”,然后按照十六进制转为十进制,变为“1315971275”,这个数字就是一个时间戳。通过时间戳的转换,就成了易看清的时间格式,如图3所示。

图3 时间戳的转换

2)    Machine

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

3)    PID

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

4)    INC

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

总的来看,objectId的前4个字节时间戳,记录了文档创建的时间;接下来3个字节代表了所在主机的唯一标识符,确定了不同主机间产生不同的objectId;后2个字节的进程id,决定了在同一台机器下,不同mongodb进程产生不同的objectId;最后通过3个字节的自增计数器,确保同一秒内产生objectId的唯一性。ObjectId的这个主键生成策略,很好地解决了在分布式环境下高并发情况主键唯一性问题,值得学习借鉴。

二、     源码分析

MongoDB可以通过自身的服务来产生objectId,也可以通过客户端的驱动程序来生成objectId。虽然objectId是轻量级的,但如果全部在服务端生成肯定会花费一点开销。所以,能从服务器端转移到客户端驱动程序完成的,就尽量转移到客户端来完成,减少服务器端的开销。我们来看一下,客户端的驱动程序是如何来生成objectId的。

1、下载mongodb java driver源码。 (https://github.com/mongodb/mongo-java-driver/downloads)

2、分析ObjectId.java

驱动源码的org.bson包下找到ObjectId.java,进行分析。默认构建的objectId代码如下代码所示,objectId主要由_time,_machine和_inc组成。

构建objectId

  1)     _time

直接由System.currentTimeMillis()/1000计算得出的时间戳。

2)    _machine

由机器码(machinePiece)和进程码(processPiece)组成,如代码所示。它这里组成方式是:首先,通过NetworkInterface这个类,获取机器的所有网络接口信息(如图4所示),并将得到的字符串取散列值,就得到了机器码;然后通过RuntimeMXBean.getName()方法获取pid,再拼装classloaderid,得到进程码;最后将机器码和进程码进行位或运算得到_machine。不过这里生成的_machine是十进制的,需转成十六进制。

图4 本地调试时的网络接口部分信息

机器码和进程码的生成

3)    _inc

自增数是通过AtomicInteger的getAndIncrement()方法获取,它能保证每次得到的值是一个递增并不重复的值。

三、  更多参考

1、          http://www.mongodb.org/display/DOCS/Object+IDs

MongoDB深究之ObjectId相关推荐

  1. MongoDB中_id(ObjectId)生成

    MongoDB 中我们经常会接触到一个自动生成的字段:"_id",类型为ObjectId. 之前我们使用MySQL等关系型数据库时,主键都是设置成自增的.但在分布式环境下,这种方法 ...

  2. C# 生成 MongoDB 中的 ObjectId

    ObjectId介绍 在MongoDB中,文档(document)在集合(collection)中的存储需要一个唯一的_id字段作为主键.这个_id默认使用ObjectId来定义,因为ObjectId ...

  3. 2021-05-12 MongoDB面试题 “ObjectID“有哪些部分组成

    "ObjectID"有哪些部分组成 一共有四部分组成:时间戳.客户端ID.客户进程ID.三个字节的增量计数器. _id是一个 12 字节长的十六进制数,它保证了每一个文档的唯一性. ...

  4. mysql objectid_在mysql中使用MongoDB中的ObjectId

    其实很简单.您只需要使用 mongodb 像平常一样打包和声明实体. 首先,安装mongodb依赖项: yarn add mongodb yarn add @types/mongodb 然后,声明你的 ...

  5. php mongodb oid,MongoDB $oid vs ObjectId

    我正在尝试让 mongodb查询工作.集合的格式如下: { "_id": { "$oid": "54651022bffebc03098b4567&qu ...

  6. 如何使用MongoDB+Springboot实现分布式ID?

    转载请标明出处: http://blog.csdn.net/forezp/article/details/69056017 本文出自方志朋的博客 一.背景 如何实现分布式id,搜索相关的资料,一般会给 ...

  7. [MongoDB] 运维相关操作记录

    前言 前段时间. 实战操作了下MongoDB. 在此将操作记录总结一下. MongoDB 相关Bin localhost:bin sean$ pwd /Users/sean/Software/Mong ...

  8. 程序员,你需要些“脑力运动”了

    程序员,你需要些"脑力运动"了 [读书笔记]开发你的大脑--图像记忆法 1   前言 最近看了一本关于记忆的书,叫<超级记忆力-图像记忆法>,看完之后发现一些有意思的东 ...

  9. mongoose和mongodb的几篇文章 (ObjectId,ref)

    http://mongoosejs.com/docs/populate.html http://stackoverflow.com/questions/6578178/node-js-mongoose ...

最新文章

  1. Android:ViewPager为页卡内视图组件添加事件
  2. HCNA多区域OSPF配置
  3. centos 7 局域网丢包排查_ethtool原理介绍和解决网卡丢包排查思路
  4. pstools套件在渗透中的应用详解
  5. Zabbix 添加端口监控链接
  6. 如何在Ubuntu里安装Helm
  7. 1052 卖个萌 (20 分)
  8. Spring4.x整合Axis1.4发布WebService服务
  9. Python3高级 之 协程
  10. Java创建Timestamp的几种方式
  11. ubuntu中安装sqldeveloper和JDK 1.7
  12. EA(Enterprise Architecture,企业架构)
  13. asp.net页面去调用通过SSL加密的webservice报错
  14. Linux学习笔记----01
  15. 《团队领导力》培训笔记
  16. Java端实现JSHOP2的调用
  17. 帧间预测--AMVP模式理论部分
  18. Problem D 筛法求素数
  19. PCF8574AT驱动LCD1602
  20. websocketpp wss

热门文章

  1. MySQL创建数据库指定编码和排序规则,mysql数据库密码重置
  2. linux mkfs 源码,Linux系统下移植busybox中mkfs.vfat命令
  3. [反重力与飞行]需要精确计算力场的数值
  4. html5通话记录,中国移动手机通话记录怎么查 苹果手机的通话记录怎么查
  5. zeppelin的安装以及使用
  6. linux 增量 cp,Linux 中 cp 命令(文件复制)
  7. java快速数据度数抵导入_java – 使用扫描仪从.txt文件读取度数符号
  8. 微信小程序之音乐播放器
  9. 加密世界的价值捕获:谁是超级捕获者?
  10. html设置距离页面上距离,html上下间距怎么调