最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MybatisPlus使用idworker解決雪花算法重復(fù)

 更新時(shí)間:2023年02月05日 10:07:31   作者:Winner002  
本文主要介紹了MybatisPlus使用idworker解決雪花算法重復(fù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、雪花算法datacenterId重復(fù)問題

華為云的服務(wù)器的/etc/hosts中都會(huì)生成一條 127.0.1.1 hostname的記錄 ,導(dǎo)致獲取network為null ,datacenterId 會(huì)取默認(rèn)值1,導(dǎo)致重復(fù)概率大大增加。

二、idworker 是一個(gè)基于zookeeper和snowflake算法的分布式統(tǒng)一ID生成工具

通過zookeeper自動(dòng)注冊(cè)機(jī)器(最多1024臺(tái)),無需手動(dòng)指定workerId和dataCenterId。
通過ZooKeeper持久順序節(jié)點(diǎn)特性,來配置維護(hù)節(jié)點(diǎn)的編號(hào)NODEID。
集群節(jié)點(diǎn)命名服務(wù)的基本流程是:
(1)啟動(dòng)節(jié)點(diǎn)服務(wù),連接ZooKeeper, 檢查命名服務(wù)根節(jié)點(diǎn)根節(jié)點(diǎn)是否存在,如果不存在就創(chuàng)建系統(tǒng)根節(jié)點(diǎn)。
(2)在根節(jié)點(diǎn)下創(chuàng)建一個(gè)臨時(shí)順序節(jié)點(diǎn),取回順序號(hào)做節(jié)點(diǎn)的NODEID。如何臨時(shí)節(jié)點(diǎn)太多,可以根據(jù)需要,刪除臨時(shí)節(jié)點(diǎn)。

由于是采用zookeeper順序節(jié)點(diǎn)的特性生成datacenterId和workerId,可以天然的保證datacenterId和workerId的唯一性,減少了人工維護(hù)的弊端。

三、idworker使用

1、mybatis-plus-boot-starter要升級(jí)到3.4.0以上,根據(jù)具體項(xiàng)目不同選擇合適的版本

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</dependency>

2、增加idworker的1.5.0版本的依賴

<dependency>
    <groupId>com.imadcn.framework</groupId>
    <artifactId>idworker</artifactId>
    <version>1.5.0</version>
</dependency>

3、增加IdAutoConfig.java文件

@Configurationd
public class IdAutoConfig {
? ? @Value("${mybatis-plus.zookeeper.serverLists:127.0.0.1:2181}")
? ? private String zkServerLists;

? ? @Bean
? ? public IdentifierGenerator idGenerator() {
? ? ? ? return new ImadcnIdentifierGenerator(zkServerLists);
? ? }
}

或者:

@Configuration
@MapperScan(
? ? ? ? basePackages = "com.script.idworker.mapper",
? ? ? ? sqlSessionFactoryRef = "sqlSessionFactory")
public class DataSourceConfig {
? ? @Value("${mybatis-plus.zookeeper.serverLists}")
? ? private String zkServerLists;

? ? @Bean(name = "dataSource")
? ? @Primary
? ? @ConfigurationProperties(prefix = "spring.datasource.druid")
? ? public DataSource getDataSource() {
? ? ? ? return DruidDataSourceBuilder.create().build();
? ? }

? ? @Bean(name = "sqlSessionFactory")
? ? @Primary
? ? public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource datasource) throws Exception {
? ? ? ? MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
? ? ? ? sqlSessionFactory.setDataSource(datasource);
? ? ? ? MybatisConfiguration configuration = new MybatisConfiguration();
? ? ? ? // 駝峰轉(zhuǎn)下劃線
? ? ? ? configuration.setMapUnderscoreToCamelCase(true);
? ? ? ? sqlSessionFactory.setConfiguration(configuration);
? ? ? ??
? ? ? ? // 設(shè)置使用Mybatis的Snowflake算法生成id
? ? ? ? GlobalConfig globalConfig = new GlobalConfig();
? ? ? ? globalConfig.setIdentifierGenerator(new ImadcnIdentifierGenerator(zkServerLists));
? ? ? ? sqlSessionFactory.setGlobalConfig(globalConfig);
? ? ? ??
? ? ? ? return sqlSessionFactory.getObject();
? ? }
}

4、可能curator版本沖突問題,idworker依賴的curator是4.x版本的,可能和dubbo依賴的curator版本沖突,可能和zookeeper 3.4.x版本不兼容

四、idworker源碼分析

1、返回SnowflakeId

Snowflake.java#nextId()

