免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
分布式ID生成系統(tǒng)怎么做?

本文轉(zhuǎn)自公眾號“達(dá)達(dá)京東到家技術(shù)”,已獲授權(quán)轉(zhuǎn)載

背景

在分布式系統(tǒng)中,經(jīng)常需要對大量的數(shù)據(jù)、消息、http 請求等進(jìn)行唯一標(biāo)識,例如:對于分布式系統(tǒng),服務(wù)間相互調(diào)用需要唯一標(biāo)識,調(diào)用鏈路分析的時(shí)候需要使用這個(gè)唯一標(biāo)識。這個(gè)時(shí)候數(shù)據(jù)庫自增主鍵已經(jīng)不能滿足需求,需要一個(gè)能夠生成全局唯一 ID 的系統(tǒng),這個(gè)系統(tǒng)需要滿足以下需求:

  • 全局唯一:不能出現(xiàn)重復(fù) ID。

  • 高可用:ID 生成系統(tǒng)是基礎(chǔ)系統(tǒng),被許多關(guān)鍵系統(tǒng)調(diào)用,一旦宕機(jī),會造成嚴(yán)重影響。

經(jīng)典方案
 1. UUID

UUID 是 Universally Unique Identifier 的縮寫,它是指在一定范圍內(nèi) (從特定的名字空間到全球) 唯一的機(jī)器生成的標(biāo)識符,UUID 是 32位的16 進(jìn)制數(shù)字,長為 128 位,例如:3F2504E0-4F89-11D3-9A0C-0305E82C3301。

UUID 經(jīng)由一定的算法機(jī)器生成,為了保證 UUID 的唯一性,規(guī)范定義了包括網(wǎng)卡 MAC 地址、時(shí)間戳、名字空間 (Namespace)、隨機(jī)或偽隨機(jī)數(shù)、時(shí)序等元素,以及從這些元素生成 UUID 的算法。UUID 的復(fù)雜特性在保證了其唯一性的同時(shí),意味著只能由計(jì)算機(jī)生成。

優(yōu)點(diǎn):

  • 本地生成 ID,不需要進(jìn)行遠(yuǎn)程調(diào)用,時(shí)延低,性能高。

缺點(diǎn):

  • UUID 過長,很多場景不適用,比如用 UUID 做數(shù)據(jù)庫索引字段。

  • 沒有排序,無法保證趨勢遞增。

 2. Flicker 方案

這個(gè)方案是由 Flickr 團(tuán)隊(duì)提出,主要思路采用了 MySQL 自增長 ID 的機(jī)制 (auto_increment + replace into)

replace into 跟 insert 功能類似,不同點(diǎn)在于:replace into 首先嘗試插入數(shù)據(jù)到表中,如果發(fā)現(xiàn)表中已經(jīng)有此行數(shù)據(jù) (根據(jù)主鍵或者唯 - 索引判斷) 則先刪除此行數(shù)據(jù),然后插入新的數(shù)據(jù), 否則直接插入新數(shù)據(jù)。

為了避免單點(diǎn)故障,最少需要兩個(gè)數(shù)據(jù)庫實(shí)例,通過區(qū)分 auto_increment 的起始值和步長來生成奇偶數(shù)的 ID。

優(yōu)點(diǎn):

  • 充分借助數(shù)據(jù)庫的自增 ID 機(jī)制,可靠性高,生成有序的 ID。

缺點(diǎn):

  • ID 生成性能依賴單臺數(shù)據(jù)庫讀寫性能。

  • 依賴數(shù)據(jù)庫,當(dāng)數(shù)據(jù)庫異常時(shí)整個(gè)系統(tǒng)不可用。

對于依賴 MySQL 性能問題,可用如下方案解決:

在分布式環(huán)境中我們可以部署多臺機(jī)器,每臺設(shè)置不同的初始值,并且步長為機(jī)器臺數(shù),比如部署 N 臺,每臺的初始值就為 0,1,2,3...N-1,步長為 N。


