分布式ID解決方案

背景

在大型互聯(lián)網(wǎng)應(yīng)用中蹋半,隨著業(yè)務(wù)量的增大拯啦,數(shù)據(jù)庫中單表的數(shù)據(jù)量會達(dá)到千萬、上億的量級符相,為緩解數(shù)據(jù)庫壓力拆融,往往采取分庫分表的策略。分庫分表后需要有一個(gè)唯一ID來標(biāo)識一條數(shù)據(jù)或消息啊终,數(shù)據(jù)庫的自增ID顯然不能滿足需求镜豹,此時(shí)就需要有一個(gè)能夠生成全局唯一ID的系統(tǒng)。全局唯一ID有幾個(gè)特性:

1蓝牲、全局唯一性:不能出現(xiàn)重復(fù)的ID號趟脂,這是最基本的要求。
2例衍、趨勢遞增:以MySQL為例 Mysql InnoDB引擎中使用的是聚集索引昔期,由于多數(shù)RDBMS使用B-tree的數(shù)據(jù)結(jié)構(gòu)來存儲索引數(shù)據(jù)已卸,在主鍵的選擇上面我們應(yīng)該盡量使用有序的主鍵保證寫入性能。
3镇眷、高性能:ID生成響應(yīng)要塊咬最,否則反倒會成為業(yè)務(wù)瓶頸
4、高可用:復(fù)雜的分布式系統(tǒng)中欠动,業(yè)務(wù)對分布式ID生成系統(tǒng)可用性要求極高永乌,比如:訂單系統(tǒng)、優(yōu)惠券具伍、倉庫系統(tǒng)等因?yàn)榉植际絀D生成系統(tǒng)癱瘓從而導(dǎo)致一些核心業(yè)務(wù)無法進(jìn)行翅雏,會引發(fā)一場災(zāi)難

我們要樹立一個(gè)理念,沒有完美的解決方案人芽,每種方案都有優(yōu)缺點(diǎn)望几,在具體的選擇上要根據(jù)具體的業(yè)務(wù)選擇合適的方案。

一:UUID (不推薦)

在用到全局唯一id時(shí)萤厅,我們很容易想到UUID橄抹,畢竟它有著全球唯一的特性。
UUID(Universally Unique Identifier)的標(biāo)準(zhǔn)型式包含32個(gè)16進(jìn)制數(shù)字惕味,以連字號分為五段楼誓,形式為8-4-4-4-12的36個(gè)字符,示例:550e8400-e29b-41d4-a716-446655440000
像用作訂單號UUID這樣的字符串沒有絲毫的意義名挥,看不出和訂單相關(guān)的有用信息疟羹;而對于數(shù)據(jù)庫來說用作業(yè)務(wù)主鍵ID,它不僅是太長還是字符串禀倔,存儲性能差查詢也很耗時(shí)榄融,所以不推薦用作分布式ID。
優(yōu)點(diǎn):
性能非常高:本地生成救湖,沒有網(wǎng)絡(luò)消耗愧杯。
缺點(diǎn):
1、不易于存儲:UUID太長鞋既,16字節(jié)128位民效,通常以36長度的字符串表示,很多場景不適用涛救。MySQL官方明確建議主鍵要盡量越短越好
2畏邢、無序的字符串,不具備趨勢自增特性检吆。作為數(shù)據(jù)庫主鍵 UUID 的無序性會導(dǎo)致數(shù)據(jù)位置頻繁變動(dòng)舒萎,嚴(yán)重影響性能。
3蹭沛、沒有具體的業(yè)務(wù)含義臂寝。比如:用于訂單號章鲤,這樣的字符串顯然沒有意義。

二:利用數(shù)據(jù)庫自增特性

