分布式ID生成器

1烤宙、ID生成的要求

  • 全局唯一性: 不重復(fù)
  • 趨勢(shì)遞增: 多數(shù)的RDBMS數(shù)據(jù)庫(kù)使用B-Tree來(lái)存儲(chǔ)索引結(jié)構(gòu),主鍵有序有利于插入效率 避免緩存失效躺枕,頁(yè)裂變等
  • 單調(diào)遞增:保證下一個(gè)ID一定大余上一個(gè)ID,滿足如事務(wù)版本號(hào)蔓姚,消息順序等需求
  • 信息安全:避免通過(guò)ID泄露太多信息 如找一天的開頭和結(jié)尾的Id號(hào)差慨丐,可以獲取一個(gè)系統(tǒng)一天的訂單量

2、UUID

36位 8-4-4-4-12 去掉- 32位 byte

優(yōu)點(diǎn):
性能高备闲,
無(wú)需網(wǎng)絡(luò)

缺點(diǎn):
無(wú)序捅暴,
太長(zhǎng),
包含mac地址信息不安全泻骤,
作為DB主鍵不合適 - a、主鍵長(zhǎng)度推薦短點(diǎn) b狱掂、uuid無(wú)序性,數(shù)據(jù)位置頻繁變動(dòng)鸟顺,影響性能

3器虾、類雪花算法 snowflake

image.png

64位 bit
1位 不用
41位 時(shí)間戳
10位 workID
12位 序列遞增
可根據(jù)實(shí)際情況調(diào)整 各個(gè)部分占位數(shù)

優(yōu)點(diǎn):
1、趨勢(shì)遞增 時(shí)間位在高位
2欧芽、不依賴第三方系統(tǒng)
3挤悉、可根據(jù)需求分配bit位
缺點(diǎn):
1、時(shí)鐘回?fù)艿那闆r下昏鹃,可能出現(xiàn)重復(fù)id --- 可以等待一段時(shí)間诀诊,時(shí)鐘跟上次正向后再發(fā)號(hào)
2、機(jī)器id的分配方案属瓣,機(jī)器宕機(jī)后抡蛙,機(jī)器id回收的問(wèn)題 --- 使用zk做id分配
3、機(jī)器id存在上限 10bit 1024 ---

算法應(yīng)用:如MongoDB的ObjectId自生成
時(shí)間+機(jī)器碼+pid+inc 4+3+2+3 共12個(gè)byte 最終標(biāo)識(shí)為24ge16進(jìn)制字符
1byte -> 8bit 16進(jìn)制 -> 4bit 所以1byte可以標(biāo)識(shí)為2個(gè)16進(jìn)制字符

571094e2976aeb1df982ad4e
57 -> 01010111

4粗截、數(shù)據(jù)庫(kù)生成

如mysql 利用 auto_increment_increment auto_increment_offset
sql replace into 如果已存在數(shù)據(jù)熊昌,則刪除后插入 如果不存在數(shù)據(jù)直接插入

begin;
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
commit;

事務(wù)保證 插入的和查詢到的是同一條ID記錄
不用insert 是保證數(shù)據(jù)庫(kù)不會(huì)無(wú)限增長(zhǎng)
不用delete 是減少一次查詢暂刘,減少交互

優(yōu)點(diǎn):
1伍派、單調(diào)遞增
2、直接使用數(shù)據(jù)庫(kù)自帶實(shí)現(xiàn)昂利,簡(jiǎn)單
缺點(diǎn):
1铁坎、強(qiáng)依賴DB犁苏,DB宕機(jī)不可用 - 如果使用主從機(jī)解決高可用問(wèn)題傀顾,又會(huì)出現(xiàn)主從切換時(shí)的重復(fù)發(fā)號(hào)問(wèn)題
2碌奉、性能瓶頸依賴單mysql數(shù)據(jù)庫(kù)的性能
可以分庫(kù)分表橫向擴(kuò)容,解決單mysql的性能問(wèn)題赐劣,如步長(zhǎng)相同,每臺(tái)msyql都用不同的初始值魁兼,可以做到不重復(fù)發(fā)號(hào)
問(wèn)題:
ID沒(méi)法單調(diào)遞增了,只能趨勢(shì)遞增
每次生成號(hào)都得讀寫一次數(shù)據(jù)庫(kù)盖呼,壓力還是在數(shù)據(jù)庫(kù)上
定好步長(zhǎng)和初始值后化撕,后期再擴(kuò)容困難

5、Leaf數(shù)據(jù)庫(kù)方案