以上方案雖然解決了性能問題,但是也存在很大的局限性:

  • 系統(tǒng)擴(kuò)容困難:系統(tǒng)定義好步長之后,增加機(jī)器之后調(diào)整步長困難。

  • 數(shù)據(jù)庫壓力大:每次獲取一個(gè) ID 都必須讀寫一次數(shù)據(jù)庫。

 3. 類 snowflake 方案

這種方案生成一個(gè) 64bit 的數(shù)字,64bit 被劃分成多個(gè)段,分別表示時(shí)間戳、機(jī)器編碼、序號。

ID為64bit 的long 數(shù)字,由三部分組成:

  • 41位的時(shí)間序列(精確到毫秒,41位的長度可以使用69年)。

  • 10位的機(jī)器標(biāo)識(10位的長度最多支持部署1024個(gè)節(jié)點(diǎn))。

  • 12位的計(jì)數(shù)順序號(12位的計(jì)數(shù)順序號支持每個(gè)節(jié)點(diǎn)每毫秒產(chǎn)生4096個(gè)ID序號)。

優(yōu)點(diǎn):
  • 時(shí)間戳在高位,自增序列在低位,整個(gè)ID是趨勢遞增的,按照時(shí)間有序。

  • 性能高,每秒可生成幾百萬ID。

  • 可以根據(jù)自身業(yè)務(wù)需求靈活調(diào)整bit位劃分,滿足不同需求。

缺點(diǎn):

依賴機(jī)器時(shí)鐘,如果機(jī)器時(shí)鐘回?fù)埽瑫?dǎo)致重復(fù)ID生成。

在單機(jī)上是遞增的,但是由于涉及到分布式環(huán)境,每臺機(jī)器上的時(shí)鐘不可能完全同步,有時(shí)候會出現(xiàn)不是全局遞增的情況。

 4. TDDL 序列生成方式

TDDL 是阿里的分庫分表中間件,它里面包含了全局?jǐn)?shù)據(jù)庫 ID 的生成方式,主要思路:


  • 使用數(shù)據(jù)庫同步ID信息。

  • 每次批量取一定數(shù)量的可用ID在內(nèi)存中,使用完后,再請求數(shù)據(jù)庫重新獲取下一批可用ID,每次獲取的可用ID數(shù)量由步長控制,實(shí)際業(yè)務(wù)中可根據(jù)使用速度進(jìn)行配置。

  • 每個(gè)業(yè)務(wù)可以給自己的序列起個(gè)唯一的名字,隔離各個(gè)業(yè)務(wù)系統(tǒng)的ID。


優(yōu)點(diǎn):
  • 相比Flicker方案,大大降低數(shù)據(jù)庫寫壓力,數(shù)據(jù)庫不再是性能瓶頸。

  • 相比Flicker方案,生成ID性能大幅度提高,因?yàn)楂@取一個(gè)可用號段后在內(nèi)存中直接分配,相對于每次讀取數(shù)據(jù)庫性能提高了幾個(gè)量級。

  • 不同業(yè)務(wù)不同的ID需求可以用seqName字段區(qū)分,每個(gè)seqName的ID獲取相互隔離,互不影響。

缺點(diǎn):
  • 強(qiáng)依賴數(shù)據(jù)庫,當(dāng)數(shù)據(jù)庫異常時(shí)整個(gè)系統(tǒng)不可用。

發(fā)號器實(shí)現(xiàn)方案

綜合對比以上四種實(shí)現(xiàn)方案,以及我們的業(yè)務(wù)需求,最后決定采用第三種方案。

主要原因:

  • 業(yè)務(wù)需求:業(yè)務(wù)要求生成的 ID 要有遞增趨勢,全局唯一,并且為數(shù)字。

  • 系統(tǒng)考慮:第三種方案性能高,穩(wěn)定性高,對外部資源依賴少。

