為什么要生成分布式ID判族?
在復雜分布式系統(tǒng)中躺盛,往往需要對大量的數(shù)據(jù)和消息進行唯一標識。例如在游戲中形帮,游戲數(shù)據(jù)日漸增長槽惫,對數(shù)據(jù)分庫分表后需要有一個唯一ID來標識一條數(shù)據(jù)或消息周叮,數(shù)據(jù)庫的自增ID顯然不能滿足需求,那業(yè)務系統(tǒng)對ID號的要求有哪些呢界斜?
1)全局唯一性:不能出現(xiàn)重復的ID號仿耽,既然是唯一標識,這是最基本的要求各薇。
2)趨勢遞增:在MySQL InnoDB引擎中使用的是聚集索引项贺,由于多數(shù)RDBMS使用B-tree的數(shù)據(jù)結構來存儲索引數(shù)據(jù),在主鍵的選擇上面我們應該盡量使用有序的主鍵保證寫入性能峭判。
3)單調(diào)遞增:保證下一個ID一定大于上一個ID开缎,例如事務版本號、IM增量消息林螃、排序等特殊需求奕删。
4)信息安全:如果ID是連續(xù)的,惡意用戶的扒取工作就非常容易做了治宣,直接按照順序下載指定URL即可急侥;如果是訂單號就更危險了,競對可以直接知道我們一天的單量。所以在一些應用場景下派草,會需要ID無規(guī)則再愈、不規(guī)則。
1铝宵、UUID
使用網(wǎng)卡地址、時間戳和隨機數(shù)進行生成唯一ID华畏,Java中就自帶生成UUID的方法鹏秋。
優(yōu)點:本地即可生成,不需要網(wǎng)絡開銷
缺點:字符串占用內(nèi)存亡笑,不自增侣夷,對數(shù)據(jù)庫索引不友好,MySQL官方推薦不要使用
2仑乌、snowflake算法
1位:保留位不用百拓。二進制中最高位為1的都是負數(shù),但是我們生成的id一般都使用整數(shù)晰甚,所以這個最高位固定是0
41位:用來記錄時間戳(毫秒)衙传,41位可以表示2^41?1個數(shù)字,(2^41?1)/(1000?60?60?24?365)=69年
10位:用來記錄工作機器id
12位:序列號厕九,用來記錄同毫秒內(nèi)產(chǎn)生的不同id
優(yōu)點:存在自增趨勢蓖捶,只占用64位
缺點:強依賴機器時鐘
3、Flicker公司的解決方案
使用MySQL的auto_increment自增特性來生成唯一ID扁远。
創(chuàng)建優(yōu)惠券表:
CREATETABLEDiscount (idbigint(20)unsignedNOTNULLauto_increment,stubchar(1)NOTNULLdefault'',PRIMARYKEY(id),UNIQUEKEYstub (stub))ENGINE=InnoDB
獲取ID: 在一個事務中執(zhí)行如下sql俊鱼,replace和insert語句區(qū)別主要是replace在插入數(shù)據(jù)的時候刻像,如果數(shù)據(jù)存在(通過主鍵和唯一索引來查找)則先刪除,然后再進行插入亭引。
START TRANSACTION;
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
COMMIT;
上面這種方法只在單臺MySQL上生成ID绎速,從高可用角度考慮,接下來就要解決單點故障問題:可以啟用兩臺數(shù)據(jù)庫服務器來生成ID焙蚓,通過區(qū)分auto_increment的起始值和步長來生成奇偶數(shù)的ID纹冤。
DiscountServer1// 優(yōu)惠券服務1
auto-increment-increment =2// 自增值
auto-increment-offset =1// 起始值
DiscountServer2// 優(yōu)惠券服務2
auto-increment-increment =2// 自增
auto-increment-offset =2// 起始值
優(yōu)點:充分借助數(shù)據(jù)庫的自增ID機制,提供高可靠性购公,生成的ID有序萌京。
缺點:強依賴數(shù)據(jù)庫,占用兩個獨立的MySQL實例宏浩,有些浪費資源知残,成本較高,而且增刪MySQL實例很復雜比庄。
4求妹、MongoDB的ObjectId
MongoDB中我們經(jīng)常會接觸到一個自動生成的字段:”_id”,類型為ObjectId佳窑。上面方法中用到了MySQL數(shù)據(jù)庫時制恍,主鍵都是設置成自增的。但在分布式環(huán)境下神凑,這種方法就不可行了净神,會產(chǎn)生沖突。為此溉委,MongoDB采用了一個稱之為ObjectId的類型來做主鍵鹃唯。ObjectId是一個12字節(jié)的 BSON 類型字符串。
4字節(jié):UNIX時間戳3字節(jié):表示運行MongoDB的機器2字節(jié):表示生成此_id的進程3字節(jié):由一個隨機數(shù)開始的計數(shù)器生成的值
前9個字節(jié)保證了同一秒不同機器不同進程產(chǎn)生的ObjectId的唯一性瓣喊。后三個字節(jié)是一個自動增加的計數(shù)器(一個mongod進程需要一個全局的計數(shù)器)坡慌,保證同一秒的ObjectId是唯一的。同一秒鐘最多允許每個進程擁有(256^3 = 16777216)個不同的ObjectId藻三。
優(yōu)點:算法實現(xiàn)思路和snowflake類似八匠,但是相比更消耗空間