国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

線上使用雪花算法生成id重復(fù)問(wèn)題

這篇具有很好參考價(jià)值的文章主要介紹了線上使用雪花算法生成id重復(fù)問(wèn)題。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

項(xiàng)目中使用的是hutool工具類庫(kù)提供的雪花算法生成id方式,版本使用的是5.3.1

 		<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.1</version>
        </dependency>

雪花算法生成id方式提供了getSnowflake(workerId,datacenterId)獲取單例的Snowflake對(duì)象,并對(duì)生成id的方法nextId()進(jìn)行了synchronized加鎖處理。

IdUtil

	public static Snowflake getSnowflake(long workerId, long datacenterId) {
		return Singleton.get(Snowflake.class, workerId, datacenterId);
	}

Snowflake

	public synchronized long nextId() {
		long timestamp = genTime();
		if (timestamp < lastTimestamp) {
			// 如果服務(wù)器時(shí)間有問(wèn)題(時(shí)鐘后退) 報(bào)錯(cuò)。
			throw new IllegalStateException(StrUtil.format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp));
		}
		if (lastTimestamp == timestamp) {
			sequence = (sequence + 1) & sequenceMask;
			if (sequence == 0) {
				timestamp = tilNextMillis(lastTimestamp);
			}
		} else {
			sequence = 0L;
		}

		lastTimestamp = timestamp;

		return ((timestamp - twepoch) << timestampLeftShift) | (dataCenterId << dataCenterIdShift) | (workerId << workerIdShift) | sequence;
	}

項(xiàng)目中使用雪花算法
IdUtils

public class IdUtils {
    private static final Snowflake SNOWFLAKE = IdUtil.getSnowflake(1, 1);
    public static Long getNextId() {
        return SNOWFLAKE.nextId();
    }
}

舉例controller
UserController

@Slf4j
@RestController
@RequestMapping("/id")
public class UserController {
    @Autowired
    private IUserService userService;


    @GetMapping("/next")
    public Long next() {
        Long id = IdUtils.getNextId();
        User user = new User().setId(id);
        boolean save = userService.save(user);
        if (save) {
            return id;
        }
        return 0L;
    }
}

線上環(huán)境報(bào)例如:BatchUpdateException: Duplicate entry ‘1531683498452185090’ for key ‘PRIMARY’ 插入主鍵沖突問(wèn)題。

分析代碼,定位到雪花算法生成id時(shí)出現(xiàn)了問(wèn)題
首先排除時(shí)鐘回退的情況,因?yàn)樵?.3.1版本如果服務(wù)器時(shí)間有問(wèn)題(時(shí)鐘后退) 直接報(bào)錯(cuò)。

1單機(jī)

排除單機(jī)情況下出現(xiàn)id重復(fù)問(wèn)題,SNOWFLAKE 是單例的,并且生成id的方法被synchronized修飾。

2集群環(huán)境下

需要手動(dòng)設(shè)置dataCenterId 和 workerId值,不同機(jī)器相同時(shí)間戳要想保證生成的id不重復(fù),那么dataCenterId 和workerId的組合必須是唯一的

private static final Snowflake SNOWFLAKE = IdUtil.getSnowflake(workerId , dataCenterId );

Mybatis-Plus v3.4.2 雪花算法實(shí)現(xiàn)類 Sequence,提供了兩種構(gòu)造方法:無(wú)參構(gòu)造,自動(dòng)生成 dataCenterId 和 workerId;有參構(gòu)造,創(chuàng)建 Sequence 時(shí)明確指定標(biāo)識(shí)位

Hutool v5.7.9 參照了 Mybatis-Plus dataCenterId 和 workerId 生成方案,提供了默認(rèn)實(shí)現(xiàn)
一起看下 Sequence 的創(chuàng)建默認(rèn)無(wú)參構(gòu)造,如何生成 dataCenterId 和 workerId

public static long getDataCenterId(long maxDatacenterId) {
    long id = 1L;
    final byte[] mac = NetUtil.getLocalHardwareAddress();
    if (null != mac) {
        id = ((0x000000FF & (long) mac[mac.length - 2])
                | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
        id = id % (maxDatacenterId + 1);
    }
 
    return id;
}

入?yún)?maxDatacenterId 是一個(gè)固定值,代表數(shù)據(jù)中心 ID 最大值,默認(rèn)值 31

