MongoDB文檔(Document)全局唯一ID的設(shè)計(jì)思路
在MongoDB中,如果不特別指定,每個(gè)文檔都會(huì)生成一個(gè)唯一的ObjectId作為其主鍵_id的值。這個(gè)值是一個(gè)看似隨機(jī)的串。這個(gè)串到底是什么值?為什么MongoDB要使用這個(gè)值作為默認(rèn)主鍵?它內(nèi)部又包含了什么樣的信息?如果你還不了解,就請(qǐng)看下面文章吧。
感謝劉浩@人民搜索的投稿。
MongoDB中數(shù)據(jù)的基本單元稱為文檔(Document)。文檔是MongoDB的核心概念,多個(gè)鍵極其關(guān)聯(lián)的值有序的放置在一起便是文檔。
在一個(gè)特定集合內(nèi)部,需要唯一的標(biāo)識(shí)文檔。因此MongoDB中存儲(chǔ)的文檔都由一個(gè)”_id”鍵,用于完成此功能。這個(gè)鍵的值可以是任意類型的,默認(rèn)試ObjectId對(duì)象。ObjectId對(duì)象的生成思路是本文的主題,也是很多分布式系統(tǒng)可以借鑒的思路。
為了考慮分布式,“_id”要求不同的機(jī)器都能用全局唯一的同種方法方便的生成它。因此不能使用自增主鍵(需要多臺(tái)服務(wù)器進(jìn)行同步,既費(fèi)時(shí)又費(fèi)力),因此選用了生成ObjectId對(duì)象的方法。
ObjectId使用12字節(jié)的存儲(chǔ)空間,其生成方式如下:
0 1 2 3 4 5 6 7 8 9 10 11
時(shí)間戳 機(jī)器ID PID 計(jì)數(shù)器
前四個(gè)字節(jié)時(shí)間戳是從標(biāo)準(zhǔn)紀(jì)元開(kāi)始的時(shí)間戳,單位為秒,有如下特性:
時(shí)間戳與后邊5個(gè)字節(jié)一塊,保證秒級(jí)別的唯一性;
保證插入順序大致按時(shí)間排序;
隱含了文檔創(chuàng)建時(shí)間;
機(jī)器ID是服務(wù)器主機(jī)標(biāo)識(shí),通常是機(jī)器主機(jī)名的散列值。
同一臺(tái)機(jī)器上可以運(yùn)行多個(gè)mongod實(shí)例,因此也需要加入進(jìn)程標(biāo)識(shí)符PID。
前9個(gè)字節(jié)保證了同一秒鐘不同機(jī)器不同進(jìn)程產(chǎn)生的ObjectId的唯一性。后三個(gè)字節(jié)是一個(gè)自動(dòng)增加的計(jì)數(shù)器(一個(gè)mongod進(jìn)程需要一個(gè)全局 的計(jì)數(shù)器),保證同一秒的ObjectId是唯一的。同一秒鐘最多允許每個(gè)進(jìn)程擁有(256^3 = 16777216)個(gè)不同的ObjectId。
總結(jié)一下:時(shí)間戳保證秒級(jí)唯一,機(jī)器ID保證設(shè)計(jì)時(shí)考慮分布式,避免時(shí)鐘同步,PID保證同一臺(tái)服務(wù)器運(yùn)行多個(gè)mongod實(shí)例時(shí)的唯一性,最后的計(jì)數(shù)器保證同一秒內(nèi)的唯一性(選用幾個(gè)字節(jié)既要考慮存儲(chǔ)的經(jīng)濟(jì)性,也要考慮并發(fā)性能的上限)。
“_id”既可以在服務(wù)器端生成也可以在客戶端生成,在客戶端生成可以降低服務(wù)器端的壓力。
|