具體實(shí)現(xiàn)是咆贬,單獨(dú)創(chuàng)建一個(gè)Mysql實(shí)例败徊,設(shè)置主鍵屬性為auto_increment,當(dāng)我們需要一個(gè)id時(shí)掏缎,往數(shù)據(jù)庫中插入一條數(shù)據(jù)拿到該記錄的主鍵id皱蹦,如:利用SELECT LAST_INSERT();
優(yōu)點(diǎn):
實(shí)現(xiàn)簡單,利用數(shù)據(jù)庫系統(tǒng)特性實(shí)現(xiàn)
缺點(diǎn):
強(qiáng)依賴DB眷蜈,如果數(shù)據(jù)庫宕機(jī)沪哺,就是引發(fā)致命問題,也可以利用集群部署保證高可用酌儒,但要考慮主從復(fù)制模式下數(shù)據(jù)一致性問題辜妓;多臺機(jī)器不能生成重復(fù)id(可以設(shè)置不同的起始值和自增步長)

三:利用數(shù)據(jù)庫號段模式

可以理解為從數(shù)據(jù)庫批量的獲取自增ID,每次從數(shù)據(jù)庫取出一個(gè)號段范圍忌怎,比如1~1000籍滴,可以想下如果每次獲取ID都得讀寫一次數(shù)據(jù)庫,勢必會對數(shù)據(jù)庫造成較大壓力榴啸。順便說下號段模式是目前很多分布式ID生成器的主流實(shí)現(xiàn)方式之一

CREATE TABLE id_sequence (
  id int(10) NOT NULL,
  max_id bigint(20) NOT NULL COMMENT '當(dāng)前最大id',
  step int(10) NOT NULL COMMENT '號段的步長',
  biz_tag    varchar(128) NOT NULL COMMENT '業(yè)務(wù)類型',
  version int(20) NOT NULL COMMENT '版本號',
  desc   varchar(256) COMMIT '描述'
  PRIMARY KEY (`id`)
) 

biz_tag :代表不同業(yè)務(wù)類型
max_id :當(dāng)前最大的可用id
step :代表號段的長度
version :是一個(gè)樂觀鎖孽惰,每次都更新version,保證并發(fā)時(shí)數(shù)據(jù)的正確性

四:基于Redis實(shí)現(xiàn)

Redis的所有命令操作都是單線程的插掂,本身提供像 incr 和 increby 這樣的自增原子命令灰瞻,所以能保證生成的 ID 肯定是唯一有序的
需要考慮用集群方式保證可用性和高性能(高吞吐量)腥例,同時(shí)需要主要考慮redis持久化

五:雪花算法(Snowflake)

這種方案把64-bit分別劃分成多段辅甥,分開來標(biāo)示機(jī)器、時(shí)間等燎竖,比如在snowflake中的64-bit分別表示如下圖所示:


image.png

Snowflake ID組成結(jié)構(gòu):正數(shù)位(占1比特)+ 時(shí)間戳(占41比特)+ 機(jī)器ID(占5比特)+ 數(shù)據(jù)中心(占5比特)+ 自增值(占12比特)璃弄,總共64比特組成的一個(gè)Long類型。
第一個(gè)bit位(1bit):Java中l(wèi)ong的最高位是符號位代表正負(fù)构回,正數(shù)是0夏块,負(fù)數(shù)是1,一般生成ID都為正數(shù)纤掸,所以默認(rèn)為0脐供。
時(shí)間戳部分(41bit):毫秒級的時(shí)間,不建議存當(dāng)前時(shí)間戳借跪,而是用(當(dāng)前時(shí)間戳 - 固定開始時(shí)間戳)的差值政己,可以使產(chǎn)生的ID從更小的值開始;41位的時(shí)間戳可以使用69年掏愁,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
工作機(jī)器id(10bit):也被叫做workId歇由,這個(gè)可以靈活配置卵牍,機(jī)房或者機(jī)器號組合都可以。
序列號部分(12bit)沦泌,自增值支持同一毫秒內(nèi)同一個(gè)節(jié)點(diǎn)可以生成4096個(gè)ID
根據(jù)這個(gè)算法的邏輯糊昙,只需要將這個(gè)算法用Java語言實(shí)現(xiàn)出來,封裝為一個(gè)工具方法谢谦,那么各個(gè)業(yè)務(wù)應(yīng)用可以直接使用該工具方法來獲取分布式ID释牺,只需保證每個(gè)業(yè)務(wù)應(yīng)用有自己的工作機(jī)器id即可,而不需要單獨(dú)去搭建一個(gè)獲取分布式ID的應(yīng)用他宛。