表增加業(yè)務(wù)字段 biz_tag 用來(lái)做不同業(yè)務(wù)區(qū)分 - 方便后續(xù)分庫(kù)分表基于業(yè)務(wù)字段進(jìn)行拆分
表字段step max_id 自己存儲(chǔ)當(dāng)前發(fā)號(hào)最大id號(hào)和步長(zhǎng)蟹瘾,不依賴數(shù)據(jù)庫(kù)自己的auto_increment特性
這時(shí)的step步長(zhǎng)標(biāo)識(shí)一次取號(hào)的批量數(shù)據(jù)掠手,等這批數(shù)據(jù)用完后再來(lái)取數(shù),減輕了mysql的交互壓力

begin
update table set max_id=max_id+step where biz_tag=xxx;
select biz_tag, max_id, step where biz_tag=xxx;
commit

優(yōu)點(diǎn):
方便橫向擴(kuò)展
ID是long型64位遞增數(shù)字众雷,滿足主鍵要求
客戶端有號(hào)段緩存 max_id-step 到max_id魁衙,取完才去數(shù)據(jù)庫(kù)取 能一定程度緩解可用性
max_id可自定義,方便其他業(yè)務(wù)遷移

缺點(diǎn):
遞增數(shù)據(jù)容易泄露發(fā)號(hào)規(guī)律
當(dāng)號(hào)段用完后剖淀,去數(shù)據(jù)庫(kù)取數(shù)時(shí),還是可能會(huì)引起高并發(fā)翻诉,阻塞
DB宕機(jī)會(huì)不可用

優(yōu)化方案:
1、雙buffer 號(hào)段還沒(méi)用完時(shí)舒岸,就去提前取下一個(gè)號(hào)段芦圾,可以不需要等待取號(hào)阻塞 2個(gè)segment
segment設(shè)置為10分鐘的高峰用號(hào)量, 這樣DB宕機(jī)也有10-20分鐘
不會(huì)阻塞在segment取號(hào)
2个少、DB可用性 使用一主兩從夜焦,分機(jī)房部署,半同步方式同步數(shù)據(jù) 主從切換需要中間件

6茫经、Leaf雪花算法方案

還是1+41+10+12 分配方案
1、利用zk的持久順序節(jié)點(diǎn) 來(lái)生成workid 抹镊,重啟后直接獲取是否已經(jīng)分配過(guò)id
2瞪慧、弱依賴zk,每次的workid獲取后都會(huì)在本地存儲(chǔ)
3氨菇、周期性上傳本機(jī)時(shí)間到zk上妓湘,每次取號(hào)都要檢查當(dāng)前時(shí)間是否出現(xiàn)了回?fù)埽霈F(xiàn)則失敗榜贴,告警
4、檢查本機(jī)時(shí)間和zk上的平均時(shí)間是否偏移過(guò)大鹃共,出現(xiàn)則失敗告警

7驶拱、我們的實(shí)現(xiàn)

redis 單線程原子性 實(shí)現(xiàn)一個(gè)業(yè)務(wù)字段的遞增

private long getUniqueAtomicLong(String tag) {
        RAtomicLong atomicLong = redissonClient.getAtomicLong(tag);
        boolean flag = atomicLong.compareAndSet(Long.MAX_VALUE, 0);
        if(flag) {
            return Long.MAX_VALUE;
        }
        long lo = atomicLong.getAndIncrement();
        return lo;
    }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蓝纲,一起剝皮案震驚了整個(gè)濱河市晌纫,隨后出現(xiàn)的幾起案子永丝,更是在濱河造成了極大的恐慌,老刑警劉巖哥牍,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喝检,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)坎弯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門抠忘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人崎脉,你說(shuō)我怎么就攤上這事∏糇疲” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵阅签,是天一觀的道長(zhǎng)蝎抽。 經(jīng)常有香客問(wèn)我,道長(zhǎng)养交,這世上最難降的妖魔是什么瓢宦? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任刁笙,我火速辦了婚禮谦趣,結(jié)果婚禮上座每,老公的妹妹穿的比我還像新娘。我一直安慰自己峭梳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布捂寿。 她就那樣靜靜地躺著孵运,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驳概。 梳的紋絲不亂的頭發(fā)上旷赖,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天等孵,我揣著相機(jī)與錄音,去河邊找鬼俯萌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛雕憔,可吹牛的內(nèi)容都是我干的糖声。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼琉苇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悦施!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起抡诞,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鬼雀,沒(méi)想到半個(gè)月后蛙吏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡励烦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年泼诱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片却音。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡矢炼,死狀恐怖阿纤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胰锌,我是刑警寧澤藐窄,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站格带,受9級(jí)特大地震影響刹枉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜微宝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一蟋软、第九天 我趴在偏房一處隱蔽的房頂上張望嗽桩。 院中可真熱鬧凄敢,春花似錦、人聲如沸贡未。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)消恍。三九已至,卻和暖如春约啊,著一層夾襖步出監(jiān)牢的瞬間佣赖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工外傅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留俩檬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓技竟,卻偏偏與公主長(zhǎng)得像屈藐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子联逻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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