日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

java高并發(fā)情況下分布式全局ID,只花五分鐘就能搞的明明白白,看完就清楚了~

 hncdman 2023-04-28 發(fā)布于湖南

代碼老濕 代碼老濕 2019-12-06 11:13:43

java高并發(fā)

1、高并發(fā)情況下,生成分布式全局id策略

2、利用全球唯一UUID生成訂單號(hào)優(yōu)缺點(diǎn)

3、基于數(shù)據(jù)庫(kù)自增或者序列生成訂單號(hào)

4、數(shù)據(jù)庫(kù)集群如何考慮數(shù)據(jù)庫(kù)自增唯一性

5、基于Redis生成生成全局id策略

6、Twitter的Snowflake算法生成全局id

7、基于Zookeeper生成全局id

高并發(fā)情況下,生成分布式全局id策略

1、注意冪等性且全局唯一性

2、注意安全性,不能被猜疑

3、趨勢(shì)遞增性

訂單號(hào)命名規(guī)則:比如“業(yè)務(wù)編碼 + 時(shí)間戳 + 機(jī)器編號(hào)[前4位] + 隨機(jī)4位數(shù) + 毫秒數(shù)”。

利用全球唯一UUID生成訂單號(hào)

UUID基本概念:

UUID是指在一臺(tái)機(jī)器上生成的數(shù)字,它保證對(duì)在同一時(shí)空中的所有機(jī)器都是唯一的。

UUID組成部分:當(dāng)前日期和時(shí)間+時(shí)鐘序列+隨機(jī)數(shù)+全局唯一的IEEE機(jī)器識(shí)別號(hào)

全局唯一的IEEE機(jī)器識(shí)別號(hào):如果有網(wǎng)卡,從網(wǎng)卡MAC地址獲得,沒有網(wǎng)卡以其他方式獲得。

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

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

簡(jiǎn)單,代碼方便

生成ID性能非常好,基本不會(huì)有性能問題

全球唯一,在遇見數(shù)據(jù)遷移,系統(tǒng)數(shù)據(jù)合并,或者數(shù)據(jù)庫(kù)變更等情況下,可以從容應(yīng)對(duì)

缺點(diǎn):

沒有排序,無法保證趨勢(shì)遞增

UUID往往是使用字符串存儲(chǔ),查詢的效率比較低

存儲(chǔ)空間比較大,如果是海量數(shù)據(jù)庫(kù),就需要考慮存儲(chǔ)量的問題。

傳輸數(shù)據(jù)量大

UUID不需要聯(lián)網(wǎng)生成,redis需要。

基于數(shù)據(jù)庫(kù)自增方式

實(shí)現(xiàn)思路:利用數(shù)據(jù)庫(kù)自增或者序列號(hào)方式實(shí)現(xiàn)訂單號(hào)

注意:在數(shù)據(jù)庫(kù)集群環(huán)境下,默認(rèn)自增方式存在問題,因?yàn)槎际菑?開始自增,可能會(huì)存在重復(fù),應(yīng)該設(shè)置每臺(tái)不同數(shù)據(jù)庫(kù)自增的間隔方式不同。

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

簡(jiǎn)單,代碼方便,性能可以接受。

數(shù)字ID天然排序,對(duì)分頁或者需要排序的結(jié)果很有幫助。

缺點(diǎn):

不同數(shù)據(jù)庫(kù)語法和實(shí)現(xiàn)不同,數(shù)據(jù)庫(kù)遷移的時(shí)候或多數(shù)據(jù)庫(kù)版本支持的時(shí)候需要處理。

在性能達(dá)不到要求的情況下,比較難于擴(kuò)展。

在單個(gè)數(shù)據(jù)庫(kù)或讀寫分離或一主多從的情況下,只有一個(gè)主庫(kù)可以生成。有單點(diǎn)故障的風(fēng)險(xiǎn)。

分表分庫(kù)的時(shí)候會(huì)有麻煩。

數(shù)據(jù)庫(kù)集群如何考慮數(shù)據(jù)庫(kù)自增唯一性

在數(shù)據(jù)庫(kù)集群環(huán)境下,默認(rèn)自增方式存在問題,因?yàn)槎际菑?開始自增,可能會(huì)存在重復(fù),應(yīng)該設(shè)置每臺(tái)節(jié)點(diǎn)自增步長(zhǎng)不同。

查詢自增的步長(zhǎng)

SHOW VARIABLES LIKE 'auto_inc%'

修改自增的步長(zhǎng)

SET @@auto_increment_increment=10;

修改起始值

SET @@auto_increment_offset=5;

假設(shè)有兩臺(tái)mysql數(shù)據(jù)庫(kù)服務(wù)器

節(jié)點(diǎn)①自增 1 3 5 7 9 11 ….

節(jié)點(diǎn)②自增 2 4 6 8 10 12 ….

注意:在最開始設(shè)置好了每臺(tái)節(jié)點(diǎn)自增方式步長(zhǎng)后,確定好了mysql集群數(shù)量后,無法擴(kuò)展新的mysql,不然生成步長(zhǎng)的規(guī)則可能會(huì)發(fā)生變化。

MySQL1 1 2 3

MySQL2 1 2 3

方法1 讀寫分離

方法2 設(shè)置自增步長(zhǎng) 需要提前設(shè)置好步長(zhǎng) 否則如果新增一臺(tái)MySQL就麻煩了

如果想提高擴(kuò)展性 采用UUID方式作為主鍵

基于Redis生成生成全局id策略

因?yàn)镽edis是單線的,天生保證原子性,可以使用Redis的原子操作 INCR和INCRBY來實(shí)現(xiàn)

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