為什么最大值要是 31?因?yàn)?5bit 的二進(jìn)制最大是 11111,對(duì)應(yīng)十進(jìn)制數(shù)值 31

獲取 dataCenterId 時(shí)存在兩種情況,一種是網(wǎng)絡(luò)接口為空,默認(rèn)取 1L;另一種不為空,通過(guò) Mac 地址獲取 dataCenterId

可以得知,dataCenterId 的取值與 Mac 地址有關(guān)

接下來(lái)再看看 workerId

public static long getWorkerId(long datacenterId, long maxWorkerId) {
    final StringBuilder mpid = new StringBuilder();
    mpid.append(datacenterId);
    try {
        mpid.append(RuntimeUtil.getPid());
    } catch (UtilException igonre) {
        //ignore
    }
    return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}

入?yún)?maxWorkderId 也是一個(gè)固定值,代表工作機(jī)器 ID 最大值,默認(rèn)值 31;datacenterId 取自上述的 getDatacenterId 方法

name 變量值為 PID@IP,所以 name 需要根據(jù) @ 分割并獲取下標(biāo) 0,得到 PID

通過(guò) MAC + PID 的 hashcode 獲取16個(gè)低位,進(jìn)行運(yùn)算,最終得到 workerId
分配標(biāo)識(shí)位
Mybatis-Plus 標(biāo)識(shí)位的獲取依賴 Mac 地址和進(jìn)程 PID,雖然能做到盡量不重復(fù),但仍有小幾率

當(dāng)然了我們也可以自己實(shí)現(xiàn)生成workerId、datacenterId的策略
如下,但并未測(cè)試過(guò)

@Configuration
public class SnowFlakeIdConfig {

    @Bean
    public SnowFlakeIdUtil propertyConfigurer() {
        return new SnowFlakeIdUtil(getWorkId(), getDataCenterId(), 10);
    }


    /**
     * workId使用IP生成
     * @return workId
     */
    private static Long getWorkId() {
        try {
            String hostAddress = Inet4Address.getLocalHost().getHostAddress();
            int[] ints = StringUtils.toCodePoints(hostAddress);
            int sums = 0;
            for (int b : ints) {
                sums = sums + b;
            }
            return (long) (sums % 32);
        }
        catch (UnknownHostException e) {
            // 失敗就隨機(jī)
            return RandomUtils.nextLong(0, 31);
        }
    }


    /**
     * dataCenterId使用hostName生成
     * @return dataCenterId
     */
    private static Long getDataCenterId() {
        try {
            String hostName = SystemUtils.getHostName();
            int[] ints = StringUtils.toCodePoints(hostName);
            int sums = 0;
            for (int i: ints) {
                sums = sums + i;
            }
            return (long) (sums % 32);
        }
        catch (Exception e) {
            // 失敗就隨機(jī)
            return RandomUtils.nextLong(0, 31);
        }
    }
}

很顯然這些方法都依賴于獲取ip 等信息,比如ip并非連續(xù),甚至獲取不到ip等信息時(shí),還是有可能出現(xiàn)id重復(fù)問(wèn)題

3docker容器

就比如在docker容器中,一般ip都是隨機(jī)的,并且未經(jīng)過(guò)設(shè)置還無(wú)法獲得ip信息。
docker容器和宿主機(jī)環(huán)境是隔離的,但是可以在啟動(dòng)docker容器時(shí)將宿主機(jī)的主機(jī)名以環(huán)境變量的形式傳入,代碼在容器中獲取該值即可。

這里采用另一種方法,我們可以手動(dòng)設(shè)置workid生成規(guī)則,并存到redis中。
這里只設(shè)置了workId,保證workId和dataCenterId的組合不重復(fù)就可以。

workId的生成是系統(tǒng)每次啟動(dòng),第一次獲取Snowflake 對(duì)象時(shí)才會(huì)進(jìn)行,

public class IdUtils {
    private static StringRedisTemplate stringRedisTemplate = ApplicationContextHolder.getBean(StringRedisTemplate.class);
    private static String SNOWFLAKE_WORKID = "snowflake:workid";
    private static final Snowflake SNOWFLAKE = IdUtil.getSnowflake(getWorkerId(SNOWFLAKE_WORKID), 1);