public synchronized long nextId() {
? ? long timestamp = timeGen();
? ? // 如果上一個(gè)timestamp與新產(chǎn)生的相等,則sequence加一(0-4095循環(huán));
? ? if (lastTimestamp == timestamp) {
? ? ? ? // 對(duì)新的timestamp,sequence從0開始
? ? ? ? sequence = sequence + 1 & sequenceMask;
? ? ? ? // 毫秒內(nèi)序列溢出
? ? ? ? if (sequence == 0) {
? ? ? ? ? ? // 阻塞到下一個(gè)毫秒,獲得新的時(shí)間戳
? ? ? ? ? ? sequence = RANDOM.nextInt(100);
? ? ? ? ? ? timestamp = tilNextMillis(lastTimestamp);
? ? ? ? }
? ? } else {
? ? ? ? // 時(shí)間戳改變,毫秒內(nèi)序列重置
? ? ? ? sequence = RANDOM.nextInt(100);
? ? }
? ? // 如果當(dāng)前時(shí)間小于上一次ID生成的時(shí)間戳,說明系統(tǒng)時(shí)鐘回退過這個(gè)時(shí)候應(yīng)當(dāng)拋出異常
? ? if (timestamp < lastTimestamp) {
? ? ? ? String message = String.format("Clock moved backwards. Refusing to generate id for %d milliseconds.",
? ? ? ? ? ? ? ? (lastTimestamp - timestamp));
? ? ? ? logger.error(message);
? ? ? ? throw new RuntimeException(message);
? ? }
? ? lastTimestamp = timestamp;
? ? // 移位并通過或運(yùn)算拼到一起組成64位的ID
? ? // 1 + 41 + 10 + 22
? ? // 0 - 0000000000 0000000000 0000000000 0000000000 0 - 0000000000 - 000000000000
? ? return timestamp - epoch << timestampLeftShift | workerId << workerIdShift | sequence;
}
  • 1位標(biāo)識(shí),由于long基本類型在Java中是帶符號(hào)的,最高位是符號(hào)位,正數(shù)是0,負(fù)數(shù)是1,所以id一般是正數(shù),最高位是0
  • 41位時(shí)間戳(毫秒級(jí)),注意,41位時(shí)間戳不是存儲(chǔ)當(dāng)前時(shí)間的時(shí)間戳,而是存儲(chǔ)時(shí)間戳的差值(當(dāng)前時(shí)間戳 - 開始時(shí)間戳)得到的值),這里的的開始時(shí)間戳,一般是我們的id生成器開始使用的時(shí)間,由我們程序來指定的(如下下面程序epoch屬性)。41位的時(shí)間戳,可以使用69年
  • 10位的數(shù)據(jù)機(jī)器位,可以部署在1024個(gè)節(jié)點(diǎn),包括5位datacenterId和5位workerId,
  • 12位序列,毫秒內(nèi)的計(jì)數(shù),12位的計(jì)數(shù)順序號(hào)支持每個(gè)節(jié)點(diǎn)每毫秒(同一機(jī)器,同一時(shí)間戳)產(chǎn)生4096個(gè)ID序號(hào)
  • 加起來剛好64位,為一個(gè)Long型。

2、向zookeeper注冊(cè)workerId,返回workerId

ZookeeperWorkerRegister#register()

