游戲服務(wù)器架構(gòu)系列 - 分布式ID生成

為什么要生成分布式ID?

在復(fù)雜分布式系統(tǒng)中,往往需要對(duì)大量的數(shù)據(jù)和消息進(jìn)行唯一標(biāo)識(shí)。例如在游戲中,游戲數(shù)據(jù)日漸增長(zhǎng),對(duì)數(shù)據(jù)分庫(kù)分表后需要有一個(gè)唯一ID來(lái)標(biāo)識(shí)一條數(shù)據(jù)或消息,數(shù)據(jù)庫(kù)的自增ID顯然不能滿足需求,那業(yè)務(wù)系統(tǒng)對(duì)ID號(hào)的要求有哪些呢?

1)全局唯一性:不能出現(xiàn)重復(fù)的ID號(hào),既然是唯一標(biāo)識(shí),這是最基本的要求。

2)趨勢(shì)遞增:在MySQL InnoDB引擎中使用的是聚集索引,由于多數(shù)RDBMS使用B-tree的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)索引數(shù)據(jù),在主鍵的選擇上面我們應(yīng)該盡量使用有序的主鍵保證寫(xiě)入性能。

3)單調(diào)遞增:保證下一個(gè)ID一定大于上一個(gè)ID,例如事務(wù)版本號(hào)、IM增量消息、排序等特殊需求。

4)信息安全:如果ID是連續(xù)的,惡意用戶的扒取工作就非常容易做了,直接按照順序下載指定URL即可;如果是訂單號(hào)就更危險(xiǎn)了,競(jìng)對(duì)可以直接知道我們一天的單量。所以在一些應(yīng)用場(chǎng)景下,會(huì)需要ID無(wú)規(guī)則、不規(guī)則。

1、UUID

使用網(wǎng)卡地址、時(shí)間戳和隨機(jī)數(shù)進(jìn)行生成唯一ID,Java中就自帶生成UUID的方法。

優(yōu)點(diǎn):本地即可生成,不需要網(wǎng)絡(luò)開(kāi)銷

缺點(diǎn):字符串占用內(nèi)存,不自增,對(duì)數(shù)據(jù)庫(kù)索引不友好,MySQL官方推薦不要使用

2、snowflake算法

1位:保留位不用。二進(jìn)制中最高位為1的都是負(fù)數(shù),但是我們生成的id一般都使用整數(shù),所以這個(gè)最高位固定是0

41位:用來(lái)記錄時(shí)間戳(毫秒),41位可以表示2^41?1個(gè)數(shù)字,(2^41?1)/(1000?60?60?24?365)=69年

10位:用來(lái)記錄工作機(jī)器id

12位:序列號(hào),用來(lái)記錄同毫秒內(nèi)產(chǎn)生的不同id

優(yōu)點(diǎn):存在自增趨勢(shì),只占用64位

缺點(diǎn):強(qiáng)依賴機(jī)器時(shí)鐘

3、Flicker公司的解決方案

使用MySQL的auto_increment自增特性來(lái)生成唯一ID。

創(chuàng)建優(yōu)惠券表:

CREATETABLEDiscount (idbigint(20)unsignedNOTNULLauto_increment,stubchar(1)NOTNULLdefault'',PRIMARYKEY(id),UNIQUEKEYstub (stub))ENGINE=InnoDB

獲取ID: 在一個(gè)事務(wù)中執(zhí)行如下sql,replace和insert語(yǔ)句區(qū)別主要是replace在插入數(shù)據(jù)的時(shí)候,如果數(shù)據(jù)存在(通過(guò)主鍵和唯一索引來(lái)查找)則先刪除,然后再進(jìn)行插入。

START TRANSACTION;

REPLACE INTO Tickets64 (stub) VALUES ('a');

SELECT LAST_INSERT_ID();

COMMIT;

上面這種方法只在單臺(tái)MySQL上生成ID,從高可用角度考慮,接下來(lái)就要解決單點(diǎn)故障問(wèn)題:可以啟用兩臺(tái)數(shù)據(jù)庫(kù)服務(wù)器來(lái)生成ID,通過(guò)區(qū)分auto_increment的起始值和步長(zhǎng)來(lái)生成奇偶數(shù)的ID。

DiscountServer1// 優(yōu)惠券服務(wù)1

auto-increment-increment =2// 自增值

auto-increment-offset =1// 起始值

DiscountServer2// 優(yōu)惠券服務(wù)2

auto-increment-increment =2// 自增

auto-increment-offset =2// 起始值

優(yōu)點(diǎn):充分借助數(shù)據(jù)庫(kù)的自增ID機(jī)制,提供高可靠性,生成的ID有序。

缺點(diǎn):強(qiáng)依賴數(shù)據(jù)庫(kù),占用兩個(gè)獨(dú)立的MySQL實(shí)例,有些浪費(fèi)資源,成本較高,而且增刪MySQL實(shí)例很復(fù)雜。

4、MongoDB的ObjectId

MongoDB中我們經(jīng)常會(huì)接觸到一個(gè)自動(dòng)生成的字段:”_id”,類型為ObjectId。上面方法中用到了MySQL數(shù)據(jù)庫(kù)時(shí),主鍵都是設(shè)置成自增的。但在分布式環(huán)境下,這種方法就不可行了,會(huì)產(chǎn)生沖突。為此,MongoDB采用了一個(gè)稱之為ObjectId的類型來(lái)做主鍵。ObjectId是一個(gè)12字節(jié)的 BSON 類型字符串。

4字節(jié):UNIX時(shí)間戳3字節(jié):表示運(yùn)行MongoDB的機(jī)器2字節(jié):表示生成此_id的進(jìn)程3字節(jié):由一個(gè)隨機(jī)數(shù)開(kāi)始的計(jì)數(shù)器生成的值

前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。

優(yōu)點(diǎn):算法實(shí)現(xiàn)思路和snowflake類似,但是相比更消耗空間

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,288評(píng)論 2 89
  • 一,題記 所有的業(yè)務(wù)系統(tǒng),都有生成ID的需求,如訂單id,商品id,文章ID等。這個(gè)ID會(huì)是數(shù)據(jù)庫(kù)中的唯一主鍵,在...
    eonhu閱讀 10,473評(píng)論 0 8
  • 一,題記 所有的業(yè)務(wù)系統(tǒng),都有生成ID的需求,如訂單id,商品id,文章ID等。這個(gè)ID會(huì)是數(shù)據(jù)庫(kù)中的唯一主鍵,在...
    架構(gòu)師小秘圈閱讀 4,139評(píng)論 1 18
  • 這篇文章總結(jié)了分布式主鍵或者唯一鍵的生成算法,文章最后有我們基于snowflow算法的思考和實(shí)踐。 分布式主鍵的生...
    彥幀閱讀 2,771評(píng)論 0 5
  • MYSQL 基礎(chǔ)知識(shí) 1 MySQL數(shù)據(jù)庫(kù)概要 2 簡(jiǎn)單MySQL環(huán)境 3 數(shù)據(jù)的存儲(chǔ)和獲取 4 MySQL基本操...
    Kingtester閱讀 8,058評(píng)論 5 115

友情鏈接更多精彩內(nèi)容