不依賴于數(shù)據(jù)庫(kù),靈活方便,且性能優(yōu)于數(shù)據(jù)庫(kù)。

數(shù)字ID天然排序,對(duì)分頁或者需要排序的結(jié)果很有幫助。

缺點(diǎn):

如果系統(tǒng)中沒有Redis,還需要引入新的組件,增加系統(tǒng)復(fù)雜度。

需要編碼和配置的工作量比較大。

注意:在Redis集群情況下,同樣和Redis一樣需要設(shè)置不同的增長(zhǎng)步長(zhǎng),同時(shí)key一定要設(shè)置有效期

可以使用Redis集群來獲取更高的吞吐量。假如一個(gè)集群中有5臺(tái)Redis??梢猿跏蓟颗_(tái)Redis的值分別是1,2,3,4,5,然后步長(zhǎng)都是5。各個(gè)Redis生成的ID為:

A:1,6,11,16,21

B:2,7,12,17,22

C:3,8,13,18,23

D:4,9,14,19,24

E:5,10,15,20,25

比較適合使用Redis來生成每天從0開始的流水號(hào)。比如訂單號(hào)=日期+當(dāng)日自增長(zhǎng)號(hào)??梢悦刻煸赗edis中生成一個(gè)Key,使用INCR進(jìn)行累加。

如果生成的訂單號(hào)超過自增增長(zhǎng)的話,可以采用前綴+自增+并且設(shè)置有效期

當(dāng)前日期-5位自增

統(tǒng)一時(shí)間 最多生成10w-1個(gè)不重復(fù)的

假設(shè)雙十一 每秒99w訂單

package com.toov5.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.support.atomic.RedisAtomicLong;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class OrderController {    @Autowired    private RedisTemplate redisTemplate;       @RequestMapping("/order")       public Long order(String key) {              RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory() );       long andIncrement = redisAtomicLong.getAndIncrement();       return andIncrement;          }}

補(bǔ)零:

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.support.atomic.RedisAtomicLong;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class OrderController {    @Autowired    private RedisTemplate redisTemplate;       @RequestMapping("/order")       public String order(String key) {              RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory() );       long increment = redisAtomicLong.getAndIncrement();       String id = String.format("%1$05d", increment);  //5位數(shù)       return id;          }}

加上前綴:

import java.text.SimpleDateFormat;import java.util.Date;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.support.atomic.RedisAtomicLong;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class OrderController {    @Autowired    private RedisTemplate redisTemplate;       @RequestMapping("/order")       public String order(String key) {              RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory() );       long increment = redisAtomicLong.getAndIncrement();       String id =prefix()+"-"+String.format("%1$05d", increment);  //5位數(shù)       return id;          }      public static String prefix() {        String temp_str = "";        Date dt = new Date();        // 最后的aa表示“上午”或“下午” HH表示24小時(shí)制 如果換成hh表示12小時(shí)制        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");        temp_str = sdf.format(dt);        return temp_str;    }}

Redis如果做集群,會(huì)產(chǎn)生重復(fù)的問題!

@RequestMapping("/order1")    public String order1(String key) {        RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());        // // 起始值        // redisAtomicLong.set(10);        // 設(shè)置步長(zhǎng)加10!!!!        redisAtomicLong.addAndGet(9);        return redisAtomicLong.incrementAndGet() + "";    }

redis 的key的失效時(shí)間問題!

24h 第二天時(shí)間變了 不會(huì)重復(fù)了哦

Twitter的snowflake(雪花)算法 (跟UUID一樣不用聯(lián)網(wǎng)) snowflake是Twitter開源的分布式ID生成算法,結(jié)果是一個(gè)long型的ID。其核心思想是: 高位隨機(jī)+毫秒數(shù)+機(jī)器碼(數(shù)據(jù)中心+機(jī)器id)+10位的流水號(hào)碼 Github地址: https://github.com/twitter-archive/snowflakeSnowflake 原理: snowflake生產(chǎn)的ID是一個(gè)18位的long型數(shù)字,二進(jìn)制結(jié)構(gòu)表示如下(每部分用-分開): 0 - 00000000 00000000 00000000 00000000 00000000 0 - 00000 - 00000 - 00000000 0000 第一位未使用,接下來的41位為毫秒級(jí)時(shí)間(41位的長(zhǎng)度可以使用69年,從1970-01-01 08:00:00),然后是5位datacenterId(最大支持2^5=32個(gè),二進(jìn)制表示從00000-11111,也即是十進(jìn)制0-31),和5位workerId(最大支持2^5=32個(gè),原理同datacenterId),所以datacenterId*workerId最多支持部署1024個(gè)節(jié)點(diǎn),最后12位是毫秒內(nèi)的計(jì)數(shù)(12位的計(jì)數(shù)順序號(hào)支持每個(gè)節(jié)點(diǎn)每毫秒產(chǎn)生2^12=4096個(gè)ID序號(hào)).所有位數(shù)加起來共64位,恰好是一個(gè)Long型(轉(zhuǎn)換為字符串長(zhǎng)度為18).單臺(tái)機(jī)器實(shí)例,通過時(shí)間戳保證前41位是唯一的,分布式系統(tǒng)多臺(tái)機(jī)器實(shí)例下,通過對(duì)每個(gè)機(jī)器實(shí)例分配不同的datacenterId和workerId避免中間的10位碰撞。最后12位每毫秒從0遞增生產(chǎn)ID,再提一次:每毫秒最多生成4096個(gè)ID,每秒可達(dá)4096000個(gè)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多