各個(gè)廠商實(shí)現(xiàn)的分布式生成器

美團(tuán)(Leaf) 支持Leaf-segment數(shù)據(jù)庫方案和Leaf-snowflake方案
百度(uid-generator) uid-generator是基于Snowflake算法實(shí)現(xiàn)的船侧,與原始的snowflake算法不同在于,uid-generator支持自定義時(shí)間戳厅各、工作機(jī)器ID和 序列號 等各部分的位數(shù)镜撩,而且uid-generator中采用用戶自定義workId的生成策略。
滴滴(Tinyid) 基于號段模式
阿里(Sequence)類似號段模式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末队塘,一起剝皮案震驚了整個(gè)濱河市袁梗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌憔古,老刑警劉巖遮怜,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸿市,居然都是意外死亡锯梁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門焰情,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陌凳,“玉大人,你說我怎么就攤上這事内舟『隙兀” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵验游,是天一觀的道長充岛。 經(jīng)常有香客問我蹄咖,道長赊琳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任逻澳,我火速辦了婚禮垒在,結(jié)果婚禮上蒜魄,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好权悟,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布砸王。 她就那樣靜靜地躺著,像睡著了一般峦阁。 火紅的嫁衣襯著肌膚如雪谦铃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天榔昔,我揣著相機(jī)與錄音驹闰,去河邊找鬼。 笑死撒会,一個(gè)胖子當(dāng)著我的面吹牛嘹朗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诵肛,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼屹培,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怔檩?” 一聲冷哼從身側(cè)響起褪秀,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎薛训,沒想到半個(gè)月后媒吗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乙埃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年闸英,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片介袜。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡甫何,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出米酬,到底是詐尸還是另有隱情沛豌,我是刑警寧澤趋箩,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布赃额,位于F島的核電站,受9級特大地震影響叫确,放射性物質(zhì)發(fā)生泄漏跳芳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一竹勉、第九天 我趴在偏房一處隱蔽的房頂上張望飞盆。 院中可真熱鬧,春花似錦、人聲如沸吓歇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽城看。三九已至女气,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間测柠,已是汗流浹背炼鞠。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轰胁,地道東北人谒主。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像赃阀,于是被迫代替她去往敵國和親霎肯。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 分布式ID方案總結(jié) ID是數(shù)據(jù)的唯一標(biāo)識榛斯,傳統(tǒng)的做法是利用UUID和數(shù)據(jù)庫的自增ID姿现,在互聯(lián)網(wǎng)企業(yè)中,大部分公司使...
    4f03f33f33be閱讀 218評論 0 0
  • 「一提佣、分布式ID概念」 說起ID,特性就是唯一荤崇,在人的世界里拌屏,ID就是身份證,是每個(gè)人的唯一的身份標(biāo)識术荤。在復(fù)雜的分...
    小白不想上班閱讀 263評論 0 0
  • 最近在做分布式任務(wù)調(diào)度系統(tǒng)倚喂,遇到分布式id的問題,我們需要一個(gè)全局唯一的id瓣戚,但是服務(wù)又部署在多臺服務(wù)器上面端圈。因?yàn)?..
    瘋狂的哈丘閱讀 972評論 0 22
  • 1. 什么情況下我們需要ID生成器 數(shù)據(jù)庫水平拆分的情況下,主鍵由于需要作為業(yè)務(wù)標(biāo)識使用子库,需要唯一舱权。 業(yè)務(wù)編號需要...
    王敏_8480閱讀 652評論 0 0
  • 閱讀大概需要3分鐘 附源碼 [toc] 前言 單體架構(gòu)的服務(wù)的日子已經(jīng)一去不復(fù)返了。 當(dāng)前系統(tǒng)業(yè)務(wù)和數(shù)據(jù)存儲的復(fù)雜...
    JavaPub閱讀 1,424評論 0 0