    public static Long getNextId() {
        return SNOWFLAKE.nextId();
    }


    /**
     * 容器環(huán)境生成workid 并redis緩存
     * @param key
     * @return
     */
    public static Long getWorkerId(String key) {
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_worker_id.lua")));
        redisScript.setResultType(Long.class);
        return stringRedisTemplate.execute(redisScript, Collections.singletonList(key));
    }
 }

ApplicationContext對(duì)象的獲取 ,解決使用注解獲取不到bean的問(wèn)題

@Component
public class ApplicationContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextHolder.applicationContext = applicationContext;
    }

    /**
     * 全局的applicationContext對(duì)象
     * @return applicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName) {
        return (T) applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

}

lua腳本 redis_worker_id.lua
workId初始為0 ,每次獲取后+1,知道獲取到31后重置為0
為什么上限是31呢,因?yàn)閣orkId默認(rèn)占5bit

local isExist = redis.call('exists', KEYS[1])
if isExist == 1
then
    local workerId = redis.call('get', KEYS[1])
    workerId = (workerId + 1) % 31
    redis.call('set', KEYS[1], workerId)
    return workerId
else
    redis.call('set', KEYS[1], 0)
    return 0
end

測(cè)試

使用nginx 端口8080

        location /api {  
            default_type  application/json;
            #internal;  
            keepalive_timeout   30s;  
            keepalive_requests  1000;  
            #支持keep-alive  
            proxy_http_version 1.1;  
            rewrite /api(/.*) $1 break;  
            proxy_pass_request_headers on;
            #more_clear_input_headers Accept-Encoding;  
            proxy_next_upstream error timeout;  
            #proxy_pass http://127.0.0.1:8081;
            proxy_pass http://backend;
        }
    }

    upstream backend {
        server 127.0.0.1:8081 max_fails=5 fail_timeout=10s weight=1;
        server 127.0.0.1:8082 max_fails=5 fail_timeout=10s weight=1;
    }  

代理訪問(wèn)8081、8082兩個(gè)項(xiàng)目
將自己的項(xiàng)目端口號(hào)設(shè)置為8081,并復(fù)制Copy Configuration ,VM options設(shè)置

-Dserver.port=8082
這樣啟動(dòng)nginx8080,項(xiàng)目8081、8082
然后使用Jmeter進(jìn)行壓測(cè),比如1000個(gè)線程 循環(huán)10次進(jìn)行插入數(shù)據(jù)庫(kù)
訪問(wèn)路徑
線上使用雪花算法生成id重復(fù)問(wèn)題
不再出現(xiàn)id重復(fù)問(wèn)題

參考
https://blog.csdn.net/weixin_36586120/article/details/118018414

https://www.cnblogs.com/hzzjj/p/15117771.html
https://blog.csdn.net/nickDaDa/article/details/89357667文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-422534.html

到了這里,關(guān)于線上使用雪花算法生成id重復(fù)問(wèn)題的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 雪花算法生成唯一數(shù)字id

    2024年02月02日
    瀏覽(87)
  • 分布式ID生成算法——雪花算法

    分布式ID生成算法——雪花算法

    一、分布式ID ID可以唯一標(biāo)識(shí)一條記錄。 對(duì)于單體架構(gòu),我們可以使用自增ID來(lái)保證ID的唯一性。但是,在分布式系統(tǒng)中,簡(jiǎn)單的使用自增ID就會(huì)導(dǎo)致ID沖突。這也就引出了 分布式ID 問(wèn)題。分布式ID也要求滿足分布式系統(tǒng)的 高性能、高可用、高并發(fā) 的特點(diǎn)。 二、雪花算法 世界

    2024年02月06日
    瀏覽(26)
  • 分布式ID生成算法:雪花算法

    雪花算法(Snowflake)是一種分布式ID生成算法,可以生成唯一的、有序的、不重復(fù)的ID號(hào),廣泛應(yīng)用于分布式系統(tǒng)中。其生成的ID號(hào)由64位二進(jìn)制數(shù)組成,可以轉(zhuǎn)換成16進(jìn)制或10進(jìn)制的字符串表示。 雪花算法的核心思想是將一個(gè)64位的二進(jìn)制數(shù)分成四部分,分別表示時(shí)間戳、數(shù)據(jù)

    2024年02月15日
    瀏覽(35)
  • 分布式ID(2):雪花算法生成ID

    分布式ID(2):雪花算法生成ID

    1 雪花算法簡(jiǎn)介 這種方案大致來(lái)說(shuō)是一種以劃分命名空間(UUID也算,由于比較常見(jiàn),所以單獨(dú)分析)來(lái)生成ID的一種算法,這種方案把64-bit分別劃分成多段,分開(kāi)來(lái)標(biāo)示機(jī)器、時(shí)間等,比如在snowflake中的64-bit分別表示如下圖(圖片來(lái)自網(wǎng)絡(luò))所示: 41-bit的時(shí)間可以表示(1L

    2024年01月20日
    瀏覽(30)
  • 分布式—雪花算法生成ID

    分布式—雪花算法生成ID

    由64個(gè)Bit(比特)位組成的long類型的數(shù)字 0 | 0000000000 0000000000 0000000000 000000000 | 00000 | 00000 | 000000000000 1個(gè)bit:符號(hào)位,始終為0。 41個(gè)bit:時(shí)間戳,精確到毫秒級(jí)別,可以使用69年。 10個(gè)bit:工作機(jī)器ID,可以部署在1024個(gè)節(jié)點(diǎn)上。 12個(gè)bit:序列號(hào),每個(gè)節(jié)點(diǎn)每毫秒內(nèi)最多可以生成

    2024年02月11日
    瀏覽(20)
  • 雪花算法ID生成器工具類

    可以通過(guò)配置bean添加到容器,注入使用

    2024年02月15日
    瀏覽(28)
  • 分布式唯一ID生成算法——雪花算法(SnowFlake)

    分布式唯一ID生成算法——雪花算法(SnowFlake)

    SnowFlake算法 據(jù)國(guó)家大氣研究中心的查爾斯·奈特稱,一般的雪花大約由10^19個(gè)水分子組成。在雪花形成過(guò)程中,會(huì)形成不同的結(jié)構(gòu)分支,所以說(shuō)大自然中不存在兩片完全一樣的雪花,每一片雪花都擁有自己漂亮獨(dú)特的形狀。 雪花算法表示生成的id如雪花般獨(dú)一無(wú)二。 snowflake是

    2023年04月20日
    瀏覽(26)
  • 雪花算法生成分布式主鍵ID

    直接上代碼,復(fù)制即可使用 在這個(gè)示例中,你可以通過(guò) SnowflakeIdGenerator.init(dataCenterId, workerId); 初始化數(shù)據(jù)中心 ID 和工作 ID,然后通過(guò) SnowflakeIdGenerator.generateId(); 靜態(tài)方法生成 Snowflake ID 的字符串形式。

    2024年02月22日
    瀏覽(23)
  • 分布式Id生成之雪花算法(SnowFlake)

    分布式Id生成之雪花算法(SnowFlake)

    目錄 前言 回顧二進(jìn)制 二進(jìn)制概念 運(yùn)算法則 位(Bit) 字節(jié)(Byte) 字符 字符集 二進(jìn)制原碼、反碼、補(bǔ)碼 有符號(hào)數(shù)和無(wú)符號(hào)數(shù) 疑問(wèn):為什么不是-127 ~ 127 ? 為什么需要分布式全局唯一ID以及分布式ID得業(yè)務(wù)需求? ID生成規(guī)則部分硬性要求 ID生成系統(tǒng)的可用性要求 通用解決方

    2024年02月11日
    瀏覽(25)
  • 【智能排班系統(tǒng)】雪花算法生成分布式ID

    【智能排班系統(tǒng)】雪花算法生成分布式ID

    在復(fù)雜而龐大的分布式系統(tǒng)中,確保數(shù)據(jù)實(shí)體的唯一標(biāo)識(shí)性是一項(xiàng)至關(guān)重要的任務(wù),生成全局唯一且有序的ID生成機(jī)制成為必不可少的環(huán)節(jié)。雪花算法(Snowflake Algorithm)正是為此目的而生,以其簡(jiǎn)潔的設(shè)計(jì)、高效的表現(xiàn)與良好的擴(kuò)展性贏得了業(yè)界的廣泛認(rèn)可。 雪花算法最早由

    2024年04月10日
    瀏覽(21)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包