依據(jù)實(shí)際業(yè)務(wù)需求和系統(tǒng)規(guī)劃,對算法進(jìn)行局部調(diào)整,實(shí)現(xiàn)了發(fā)號器 snowflake 方案。

 發(fā)號器 snowflake 方案

發(fā)號器 snowflake 方案中對 bit 的劃分做了如下調(diào)整:

  • 36 bit 時(shí)間戳,使用時(shí)間秒

  • 5 bit 機(jī)器編碼

  • 22 bit 序號

機(jī)器編碼維護(hù):

機(jī)器編碼是不同機(jī)器之間產(chǎn)生唯一 ID 的重要依據(jù),不能重復(fù),一旦重復(fù),就會導(dǎo)致有相同機(jī)器編碼的服務(wù)器生成的 ID 大量重復(fù)。 如果部署的機(jī)器只是少量的,可以人工維護(hù),如果大量,手動(dòng)維護(hù)成本高,考慮到自動(dòng)部署、運(yùn)維等等問題,機(jī)器編碼最好由系統(tǒng)自動(dòng)維護(hù),有以下兩個(gè)方案可供選擇:

  • 使用 MySQL 自增 ID 特性,用數(shù)據(jù)表,存儲機(jī)器的 mac 地址或者 ip 來維護(hù)。

  • 使用 ZooKeeper 持久順序節(jié)點(diǎn)的特性。

這里我們使用 ZooKeeper 持久順序節(jié)點(diǎn)特性來配置維護(hù) WORKID發(fā)號器的啟動(dòng)順序如下:

  • 啟動(dòng)發(fā)號器服務(wù),連接 ZooKeeper, 檢查根節(jié)點(diǎn) id_generator 是否存在,如果不存在就創(chuàng)建系統(tǒng)根節(jié)點(diǎn)。

  • 檢查根節(jié)點(diǎn)下當(dāng)前機(jī)器是否已經(jīng)注冊過 (是否有該順序子節(jié)點(diǎn))。

  • 如果有注冊,直接取回自己的 WORKID。如果沒注冊,在根節(jié)點(diǎn)下創(chuàng)建一個(gè)持久順序節(jié)點(diǎn),取回順序號做 WORKID。

一旦取回 WORKID,緩存在本地文件中,后續(xù)直接使用,不再與 ZooKeeper 進(jìn)行任何交互,此方案對 ZooKeeper 依賴極小。

時(shí)鐘問題:

snowflake方案依賴系統(tǒng)時(shí)鐘,如果機(jī)器時(shí)鐘回?fù)埽陀锌赡苌芍貜?fù)ID,為了保證ID唯一性,必須解決時(shí)鐘回?fù)軉栴}。

