id作為業(yè)務(wù)的唯一標(biāo)識(shí),在數(shù)據(jù)設(shè)計(jì)中屢見不鮮,例如:
?商品 —— product_id
?訂單 —— order_id
?消息 —— message_id
這些標(biāo)識(shí)往往就是數(shù)據(jù)庫(kù)的主鍵,mysql會(huì)在主鍵是建立聚簇索引,這個(gè)索引直接指向數(shù)據(jù)地址。相比普通索引指向聚簇索引,減少了一次索引查詢,速度很快。消息、訂單類似業(yè)務(wù)一般會(huì)有按照時(shí)間倒序查詢數(shù)據(jù)的需求,一種做法是在時(shí)間列上建立索引,更好的是依賴ID本身的插入有序性。所以,分布式ID需要滿足兩個(gè)核心條件:
?全局唯一
?時(shí)間趨勢(shì)有序
可能有人會(huì)說(shuō)了,直接用MySQL的auto_increment不就行了么。在創(chuàng)業(yè)初期的時(shí)候我也會(huì)選擇這個(gè)方案,簡(jiǎn)單、高效、快速——?jiǎng)?chuàng)業(yè)公司還是得快速迭代,盡快出產(chǎn)品,而且產(chǎn)品經(jīng)常變,花太多時(shí)間搞出的牛逼架構(gòu)說(shuō)不定不太用得上,浪費(fèi)了寶貴的時(shí)間。但這個(gè)方案是存在一些問(wèn)題的:
?影響并行插入——B記錄依賴A記錄的主鍵,需要等到A記錄插入成功,拿到A.id,才能插入B記錄
?數(shù)據(jù)恢復(fù)難度大——數(shù)據(jù)誤刪或者丟失后,由于日志中沒(méi)有ID,不能直接確定數(shù)據(jù)關(guān)聯(lián)性
?影響分庫(kù)分表——由于ID要插入后才知道,不能根據(jù)業(yè)務(wù)的主鍵進(jìn)行分庫(kù)分表
所以,在業(yè)務(wù)穩(wěn)定后,一定要抽出時(shí)間來(lái)還早期的技術(shù)債務(wù)。
常見方案
使用數(shù)據(jù)庫(kù)的auto_increment來(lái)生成唯一ID
優(yōu)點(diǎn)
?簡(jiǎn)單,使用已有功能,開發(fā)量小
?ID步長(zhǎng)固定
缺點(diǎn)
?寫入單點(diǎn),非高可用
?即使按照不同auto_increment起點(diǎn)擴(kuò)展多個(gè)主庫(kù),雖然提高了可用性,但卻不能保證ID的嚴(yán)格有序
?每次都需要訪問(wèn)數(shù)據(jù)庫(kù),容易到達(dá)性能天花板
批量拉取ID,逐一分配
這種方案也是將ID數(shù)據(jù)存入數(shù)據(jù)庫(kù),ID服務(wù)每次從數(shù)據(jù)庫(kù)中拉取N個(gè)ID,并將當(dāng)前已用ID最大值更新為原始數(shù)據(jù)+N,ID服務(wù)每次接到ID生成請(qǐng)求時(shí)就從這N個(gè)ID中依次返回。
優(yōu)點(diǎn)
?批量獲取,不用每次訪問(wèn)數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)壓力小
缺點(diǎn)
?整個(gè)服務(wù)還是單點(diǎn)
?服務(wù)宕機(jī)重啟會(huì)造成ID不連續(xù)
?無(wú)法水平擴(kuò)展
改進(jìn)
增加一套備用服務(wù),主服務(wù)掛了漂移到備用服務(wù)上,可以采用vip + keepalived或者增加proxy。
uuid
優(yōu)點(diǎn)
?本地生成ID,沒(méi)有單點(diǎn)問(wèn)題,沒(méi)有性能瓶頸
缺點(diǎn)
?不能保證遞增有序
?長(zhǎng)度過(guò)長(zhǎng),作為主鍵性能低
類snowflake算法
snowflake是twitter開源的分布式ID生成算法,其核心思想是:一個(gè)long型的ID,使用其中41bit作為毫秒數(shù),10bit作為機(jī)器編號(hào),12bit作為毫秒內(nèi)序列號(hào)。這個(gè)算法單機(jī)每秒內(nèi)理論上最多可以生成1000*(2^12),也就是400W的ID,完全能滿足業(yè)務(wù)的需求。
借鑒snowflake的思想,結(jié)合各公司的業(yè)務(wù)邏輯和并發(fā)量,可以實(shí)現(xiàn)自己的分布式ID生成算法。
優(yōu)點(diǎn)
?時(shí)間在高位,趨勢(shì)遞增
?實(shí)現(xiàn)簡(jiǎn)單,不依賴其它服務(wù),方便擴(kuò)展
缺點(diǎn)
?沒(méi)有全局時(shí)鐘,單機(jī)絕對(duì)有序,但從整個(gè)集群來(lái)看,是趨勢(shì)有序的
注意事項(xiàng)
?由于ID常作為分庫(kù)分表的標(biāo)識(shí),所以需要這些ID有一定的隨機(jī)性,不至于分庫(kù)后的數(shù)據(jù)不均勻,可以在每個(gè)毫秒開始時(shí)序列號(hào)不從1開始,二是從0-9中的任意一個(gè)開始