一.生成邏輯與組成部分
ObjectId的生成過程由四個核心組件協作完成,總計12字節(24位十六進制字符串)13:
1.時間戳(4字節)
- 採用Unix時間戳(從1970年1月1日UTC開始的秒數),寫入時取當前時間的秒級精度值。
- 例如:時間戳641c54b2(十六進制)轉換為十進制為1679507122,對應2023年3月23日15:05:22 UTC。
-
作用:保證生成的ID按時間有序排列,便於範圍查詢和索引優化。
2.機器標識(3字節)
- 基於運行MongoDB實例的主機名或MAC地址的哈希值生成,確保不同機器的ID不重複。
-
例如:主機名server01.example.com通過哈希算法轉換為e67400。
3. 進程ID(2字節)
- 使用生成ID時的進程PID(Process ID),避免同一台機器上不同MongoDB進程產生衝突。
-
例如:PID0035對應十進制53,表示MongoDB服務的進程號。
4.計數器(3字節)
- 初始值為隨機數,後續每次生成ID時遞增,確保同一進程同一秒內可生成最多16,777,216個唯一ID(256^3)。
-
例如:計數器001dc2表示首次生成時隨機起始值,下一次生成時變為001dc3。
二.生成流程
1.初始化階段
-
進程啓動時計算並緩存機器標識和進程PID,後續生成ID時直接複用。
2.運行時生成
生成步驟:
- 獲取當前時間的秒級Unix時間戳 → 轉換為4字節十六進制
- 加載預緩存的3字節機器標識
- 獲取當前進程的2字節PID
- 從計數器中讀取當前值 → 轉換為3字節 → 計數器+1
-
拼接四部分生成完整ObjectId
原子性保障:計數器使用原子操作保證併發場景下的線程安全。
3. 唯一性與有序性原理
- 全局唯一:通過“機器標識+進程PID+計數器”三重機制,即使分佈式系統中多節點同時生成ID也不會重複。
-
時間有序:時間戳作為ID前綴,使得按_id排序等價於按插入時間排序。
4. 手動生成示例
通過MongoDB驅動可手動生成ObjectId:
// Node.js示例:手動生成ObjectId
const { ObjectId } = require('mongodb');
const id = new ObjectId();
console.log(id.toHexString()); // 輸出:641c54b2e674000035001dc2驅動內部遵循相同生成規則,保證與數據庫自動生成的ID兼容。
5. 性能與擴展性
- 高效生成:無鎖設計+本地計算,每秒可生成百萬級ID。
-
空間優化:相比UUID(16字節),ObjectId節省4字節存儲空間。
通過以上機制,MongoDB的ObjectId在分佈式環境下實現了高效、唯一且有序的ID生成能力