可以采取以下幾種方案解決時(shí)鐘問題:

  • 關(guān)閉系統(tǒng)NTP同步,這樣就不會產(chǎn)生時(shí)鐘調(diào)整。

  • 系統(tǒng)做出判斷,在時(shí)鐘回?fù)苓@段時(shí)間,不生成ID,直接返回ERROR_CODE,直到時(shí)鐘追上,恢復(fù)服務(wù)。


  • 系統(tǒng)做出判斷,如果遇到超過容忍限度的回?fù)?,上?bào)報(bào)警系統(tǒng),并把自身從集群節(jié)點(diǎn)中摘除

  • 系統(tǒng)做兼容處理,由于nfp網(wǎng)絡(luò)回?fù)芏际菐资撩氲綆装俸撩耄瑯O少數(shù)到秒級別,這種回?fù)軙a(chǎn)生以下幾種結(jié)果:

    系統(tǒng)中緩存最近幾秒內(nèi)最后的發(fā)號序號(具體范圍請根據(jù)實(shí)際需要確定),存儲格式為:時(shí)間秒-序號。

    • 當(dāng)前秒數(shù)不變: 當(dāng)前是8:30秒100毫秒,ntp回?fù)?0毫秒,當(dāng)前時(shí)間變成8:30秒50毫秒,這個(gè)時(shí)候秒數(shù)沒變,我們算法的時(shí)間戳部分不會產(chǎn)生重復(fù),就不影響系統(tǒng)繼續(xù)發(fā)號

    • 當(dāng)前秒數(shù)向前:當(dāng)前是8:30秒800毫秒,ntp 向前調(diào)整300毫秒,當(dāng)前時(shí)間變成8:31秒100毫秒,由于這個(gè)時(shí)間還沒發(fā)過號,不會生成重復(fù)的ID

    • 當(dāng)前秒數(shù)向后:當(dāng)前是8:30秒100毫秒,ntp回?fù)?50毫秒,當(dāng)前時(shí)間變成8:29秒950毫秒,這個(gè)時(shí)候秒發(fā)生回退,就可能產(chǎn)生重復(fù)ID。產(chǎn)生重復(fù)的原因在于秒回退后,算法的時(shí)間戳部分使用了已經(jīng)用過的時(shí)間戳,但是算法的序號部分,并沒有回退到29秒那個(gè)時(shí)間對應(yīng)的序號,依然使用當(dāng)前的序號,如果序號也同時(shí)回退到29秒時(shí)間戳所對應(yīng)的最后序號,就不會重復(fù)發(fā)號。解決方案如下:


閏秒處理:

閏秒,是指為保持協(xié)調(diào)世界時(shí)接近于世界時(shí)時(shí)刻,由國際計(jì)量局統(tǒng)一規(guī)定在年底或年中(也可能在季末)對協(xié)調(diào)世界時(shí)增加或減少1秒的調(diào)整。由于地球自轉(zhuǎn)的不均勻性和長期變慢性(主要由潮汐摩擦引起的),會使世界時(shí)(民用時(shí))和原子時(shí)之間相差超過到±0.9秒時(shí),就把協(xié)調(diào)世界時(shí)向前撥1秒(負(fù)閏秒,最后一分鐘為59秒)或向后撥1秒(正閏秒,最后一分鐘為61秒),閏秒一般加在公歷年末或公歷六月末。

在閏秒產(chǎn)生的時(shí)候系統(tǒng)會出現(xiàn)秒級時(shí)間調(diào)整,下面我們來分析閏秒對發(fā)號器的影響:

  • 負(fù)閏秒:當(dāng)前23:59:58的下一秒就是第二天的00:00:00,00:00:00 這個(gè)時(shí)間我們還沒產(chǎn)生過ID,不會產(chǎn)生重復(fù)的,對發(fā)號器沒影響。

  • 正閏秒:當(dāng)天23:59:59的下一秒當(dāng)記為23:59:60,然后才是第二天的00:00:00。由于我們系統(tǒng)時(shí)間戳部分取的從某個(gè)時(shí)間點(diǎn)(1970年1月1日)到現(xiàn)在的秒數(shù),是一個(gè)數(shù)字,只要這個(gè)數(shù)字不重復(fù),就不會產(chǎn)生重復(fù)的ID。如果在閏秒發(fā)生一段時(shí)間后ntp時(shí)間同步(為了規(guī)避閏秒風(fēng)險(xiǎn),很多公司閏秒前關(guān)閉ntp同步,閏秒后打開ntp同步),這個(gè)時(shí)候系統(tǒng)時(shí)鐘回?fù)?可以使用解決時(shí)鐘回?fù)艿姆桨高M(jìn)行處理。

 服務(wù)部署優(yōu)化

部署結(jié)構(gòu)

為了實(shí)現(xiàn)高可用,避免單點(diǎn)故障,系統(tǒng)部署采用集群水平部署,前置使用Nginx做負(fù)載均衡,發(fā)號器使用Spring Boot框架,web服務(wù)器使用Spring Boot內(nèi)嵌Tomcat, 發(fā)號器和Nginx之間進(jìn)行心跳檢測。

