溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

理解MongoDB默認(rèn)的ObjectID

發(fā)布時(shí)間:2020-06-25 16:43:47 來(lái)源:網(wǎng)絡(luò) 閱讀:2611 作者:ztfriend 欄目:MongoDB數(shù)據(jù)庫(kù)

BSON ObjectID Specification

A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure a mostly increasing order. The format:

 

0 1 2 3 4 5 6 7 8 9 10 11
time machine pid inc

 

  • TimeStamp. This is a unix style timestamp. It is a signed int representing the number of seconds before or after January 1st 1970 (UTC).
  • Machine. This is the first three bytes of the (md5) hash of the machine host name, or of the mac/network address, or the virtual machine id.
  • Pid. This is 2 bytes of the process id (or thread id) of the process generating the object id.
  • Increment. This is an ever incrementing value, or a random number if a counter can't be used in the language/runtime.

BSON ObjectIds can be any 12 byte binary string that is unique; however, the server itself and almost all drivers use the format above.

分段查看ObjectId的指令及結(jié)果如下:

  1. > db.test.findOne()._id.toString()  
  2. ObjectId("50c6b336ba95d7738d1042e3")  
  3. > db.test.findOne()._id.toString().substring(10,18)  
  4. 50c6b336  
  5. > db.test.findOne()._id.toString().substring(18,24)  
  6. ba95d7  
  7. > db.test.findOne()._id.toString().substring(24,28)  
  8. 738d  
  9. > db.test.findOne()._id.toString().substring(28,34)  
  10. 1042e3 

ObjectId占用12字節(jié)的存儲(chǔ)空間,由“時(shí)間戳” 、“機(jī)器名”、“PID號(hào)”和“計(jì)數(shù)器”組成。使用機(jī)器名的好處是在分布式環(huán)境中能夠避免單點(diǎn)計(jì)數(shù)的性能瓶頸。使用PID號(hào)的好處是支持同一機(jī)器內(nèi)運(yùn)行多個(gè)mongod實(shí)例。最終采用時(shí)間戳和計(jì)數(shù)器的組合來(lái)保證唯一性。

時(shí)間戳

確保ObjectId唯一性依賴的是時(shí)間的順序,不依賴時(shí)間的取值,因此集群節(jié)點(diǎn)的時(shí)間不必完全同步。既然ObjectId已經(jīng)有了時(shí)間戳,那么在文檔中就可以省掉一個(gè)時(shí)間戳了。在使用ObjectID提取時(shí)間時(shí),應(yīng)注意到MongoDB允許各節(jié)點(diǎn)時(shí)間不一致這一細(xì)節(jié)。

下面是查看時(shí)間戳的兩種寫法:

  1. > db.test1.findOne()._id.getTimestamp()
  2. ISODate("2012-12-12T03:52:45Z")
  3. > Date(parseInt(db.test1.findOne()._id.toString().substring(10,18),16))
  4. Wed Dec 12 2012 12:11:02 GMT+0800

機(jī)器名

機(jī)器名通過(guò)Md5加密后取前三個(gè)字節(jié),應(yīng)該還是有重復(fù)概率的,配置生產(chǎn)集群時(shí)檢查一下總不會(huì)錯(cuò)。另外,我也注意到重啟MongoDB后MD5加密結(jié)果會(huì)發(fā)生變化,在利用ObjectID提取機(jī)器名信息時(shí)需格外注意。

PID號(hào)

注意到每次重啟mongod進(jìn)程后PID號(hào)通常會(huì)發(fā)生變化就可以了。

計(jì)數(shù)器

計(jì)數(shù)器占3個(gè)字節(jié),表示的取值范圍就是256*256*256-1=16777215。不妨認(rèn)為MongDB性能的極限是單臺(tái)設(shè)備一秒鐘插入一千萬(wàn)條記錄。以目前的水平看,單臺(tái)設(shè)備一秒鐘插入一萬(wàn)條就很不錯(cuò)了,因此ObjectID計(jì)數(shù)器的設(shè)計(jì)是夠用的。

循環(huán)插入了一些記錄,下面的查詢中b是循環(huán)計(jì)數(shù)器,可以看出我機(jī)器上的ObjectId計(jì)數(shù)器是按順序增加的:

  1. > parseInt(db.test.findOne({b:1000})._id.toString().substring(28,34),16)  
  2. 1947382  
  3. > parseInt(db.test.findOne({b:1001})._id.toString().substring(28,34),16)  
  4. 1947383  
  5. > parseInt(db.test.findOne({b:1002})._id.toString().substring(28,34),16)  
  6. 1947384  
  7. > parseInt(db.test.findOne({b:1003})._id.toString().substring(28,34),16)  
  8. 1947385 

以下代碼源自:http://www.cnblogs.com/xjk15082/archive/2011/09/18/2180792.html

  1. 構(gòu)建objectId   
  2.  public class ObjectId implements Comparable<ObjectId> , java.io.Serializable {  
  3.  final int _time;  
  4.      final int _machine;  
  5.      final int _inc;  
  6.  boolean _new;  
  7.    
  8.  public ObjectId(){  
  9.          _time = (int) (System.currentTimeMillis() / 1000);  
  10.          _machine = _genmachine;  
  11.          _inc = _nextInc.getAndIncrement();  
  12.          _new = true;  
  13.  }  
  14.  ……  
  15.  } 
  1. 機(jī)器碼和進(jìn)程碼的生成  
  2.  private static final int _genmachine;  
  3.  static {  
  4.  try {  
  5.  final int machinePiece;  
  6.          {  
  7.  StringBuilder sb = new StringBuilder();  
  8.              Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();  
  9.              while ( e.hasMoreElements() ){  
  10.                  NetworkInterface ni = e.nextElement();  
  11.                  sb.append( ni.toString() );  
  12.              }  
  13.              machinePiece = sb.toString().hashCode() << 16;  
  14.              LOGGER.fine( "machine piece post: " + Integer.toHexString( machinePiece ) );  
  15.  }  
  16.  final int processPiece;  
  17.          {  
  18.              int processId = new java.util.Random().nextInt();  
  19.              try {  
  20.  processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();  
  21.  }catch ( Throwable t ){  
  22.  }  
  23.  ClassLoader loader = ObjectId.class.getClassLoader();  
  24.              int loaderId = loader != null ? System.identityHashCode(loader) : 0;  
  25.  StringBuilder sb = new StringBuilder();  
  26.              sb.append(Integer.toHexString(processId));  
  27.              sb.append(Integer.toHexString(loaderId));  
  28.              processPiece = sb.toString().hashCode() & 0xFFFF;  
  29.              LOGGER.fine( "process piece: " + Integer.toHexString( processPiece ) );  
  30.          }  
  31.  _genmachine = machinePiece | processPiece;  
  32.          LOGGER.fine( "machine : " + Integer.toHexString( _genmachine ) );  
  33.      }catch ( java.io.IOException ioe ){  
  34.          throw new RuntimeException( ioe );  
  35.      }  
  36.  } 

 

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI