基于Twitter的snowflake分布式ID生成,改成可集群應(yīng)用模式

ID生成方案榆芦,基于twitter的snowflake分布式ID生成改造,在集群環(huán)境中多實例自動分配snowflake的workId,dataCenterId喘鸟;如果是小項目小業(yè)務(wù)不需要考慮匆绣,直接基本snowflake在配置文件中配置即可,本項目將會在docker swarm 和 k8s中部署測試迷守。

源碼

  1. coding
# 單機(jī)多實例不同端口
git clone -b single-v1.0 https://git.dev.tencent.com/liangxiaobo/uuid-generate.git

# Docker Swarm集群模式
git clone -b cluster-v1.0 https://git.dev.tencent.com/liangxiaobo/uuid-generate.git

# k8s集群模式
git clone -b cluster-k8s-v1.0 https://git.dev.tencent.com/liangxiaobo/uuid-generate.git
  1. github
# 單機(jī)多實例不同端口
git clone -b single-v1.0 https://github.com/liangxiaobo/uuid-generate.git

# Docker Swarm集群模式
git clone -b cluster-v1.0 https://github.com/liangxiaobo/uuid-generate.git

# k8s集群模式
git clone -b cluster-k8s-v1.0 https://git.dev.tencent.com/liangxiaobo/uuid-generate.git

項目思路

1.jpeg
  • 以Eureka為注冊中心
  • Redis 存儲
  • ID-Server 配置種子數(shù)據(jù)的初始化并處理過期的配置種子
  • ID-Client ID生成服務(wù)

定義簡稱

  • Redis中自定義的三個存儲簡稱 R1(未全用池)犬绒、R2(已使用池)旺入、R3(id-client實例和R2中的數(shù)據(jù)關(guān)聯(lián)池)
  • workId和dataCenterId簡稱WD

大概思路是:

  1. 由一個應(yīng)用ID-Server主動創(chuàng)建足夠量的workId和DataCenterId兑凿,放到Redis中的R1中
  2. ID-Client是ID生成服務(wù)凯力,需要配置workId和dataCenterId,所以啟動時第一步從Redis的R1中讀取可用的worId和dataCenterId礼华,
    第二步把拿到的可用WD放到放到R2中咐鹤,第三步獲取當(dāng)前Eureka-client客戶端的實例ID和剛才放入R2的數(shù)據(jù)關(guān)聯(lián)放R3中,在此同時ID-Client也向Eureka-Server注冊
  3. ID-Server會獲取Eureka-Server中ID-Client的注冊實例列表圣絮,定時判斷祈惶,R3中的列表數(shù)據(jù)和Eureka-Server中的實例列表的差異,如果有差異表示有機(jī)器實例Down了扮匠,ID-Server主動收回R2中的數(shù)據(jù)給R1捧请,并刪除R3中無效應(yīng)用實例的數(shù)據(jù)

ID-Server

當(dāng)前設(shè)計ID-Server只能跑一個實例;

  1. 當(dāng)ID-Server第一次運(yùn)行棒搜,這時候Redis中的R1是空的疹蛉,需要初始化配置數(shù)據(jù)(workId,dataCenterId 后面簡稱WD),配置文件中自定義參數(shù)
spring:
  application:
    name: uuid-server
  redis: # redis配置 ========================
    host: localhost
    port: 6379
    timeout: 5000ms
server:
  port: 8082

eureka:
  client:
    registryFetchIntervalSeconds: 5
    service-url:
      defaultZone: http://localhost:8761/eureka/
    fetch-registry: true # 只需要拉取注冊表就可以
    register-with-eureka: false # 不需要向Eureka注冊

uuid:
  # ID生成器的應(yīng)用名稱
  client-application-name: uuid-snowflake-client
  # 機(jī)器數(shù)量力麸,默認(rèn)2臺可款,最大31*31=961臺
  machine-count: 10
  # 同步檢測已使用池中的數(shù)據(jù)和eureka注冊表中的實例數(shù)30秒,生產(chǎn)環(huán)境設(shè)置10分鐘以上
  task-execution-interval: 30

R1 中存的是一個Map數(shù)據(jù)格式[{1:{workId:1,dataCenterId:1}}, {2:{workId:1,dataCenterId:2}}, ...]
R2 中存的數(shù)據(jù)格式Map [{1:{workId:1,dataCenterId:1}}, {2:{workId:1,dataCenterId:2}}, ...]
R3 中的數(shù)據(jù)格式 Map [{"實例1": 1}, {"實例2": 2}]

  1. 如果是重啟ID-Server會主動去讀取Redis中R1池中未被使用的WD
  2. 監(jiān)控Redis中R3的數(shù)據(jù)列表克蚂,與Eureka-Server中的ID-Client實例列表相對比差異

ID-Client

  1. 啟動時從Redis中的R1中取一個WD放到R2中闺鲸,并和取出來的WD的KEY 關(guān)聯(lián)后放到R3中記錄
    配置文件中需要注意的是:
......

eureka:
  instance:
    leaseRenewalIntervalInSeconds: 10
    # 如果是集群模式部署,instance-id值必須設(shè)置
    instance-id: ${spring.application.name}:${server.port}:${random.int}
......
  1. snowflake以單例模式運(yùn)行

運(yùn)行-單機(jī)

注意:運(yùn)行順序 Eureka-Server => ID-Server => ID-Client
單機(jī)多實例不同端口測試埃叭,跑兩個實例端口分別是8121和8123

2019-06-10 19:25:55.910  INFO 39078 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : Getting all instance registry info from the eureka server
2019-06-10 19:25:55.914  INFO 39078 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : The response status is 200
2019-06-10 19:25:56.201  INFO 39078 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 未使用DataPoolMap 10 
2019-06-10 19:25:56.215  INFO 39078 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 1. 應(yīng)用 uuid-snowflake-client:8121:-1696405068 抽到的 key 8 value 為 UuidDataItemModel{workId=1, dataCenterId=8}
2019-06-10 19:25:56.215  INFO 39078 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 2. 將抽到的數(shù)據(jù)到放已經(jīng)使用的池子里
2019-06-10 19:25:56.228  INFO 39078 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 3. 查詢已使用池子數(shù)據(jù) {8=UuidDataItemModel{workId=1, dataCenterId=8}}
2019-06-10 19:25:56.234  INFO 39078 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 4. 查詢應(yīng)用和數(shù)據(jù)種子關(guān)聯(lián)的池子 {uuid-snowflake-client:8121:-1696405068=8}
2019-06-10 19:25:56.234  INFO 39078 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : ============== 設(shè)置完成 workId=1, dataCenterId=8

第二個應(yīng)用啟動

2019-06-10 19:27:59.992  INFO 39088 --- [           main] io.lettuce.core.EpollProvider            : Starting without optional epoll library
2019-06-10 19:27:59.993  INFO 39088 --- [           main] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
2019-06-10 19:28:05.117  INFO 39088 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 未使用DataPoolMap 9 
2019-06-10 19:28:05.129  INFO 39088 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 1. 應(yīng)用 uuid-snowflake-client:8123:-70110274 抽到的 key 1 value 為 UuidDataItemModel{workId=1, dataCenterId=1}
2019-06-10 19:28:05.129  INFO 39088 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 2. 將抽到的數(shù)據(jù)到放已經(jīng)使用的池子里
2019-06-10 19:28:05.138  INFO 39088 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 3. 查詢已使用池子數(shù)據(jù) {1=UuidDataItemModel{workId=1, dataCenterId=1}, 8=UuidDataItemModel{workId=1, dataCenterId=8}}
2019-06-10 19:28:05.147  INFO 39088 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : 4. 查詢應(yīng)用和數(shù)據(jù)種子關(guān)聯(lián)的池子 {uuid-snowflake-client:8121:-1696405068=8, uuid-snowflake-client:8123:-70110274=1}
2019-06-10 19:28:05.147  INFO 39088 --- [           main] c.l.u.s.s.u.Runner.SnowflakeRunner       : ============== 設(shè)置完成 workId=1, dataCenterId=1

訪問 http://localhost:8121/generator/idhttp://localhost:8123/generator/id

生成ID服務(wù)的端口:8121, workId: 1, dateCenterId: 8
生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 1

運(yùn)行-集群模式-docker swarm