Tomcat調(diào)優(yōu)

使用APR

Tomcat支持三種接收請求的處理方式:BIO、NIO、APR, 性能上 BIO<><>在Spring Boot程序中增加ARP配置開啟APR(這里有一個(gè)配置變量來控制是否開啟)

開發(fā)中遇到的問題

整個(gè)開發(fā)過程都非常順利,測試的時(shí)候tps也很高,心情很愉快,世界很美好,突然一個(gè)意外出現(xiàn),發(fā)現(xiàn)存在full gc現(xiàn)象,有內(nèi)存溢出? 于是分析了好幾遍程序,也沒找到明顯的線索,只能開始jvm調(diào)試旅程。

pingpoint 監(jiān)控圖:

(上圖中紅色部署表示full gc)

JVM調(diào)試最直接的就是獲取full gc時(shí)的jvm dump文件,以及gc log進(jìn)行分析:

為了獲取dump文件,在jvm參數(shù)中加上:

參數(shù)介紹:

配置上面的虛擬機(jī)參數(shù)后,虛擬機(jī)gc的時(shí)候會把gc相關(guān)信息輸出到文件gc.log中,full gc前后,會生成當(dāng)時(shí)虛擬機(jī)的內(nèi)存dump文件。從pingpoint監(jiān)控圖中可以看出full gc是發(fā)生在持久區(qū)域。

使用jmap 工具,獲取JVM堆內(nèi)存信息如下:

jmap -heap pid

從上圖可以看出,使用的堆內(nèi)存很少,總的堆內(nèi)存只有0.84% 使用,其它使用指標(biāo)也都在正常范圍,系統(tǒng)裝載的類也不多,沒有內(nèi)存泄露。

繼續(xù)分析gc log:

從gc log 中尋找線索:

這里發(fā)現(xiàn)了以下線索:

  • 從 [Full GC (Metadata GC Threshold)看出,的確產(chǎn)生了full gc,原因 Metadata GC Threshold。

  • [Metaspace: 34773K->34773K(1081344K)] full gc前后metaspace的size沒有變化說明此區(qū)域已經(jīng)滿了,釋放不出內(nèi)存。

  • 仔細(xì)分析gc log,發(fā)現(xiàn)2次full gc記錄,第一次full gc [Metaspace: 20897K->20897K(1069056K),這個(gè)值比第2次的要小很多。

兩次full gc原因都是 Metadata GC Threshold類型,說明pingpoint監(jiān)控到的full gc是元空間引發(fā)的full gc,并非內(nèi)存泄露引起,但是這個(gè)值才34m,距離最大值1081m,還有很大空間,為什么會full gc?

經(jīng)過查閱官方資料,發(fā)現(xiàn)MetaspaceSize的默認(rèn)大小是21807104b,也就是21296k,而發(fā)生GC的時(shí)候,元空間已經(jīng)使用了34722K,從而產(chǎn)生full gc。

方法區(qū):

方法區(qū)也是所有線程共享。主要用于存儲類的信息、常量池、方法數(shù)據(jù)、方法代碼等。方法區(qū)邏輯上屬于堆的一部分,但是為了與堆進(jìn)行區(qū)分,通常又叫“非堆”。其實(shí),移除永久代的工作從JDK1.7就開始了。JDK1.7中,存儲在永久代的部分?jǐn)?shù)據(jù)就已經(jīng)轉(zhuǎn)移到了Java Heap或者是 Native Heap。但永久代仍存在于JDK1.7中,并沒完全移除,譬如符號引用(Symbols)轉(zhuǎn)移到了native heap,字符串常量轉(zhuǎn)移到了java heap,類的靜態(tài)變量(class statics)轉(zhuǎn)移到了java heap。

