日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

基于.NET Standard的分布式自增ID算法--美团点评LeafSegment

發(fā)布時間:2023/12/4 asp.net 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于.NET Standard的分布式自增ID算法--美团点评LeafSegment 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

概述

前一篇文章講述了最流行的分布式ID生成算法snowflake,本篇文章根據(jù)美團點評分布式ID生成系統(tǒng)文章,介紹另一種相對更容易理解和編寫的分布式ID生成方式。


實現(xiàn)原理


Leaf這個名字是來自德國哲學家、數(shù)學家萊布尼茨的一句話:

There are no two identical leaves in the world

"世界上沒有兩片相同的樹葉"

設(shè)置數(shù)據(jù)表主鍵自增是最簡單的方案,缺點也很明顯:

  • 強依賴數(shù)據(jù)庫,無法提供高可用

  • ID生成強依賴單臺服務(wù),無法橫向擴展

很容易想到,如果我的應(yīng)用每次申請一批id,插入數(shù)據(jù)時順序取一個使用,即將耗盡時再去獲取一批新的id,如此即可在一定程度上減弱與數(shù)據(jù)庫的關(guān)系,同時將單臺擴展延伸為獲取id的步長。

負責發(fā)放ID的服務(wù)既可以使用MySQL服務(wù),也可以使用Redis等服務(wù)。


基于MySQL實現(xiàn)

首先我們建立一張數(shù)據(jù)庫表


DROP?TABLE?IF?EXISTS?`leafsegment`;CREATE?TABLE?`leafsegment`??(??`biz_tag`?varchar(255)?NULL?DEFAULT?NULL,??`max_id`?bigint(20)?NULL?DEFAULT?0,??`step`?int(11)?NULL?DEFAULT?5000,??`desc`?varchar(255)??NULL?DEFAULT?NULL,??`update_time`?datetime(0)?NULL?DEFAULT?now());--?添加一條初始化數(shù)據(jù)INSERT?INTO?`leafsegment`?VALUES?('test',?0,?5000,?'測試',?'2018-12-06?23:32:11');

數(shù)據(jù)庫表如下圖

biz_tag:業(yè)務(wù)標記,不同業(yè)務(wù)使用不同的值,可以最大限度地利用ID

max_id:當前已經(jīng)被申請走的最大Id

step:每次申請Id的步長

desc:業(yè)務(wù)內(nèi)容描述

update_time:最新一次申請時間


應(yīng)用如何獲取一批有效ID呢?


BeginUPDATE?leafsegment?SET?max_id=max_id+step,update_time=now()?WHERE?biz_tag='test'SELECT?biz_tag,?max_id,?step?FROM?leafsegment?WHERE?biz_tag='test'Commit

在一個事務(wù)周期內(nèi)完成max_id的更新,和最新數(shù)據(jù)的獲取,天然解決了資源競爭問題。

而后,我們就可以在應(yīng)用中將[max_id-step+1,max_id]閉區(qū)間的所有值作為ID來使用了。


基于Redis實現(xiàn)

Redis的實現(xiàn)更為簡單,基本原理是利用了Redis的IncrBy命令實現(xiàn)原子加N,具體實現(xiàn)流程無須贅述。


代碼實現(xiàn)

首先我們定義一個傳遞Step(步長)和MaxId(最大值)的DTO


????///?<summary>????///?數(shù)據(jù)單元????///?</summary>????public?class?DataVal????{????????///?<summary>????????///?當前最大Id????????///?</summary>????????public?long?MaxId?{?get;?set;?}?=?1;????????///?<summary>????????///?當前步長????????///?</summary>????????public?int?Step?{?get;?set;?}?=?1000;????}

這個類僅負責將ID生發(fā)器的數(shù)據(jù)傳入核心類LeafSegment中。核心類的具體實現(xiàn)如下代碼:


????///?<summary>????///?美團的Leaf?Segment?方案????///?</summary>????public?class?LeafSegment????{????????private?long?_currentStep?=?long.MaxValue?>>?1;????????private?readonly?Func<DataVal>?_idGetAction;????????private?readonly?ConcurrentQueue<long>?_data?=?new?ConcurrentQueue<long>();????????private?readonly?AutoResetEvent?_autoReset?=?new?AutoResetEvent(false);????????///?<summary>????????///?美團的Leaf?Segment?方案????????///?</summary>????????///?<param?name="idGetAction">Id生成策略</param>????????///?<param?name="prefill">是否立即初始化數(shù)據(jù)</param>????????public?LeafSegment(Func<DataVal>?idGetAction,bool?prefill=false)????????{????????????_idGetAction?=?idGetAction;????????????if?(prefill)????????????{????????????????FillData();????????????}????????????Loop();????????}????????///?<summary>????????///?獲取下一個Id????????///?</summary>????????///?<returns></returns>????????public?long?NextId()????????{????????????_autoReset.Set();????????????if?(_data.TryDequeue(out?var?result))????????????{????????????????return?result;????????????}????????????throw?new?Exception("Resource?not?enough");????????}????????private?void?Loop()????????{????????????(new?Thread(_?=>????????????{????????????????while?(true)????????????????{????????????????????_autoReset.WaitOne();????????????????????FillData();????????????????}????????????})?{IsBackground?=?true}).Start();????????}????????private?void?FillData()????????{????????????//數(shù)量小于步長一半時觸發(fā)拉新????????????while?(_data.Count?<?(_currentStep?>>?1))????????????{????????????????var?tmp?=?_idGetAction.Invoke();????????????????_currentStep?=?tmp.Step;????????????????for?(var?i?=?tmp.MaxId?-?tmp.Step?+?1;?i?<=?tmp.MaxId;?i++)????????????????{????????????????????_data.Enqueue(i);????????????????}????????????}????????}????}

此處需要注意的是LeafSegment構(gòu)造函數(shù)的第一個入?yún)dGetAction是一個返回DataVal的回調(diào)函數(shù),因此外部實現(xiàn)中可以在該回調(diào)函數(shù)中返回所需ID序列;

第二個參數(shù)prefill,該參數(shù)控制實例化LeafSegment對象時,是否同步調(diào)用獲取ID區(qū)段,如該值為false,將會由啟動的線程稍后補充數(shù)據(jù)。

完整實現(xiàn)、使用Demo以及benchmark測試請參見源代碼:https://github.com/sampsonye/nice

原文地址:?https://www.cnblogs.com/leafly/p/10135431.html

.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com


總結(jié)

以上是生活随笔為你收集整理的基于.NET Standard的分布式自增ID算法--美团点评LeafSegment的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。