public long register() {
? ? InterProcessMutex lock = null;
? ? try {
? ? ? ? CuratorFramework client = (CuratorFramework) regCenter.getRawClient();
? ? ? ? lock = new InterProcessMutex(client, nodePath.getGroupPath());
? ? ? ? int numOfChildren = regCenter.getNumChildren(nodePath.getWorkerPath());
? ? ? ? if (numOfChildren < MAX_WORKER_NUM) {
? ? ? ? ? ? if (!lock.acquire(MAX_LOCK_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
? ? ? ? ? ? ? ? String message = String.format("acquire lock failed after %s ms.", MAX_LOCK_WAIT_TIME_MS);
? ? ? ? ? ? ? ? throw new TimeoutException(message);
? ? ? ? ? ? }
? ? ? ? ? ? NodeInfo localNodeInfo = getLocalNodeInfo();
? ? ? ? ? ? List<String> children = regCenter.getChildrenKeys(nodePath.getWorkerPath());
? ? ? ? ? ? // 有本地緩存的節(jié)點(diǎn)信息,同時(shí)ZK也有這條數(shù)據(jù)
? ? ? ? ? ? if (localNodeInfo != null && children.contains(String.valueOf(localNodeInfo.getWorkerId()))) {
? ? ? ? ? ? ? ? String key = getNodePathKey(nodePath, localNodeInfo.getWorkerId());
? ? ? ? ? ? ? ? String zkNodeInfoJson = regCenter.get(key);
? ? ? ? ? ? ? ? NodeInfo zkNodeInfo = createNodeInfoFromJsonStr(zkNodeInfoJson);
? ? ? ? ? ? ? ? if (checkNodeInfo(localNodeInfo, zkNodeInfo)) {
? ? ? ? ? ? ? ? ? ? // 更新ZK節(jié)點(diǎn)信息,保存本地緩存,開啟定時(shí)上報(bào)任務(wù)
? ? ? ? ? ? ? ? ? ? nodePath.setWorkerId(zkNodeInfo.getWorkerId());
? ? ? ? ? ? ? ? ? ? zkNodeInfo.setUpdateTime(new Date());
? ? ? ? ? ? ? ? ? ? updateZookeeperNodeInfo(key, zkNodeInfo);
? ? ? ? ? ? ? ? ? ? saveLocalNodeInfo(zkNodeInfo);
? ? ? ? ? ? ? ? ? ? executeUploadNodeInfoTask(key, zkNodeInfo);
? ? ? ? ? ? ? ? ? ? return zkNodeInfo.getWorkerId();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? // 無本地信息或者緩存數(shù)據(jù)不匹配,開始向ZK申請(qǐng)節(jié)點(diǎn)機(jī)器ID
? ? ? ? ? ? for (int workerId = 0; workerId < MAX_WORKER_NUM; workerId++) {
? ? ? ? ? ? ? ? String workerIdStr = String.valueOf(workerId);
? ? ? ? ? ? ? ? if (!children.contains(workerIdStr)) { // 申請(qǐng)成功
? ? ? ? ? ? ? ? ? ? NodeInfo applyNodeInfo = createNodeInfo(nodePath.getGroupName(), workerId);
? ? ? ? ? ? ? ? ? ? nodePath.setWorkerId(applyNodeInfo.getWorkerId());
? ? ? ? ? ? ? ? ? ? // 保存ZK節(jié)點(diǎn)信息,保存本地緩存,開啟定時(shí)上報(bào)任務(wù)
? ? ? ? ? ? ? ? ? ? saveZookeeperNodeInfo(nodePath.getWorkerIdPath(), applyNodeInfo);
? ? ? ? ? ? ? ? ? ? saveLocalNodeInfo(applyNodeInfo);
? ? ? ? ? ? ? ? ? ? executeUploadNodeInfoTask(nodePath.getWorkerIdPath(), applyNodeInfo);
? ? ? ? ? ? ? ? ? ? return applyNodeInfo.getWorkerId();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? throw new RegException("max worker num reached. register failed");
? ? } catch (RegException e) {
? ? ? ? throw e;
? ? } catch (Exception e) {
? ? ? ? logger.error("", e);
? ? ? ? throw new IllegalStateException(e.getMessage(), e);
? ? } finally {
? ? ? ? try {
? ? ? ? ? ? if (lock != null) {
? ? ? ? ? ? ? ? lock.release();
? ? ? ? ? ? }
? ? ? ? } catch (Exception ignored) {
? ? ? ? ? ? logger.error("", ignored);
? ? ? ? }
? ? }
}

五、idworker缺點(diǎn)

idworker向zookeeper注冊(cè)workerId,返回workerId后,會(huì)在本地緩存workerId,這樣就會(huì)導(dǎo)致如果同一臺(tái)機(jī)器部署了多個(gè)應(yīng)用,那么多個(gè)應(yīng)用會(huì)共享同一個(gè)本地緩存,所以仍有可能造成id重復(fù)。

到此這篇關(guān)于MybatisPlus使用idworker解決雪花算法重復(fù)的文章就介紹到這了,更多相關(guān)MybatisPlus dworker雪花算法重復(fù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

邯郸市| 泾阳县| 施秉县| 吕梁市| 皮山县| 漳州市| 广水市| 湛江市| 绵阳市| 安龙县| 茶陵县| 南华县| 当阳市| 林州市| 青田县| 荥阳市| 曲沃县| 白银市| 建湖县| 阳山县| 逊克县| 兴和县| 疏附县| 南汇区| 元朗区| 延庆县| 大渡口区| 合阳县| 封丘县| 成安县| 衡阳县| 辽阳县| 彭州市| 丰台区| 乡城县| 霍邱县| 武宣县| 阿鲁科尔沁旗| 崇左市| 财经| 沾化县|