在JDK8中,classe metadata(the virtual machines internal presentation of Java class),被存儲在叫做Metaspace的native memory。一些新的flags被加入:-XX:MetaspaceSize,class metadata的初始空間配額,以bytes為單位,達(dá)到該值就會觸發(fā)垃圾收集進(jìn)行類型卸載,同時(shí)GC會對該值進(jìn)行調(diào)整:如果釋放了大量的空間,就適當(dāng)?shù)慕档驮撝?;如果釋放了很少的空間,就會在不超過MaxMetaspaceSize(如果設(shè)置了的話)的情況下,適當(dāng)?shù)奶岣咴撝怠?/p>

在虛擬機(jī)參數(shù)中增加MetaspaceSize初始化大小,-XX:MetaspaceSize=128m,重新啟動(dòng)項(xiàng)目,不再有full gc出現(xiàn)。

總結(jié)

發(fā)號器-達(dá)達(dá)分布式ID生成系統(tǒng),以snowflake算法為基礎(chǔ),實(shí)現(xiàn)了生成全局唯一ID的功能,解決了在分布式系統(tǒng)唯一ID生成問題。在實(shí)現(xiàn)高可用性方面,采用水平集群部署、心跳檢測等方案為系統(tǒng)保駕護(hù)航。該系統(tǒng)目前已在達(dá)達(dá)商城等項(xiàng)目中使用。

作者介紹

段同海,就職于達(dá)達(dá)基礎(chǔ)架構(gòu)團(tuán)隊(duì),主要參與達(dá)達(dá)分布式 ID 生成系統(tǒng),日志采集系統(tǒng)等中間件研發(fā)工作。

 More

翻遍整個(gè)技術(shù)雷達(dá),竟沒有找到 AI 四個(gè)字???

全流程重構(gòu)京東服務(wù)市場系統(tǒng)


 其它

根據(jù) Gartner 的預(yù)測,AI 在 2018 年已經(jīng)不是遙不可及的東西,每家公司都可以碰得到。那么,2018 年,你是否已經(jīng)做好準(zhǔn)備轉(zhuǎn)戰(zhàn) AI 了?應(yīng)該去哪里學(xué)習(xí)現(xiàn)成的落地案例和實(shí)踐經(jīng)驗(yàn)?zāi)兀?/span>

InfoQ 中國團(tuán)隊(duì)為大家梳理了目前機(jī)器學(xué)習(xí)領(lǐng)域的最新動(dòng)態(tài),并邀請到了來自 Amazon、Snapchat、Etsy、BAT、360、京東等公司 AI 技術(shù)負(fù)責(zé)人前來分享他們的機(jī)器學(xué)習(xí)落地實(shí)踐經(jīng)驗(yàn),部分精彩案例如下:

  • 深度學(xué)習(xí)框架演進(jìn)漫談》老師木,一流科技創(chuàng)始人

  • 機(jī)器學(xué)習(xí)在工程項(xiàng)目中的應(yīng)用實(shí)踐》 蔡超,Amazon 中國研發(fā)中心首席架構(gòu)師

  • 菜鳥雙 11:如何運(yùn)用機(jī)器學(xué)習(xí)等 AI 技術(shù)實(shí)現(xiàn)物流優(yōu)化》徐盈輝,菜鳥人工智能部資深總監(jiān)

  • 機(jī)器學(xué)習(xí)和運(yùn)籌優(yōu)化在外賣行業(yè)的應(yīng)用實(shí)踐》張浩,餓了么技術(shù)副總裁

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
UUID 好處 以及 自增主鍵 的優(yōu)缺點(diǎn)
唯一ID生成算法剖析,看看這篇就夠了
分布式ID生成--雪花算法
適用于分布式唯一標(biāo)識碼的生成算法有哪些?
分布式系統(tǒng)ID生成辦法
如何在分布式場景下生成全局唯一 ID ?
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服