在現(xiàn)有的docker swarm環(huán)境中部署摸恍,這里不講如何打包成docker image

  1. docker swarm 的編排配置
    https://github.com/liangxiaobo/uuid-generate/blob/cluster-v1.0/docker-swarm-compose.yml

  2. 測試結(jié)果

[root@manager uuid-generate]# docker service ls
ID                  NAME                           MODE                REPLICAS            IMAGE                                                  PORTS
gjjf0oaou5zg        id-app_uuid-eureka-server      replicated          1/1                 172.16.10.192:5000/bobo/uuid-eureka-server:latest      *:8761->8761/tcp
wmwusdo737pm        id-app_uuid-server             replicated          1/1                 172.16.10.192:5000/bobo/uuid-server:latest             *:8082->8082/tcp
y97ceng663iz        id-app_uuid-snowflake-client   replicated          2/2                 172.16.10.192:5000/bobo/uuid-snowflake-client:latest   *:8123->8123/tcp

部署完成后可訪問,你集群IP:端口赤屋,http://ip:8123/generator/id 多刷新幾次

id-app_uuid-snowflake-client.2.0tkgecz302jw@work2    | 2019-06-12 17:16:50.522  INFO 1 --- [nio-8123-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in 12 ms
id-app_uuid-snowflake-client.2.0tkgecz302jw@work2    | 2019-06-12 17:16:50.559  INFO 1 --- [nio-8123-exec-2] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 3
id-app_uuid-snowflake-client.2.0tkgecz302jw@work2    | 單例模式 ===== 進(jìn)入
id-app_uuid-snowflake-client.2.0tkgecz302jw@work2    | 2019-06-12 17:19:16.838  INFO 1 --- [nio-8123-exec-4] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 3
id-app_uuid-snowflake-client.2.0tkgecz302jw@work2    | 2019-06-12 17:19:17.056  INFO 1 --- [nio-8123-exec-6] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 3
id-app_uuid-snowflake-client.2.0tkgecz302jw@work2    | 2019-06-12 17:19:17.238  INFO 1 --- [nio-8123-exec-8] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 3
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 2019-06-12 17:21:23.632  INFO 1 --- [nio-8123-exec-7] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 2019-06-12 17:21:23.632  INFO 1 --- [nio-8123-exec-7] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 2019-06-12 17:21:23.640  INFO 1 --- [nio-8123-exec-7] o.s.web.servlet.DispatcherServlet        : Completed initialization in 8 ms
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 2019-06-12 17:21:23.673  INFO 1 --- [nio-8123-exec-7] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 9
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 單例模式 ===== 進(jìn)入
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 2019-06-12 17:22:35.978  INFO 1 --- [nio-8123-exec-6] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 9
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 2019-06-12 17:22:36.057  INFO 1 --- [nio-8123-exec-8] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 9
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 2019-06-12 17:22:36.143  INFO 1 --- [io-8123-exec-10] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 9
id-app_uuid-snowflake-client.1.gxkc7k0xuyph@manager    | 2019-06-12 17:22:36.225  INFO 1 --- [nio-8123-exec-2] c.l.u.s.s.u.c.SnowflakeController        : 生成ID服務(wù)的端口:8123, workId: 1, dateCenterId: 9

運(yùn)行-集群模式 k8s 部署

需要注意

1. 本實例在k8s中 uuid-eureka-server和uuid-server 只部署一個實例
2. 使用的docker私有庫误墓,請參考[k8s 從私有倉庫拉取鏡像](http://www.reibang.com/p/3f24bbee72ad)

重新打包上傳docker image

   cd uuid-eureka-server/
   mvn package docker:build -Dmaven.test.skip=true
   
   cd uuid-server/
   mvn package docker:build -Dmaven.test.skip=true
   
   cd uuid-snowflake-client/
   mvn package docker:build -Dmaven.test.skip=true

重新 docker push image

同上

執(zhí)行

  1. 先發(fā)布Eureka-Server, 執(zhí)行根目錄的 eureka-k8s.yaml
kubectl create -f eureka-k8s.yaml
  1. 執(zhí)行發(fā)布 uuid-server和uuid-snowflake-client 執(zhí)行根目錄的 uuid-k8s.yaml
kubectl create -f uuid-k8s.yaml 

結(jié)果

查看pod

[root@master work]# kubectl get pod -o wide
NAME                                    READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
nginx-65f88748fd-s9727                  1/1     Running   1          27h   10.244.1.4    node1   <none>           <none>
uuid-eureka-server-0                    1/1     Running   0          52m   10.244.1.37   node1   <none>           <none>
uuid-server-68c4b867c-7qt8p             1/1     Running   0          50m   10.244.1.38   node1   <none>           <none>
uuid-snowflake-client-866764b58-ltdc6   1/1     Running   0          50m   10.244.1.39   node1   <none>           <none>
uuid-snowflake-client-866764b58-nh6gl   1/1     Running   0          50m   10.244.2.25   node2   <none>           <none>

查看service

[root@master work]# kubectl get svc
NAME                    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes              ClusterIP   10.1.0.1       <none>        443/TCP          29h
nginx                   NodePort    10.1.193.136   <none>        80:30057/TCP     27h
uuid-eureka-server      NodePort    10.1.8.102     <none>        8761:32297/TCP   56m
uuid-snowflake-client   NodePort    10.1.103.35    <none>        8123:31968/TCP   54m

其中訪問 eureka-server地址 http://IP:32297 訪問id生成服務(wù) http://IP:31968/generator/id

  • uuid-server的日志
INFO 1 --- [pool-7-thread-1] c.l.u.s.u.UuidServerApplication          : 應(yīng)用關(guān)聯(lián)的種子 2
INFO 1 --- [pool-7-thread-1] c.l.u.s.u.UuidServerApplication          : 服務(wù)應(yīng)用注冊數(shù)量: 2

應(yīng)用關(guān)聯(lián)的種子 和 服務(wù)應(yīng)用注冊數(shù)量 相等時,表示正常益缎,否則表示有異常

注意

uuid-server項目主要工作是初始化 workid和dataCenterId到redis中谜慌,并監(jiān)控redis中的關(guān)聯(lián)池與實際Eureka-server中注冊服務(wù)的變化,
監(jiān)控的任務(wù) task-execution-interval: 30默認(rèn)30秒執(zhí)行一次莺奔,由于在生產(chǎn)環(huán)境中欣范,uuid-snowflake-client注冊的數(shù)量不確定,所以需要設(shè)置足夠大的時長令哟,10分鐘以上恼琼,
30秒為測試環(huán)境。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屏富,一起剝皮案震驚了整個濱河市晴竞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狠半,老刑警劉巖噩死,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颤难,死亡現(xiàn)場離奇詭異,居然都是意外死亡已维,警方通過查閱死者的電腦和手機(jī)行嗤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垛耳,“玉大人栅屏,你說我怎么就攤上這事√孟剩” “怎么了栈雳?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缔莲。 經(jīng)常有香客問我甫恩,道長,這世上最難降的妖魔是什么酌予? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任磺箕,我火速辦了婚禮,結(jié)果婚禮上抛虫,老公的妹妹穿的比我還像新娘松靡。我一直安慰自己,他們只是感情好建椰,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布雕欺。 她就那樣靜靜地躺著,像睡著了一般棉姐。 火紅的嫁衣襯著肌膚如雪屠列。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天伞矩,我揣著相機(jī)與錄音笛洛,去河邊找鬼。 笑死乃坤,一個胖子當(dāng)著我的面吹牛苛让,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播湿诊,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼狱杰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了厅须?” 一聲冷哼從身側(cè)響起仿畸,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后错沽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體簿晓,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年甥捺,在試婚紗的時候發(fā)現(xiàn)自己被綠了抢蚀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镀层。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡镰禾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唱逢,到底是詐尸還是另有隱情吴侦,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布坞古,位于F島的核電站备韧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏痪枫。R本人自食惡果不足惜织堂,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奶陈。 院中可真熱鬧易阳,春花似錦、人聲如沸吃粒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽徐勃。三九已至事示,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間僻肖,已是汗流浹背肖爵。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留臀脏,地道東北人遏匆。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像谁榜,于是被迫代替她去往敵國和親幅聘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355