分佈式 ID 生成策略

  1. MongoDB  objectid數據庫

    ObjectId 是"_id" 的默認類型。它設計成輕量型的,不一樣的機器都能用全局惟一的同種方法方便地生成它。這是MongoDB 採用ObjectId,而不是其餘比較常規的作法(好比自動增長的主鍵)的主要緣由,由於在多個服務器上同步自動增長主鍵值既費力還費時。MongoDB 從一開始就設計用來做爲分佈式數據庫,處理多個節點是一個核心要求。後面會看到ObjectId 類型在分片環境中要容易生成得多。

    ObjectId 使用12 字節的存儲空間,每一個字節兩位十六進制數字,是一個24 位的字符串。因爲看起來很長,很多人會以爲難以處理。但關鍵是要知道這個長長的ObjectId 是實際存儲數據的兩倍長。


    若是快速連續建立多個ObjectId,會發現每次只有最後幾位數字有變化。另外,中間的幾位數字也會變化(要是在建立的過程當中停頓幾秒鐘)。這是ObjectId 的建立方式致使的。12 字節按照以下方式生成:
    服務器

    前4 個字節是從標準紀元開始的時間戳,單位爲秒。這會帶來一些有用的屬性。時間戳,與隨後的. 5 個字節組合起來,提供了秒級別的惟一性。
    因爲時間戳在前,這意味着ObjectId 大體會按照插入的順序排列。這對於某些方面頗有用,如將其做爲索引提升效率,可是這個是沒有保證的,僅僅是「大體」。
    這4 個字節也隱含了文檔建立的時間。絕大多數驅動都會公開一個方法從ObjectId 獲取這個信息。
    由於使用的是當前時間,不少用戶擔憂要對服務器進行時間同步。其實沒有這個必要,由於時間戳的實際值並不重要,只要其老是不停增長就行了(每秒一次)。
    接下來的3 字節是所在主機的惟一標識符。一般是機器主機名的散列值。這樣就能夠確保不一樣主機生成不一樣的ObjectId,不產生衝突。
    爲了確保在同一臺機器上併發的多個進程產生的ObjectId 是惟一的,接下來的兩字節來自產生ObjectId 的進程標識符(PID)。
    前9 字節保證了同一秒鐘不一樣機器不一樣進程產生的ObjectId 是惟一的。後3 字節就是一個自動增長的計數器,確保相同進程同一秒產生的ObjectId 也是不同的。同一秒鐘最多容許每一個進程擁有2563(16 777 216)個不一樣的ObjectId併發

  2. @宇智波唐嫣     的實現方案 學習一下app

    目前我正在寫的 ID 生成服務的基本思路是這樣的:
    優勢是邏輯簡單,生成的 ID 短小,單個進程維護起來方便。缺點是知道生成的 ID 的上限(能夠用很大的塊部分解決)。
    分佈式

    ID 生成服務管理多個不一樣名字的 ID 池 (pool)。學習

        每種不一樣類型的 ID 屬於不一樣的 ID 池,好比知乎會有用戶 ID 池、回答 ID 池等等。spa

       每一個 ID 池由多個定長 ID 塊 (block) 構成。設計

       每一個 ID 塊包含一段連續的 ID,好比第一塊是從 0~1023,第二塊從 1024~2047,以此類推。日誌

       每一個 ID 塊並不徹底分配,而是按照一個給定的填充率 (fill ratio) 隨機選擇來分配,好比假設填充率是 50%,那麼每一個 ID 塊中只有大約一半的 ID 會被分配。也就是說每一個 ID 塊是有隨機空洞的。索引

        若是某個 ID 塊中可用 ID 被分配完畢,服務會自動生成下一個新的 ID 塊,並按照填充率去掉不可用 ID。生成新的 ID 塊時須要記錄下最後一個 ID 塊的起始 ID。

        已經分配過的 ID 會寫入一個 append-only 日誌。新的 ID 塊生成時會建立一個新的 append-only 日誌(由於舊的已經不須要了)。

        服務從新啓動的時候先拿到最後一個 ID 塊的起始 ID,再讀取 append-only 日誌將已經分配過的 ID 剔除,再剔除掉部分未分配的 ID 以維持填充率。

         客戶端發送請求訪問 ID 生成服務。服務端返回 ID 作爲回覆。

相關文章
相關標籤/搜索