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

PowerJob的IdGenerateService工作流程源碼解讀

 更新時間:2024年01月12日 09:24:07   作者:codecraft  
這篇文章主要為大家介紹了PowerJob的IdGenerateService工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

本文主要研究一下PowerJob的IdGenerateService

IdGenerateService

tech/powerjob/server/core/uid/IdGenerateService.java

@Slf4j
@Service
public class IdGenerateService {
    private final SnowFlakeIdGenerator snowFlakeIdGenerator;
    private static final int DATA_CENTER_ID = 0;
    public IdGenerateService(ServerInfoService serverInfoService) {
        long id = serverInfoService.fetchServiceInfo().getId();
        snowFlakeIdGenerator = new SnowFlakeIdGenerator(DATA_CENTER_ID, id);
        log.info("[IdGenerateService] initialize IdGenerateService successfully, ID:{}", id);
    }
    /**
     * 分配分布式唯一ID
     * @return 分布式唯一ID
     */
    public long allocate() {
        return snowFlakeIdGenerator.nextId();
    }
}
IdGenerateService的構(gòu)造器接收ServerInfoService,然后通過serverInfoService.fetchServiceInfo().getId()獲取machineId,最后創(chuàng)建SnowFlakeIdGenerator,其DATA_CENTER_ID為0;其allocate返回的是snowFlakeIdGenerator.nextId()

ServerInfoService

tech/powerjob/server/remote/server/self/ServerInfoService.java

public interface ServerInfoService {
    /**
     * fetch current server info
     * @return ServerInfo
     */
    ServerInfo fetchServiceInfo();
}
ServerInfoService定義了fetchServiceInfo方法,返回ServerInfo

ServerInfoServiceImpl

tech/powerjob/server/remote/server/self/ServerInfoServiceImpl.java

@Slf4j
@Service
public class ServerInfoServiceImpl implements ServerInfoService {
    private final ServerInfo serverInfo;
    private final ServerInfoRepository serverInfoRepository;
    private static final long MAX_SERVER_CLUSTER_SIZE = 10000;
    private static final String SERVER_INIT_LOCK = "server_init_lock";
    private static final int SERVER_INIT_LOCK_MAX_TIME = 15000;
    @Autowired
    public ServerInfoServiceImpl(LockService lockService, ServerInfoRepository serverInfoRepository) {
        this.serverInfo = new ServerInfo();
        String ip = NetUtils.getLocalHost();
        serverInfo.setIp(ip);
        serverInfo.setBornTime(System.currentTimeMillis());
        this.serverInfoRepository = serverInfoRepository;
        Stopwatch sw = Stopwatch.createStarted();
        while (!lockService.tryLock(SERVER_INIT_LOCK, SERVER_INIT_LOCK_MAX_TIME)) {
            log.info("[ServerInfoService] waiting for lock: {}", SERVER_INIT_LOCK);
            CommonUtils.easySleep(100);
        }
        try {
            // register server then get server_id
            ServerInfoDO server = serverInfoRepository.findByIp(ip);
            if (server == null) {
                ServerInfoDO newServerInfo = new ServerInfoDO(ip);
                server = serverInfoRepository.saveAndFlush(newServerInfo);
            } else {
                serverInfoRepository.updateGmtModifiedByIp(ip, new Date());
            }
            if (server.getId() < MAX_SERVER_CLUSTER_SIZE) {
                serverInfo.setId(server.getId());
            } else {
                long retryServerId = retryServerId();
                serverInfo.setId(retryServerId);
                serverInfoRepository.updateIdByIp(retryServerId, ip);
            }
        } catch (Exception e) {
            log.error("[ServerInfoService] init server failed", e);
            throw e;
        } finally {
            lockService.unlock(SERVER_INIT_LOCK);
        }
        log.info("[ServerInfoService] ip:{}, id:{}, cost:{}", ip, serverInfo.getId(), sw);
    }
    @Scheduled(fixedRate = 15000, initialDelay = 15000)
    public void heartbeat() {
        serverInfoRepository.updateGmtModifiedByIp(serverInfo.getIp(), new Date());
    }
    private long retryServerId() {
        List<ServerInfoDO> serverInfoList = serverInfoRepository.findAll();
        log.info("[ServerInfoService] current server record num in database: {}", serverInfoList.size());
        // clean inactive server record first
        if (serverInfoList.size() > MAX_SERVER_CLUSTER_SIZE) {
            // use a large time interval to prevent valid records from being deleted when the local time is inaccurate
            Date oneDayAgo = DateUtils.addDays(new Date(), -1);
            int delNum =serverInfoRepository.deleteByGmtModifiedBefore(oneDayAgo);
            log.warn("[ServerInfoService] delete invalid {} server info record before {}", delNum, oneDayAgo);
            serverInfoList = serverInfoRepository.findAll();
        }
        if (serverInfoList.size() > MAX_SERVER_CLUSTER_SIZE) {
            throw new PowerJobException(String.format("The powerjob-server cluster cannot accommodate %d machines, please rebuild another cluster", serverInfoList.size()));
        }
        Set<Long> uedServerIds = serverInfoList.stream().map(ServerInfoDO::getId).collect(Collectors.toSet());
        for (long i = 1; i <= MAX_SERVER_CLUSTER_SIZE; i++) {
            if (uedServerIds.contains(i)) {
                continue;
            }
            log.info("[ServerInfoService] ID[{}] is not used yet, try as new server id", i);
            return i;
        }
        throw new PowerJobException("impossible");
    }
    @Autowired(required = false)
    public void setBuildProperties(BuildProperties buildProperties) {
        if (buildProperties == null) {
            return;
        }
        String pomVersion = buildProperties.getVersion();
        if (StringUtils.isNotBlank(pomVersion)) {
            serverInfo.setVersion(pomVersion);
        }
    }
    @Override
    public ServerInfo fetchServiceInfo() {
        return serverInfo;
    }
}
ServerInfoServiceImpl實現(xiàn)了ServerInfoService接口,其構(gòu)造器注入lockService和serverInfoRepository,先通過lockService.tryLock搶到server_init_lock,然后serverInfoRepository.findByIp找到ServerInfoDO執(zhí)行saveAndFlush或者updateGmtModifiedByIp;其fetchServiceInfo返回的是serverInfo信息;它還以fixedRate為15s調(diào)度了heartbeat,主要是更新gmtModifed

SnowFlakeIdGenerator

tech/powerjob/server/core/uid/SnowFlakeIdGenerator.java

public class SnowFlakeIdGenerator {
    /**
     * 起始的時間戳(a special day for me)
     */
    private final static long START_STAMP = 1555776000000L;
    /**
     * 序列號占用的位數(shù)
     */
    private final static long SEQUENCE_BIT = 6;
    /**
     * 機器標(biāo)識占用的位數(shù)
     */
    private final static long MACHINE_BIT = 14;
    /**
     * 數(shù)據(jù)中心占用的位數(shù)
     */
    private final static long DATA_CENTER_BIT = 2;
    /**
     * 每一部分的最大值
     */
    private final static long MAX_DATA_CENTER_NUM = ~(-1L << DATA_CENTER_BIT);
    private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
    /**
     * 每一部分向左的位移
     */
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;
    /**
     * 數(shù)據(jù)中心
     */
    private final long dataCenterId;
    /**
     * 機器標(biāo)識
     */
    private final long machineId;
    /**
     * 序列號
     */
    private long sequence = 0L;
    /**
     * 上一次時間戳
     */
    private long lastTimestamp = -1L;

    public SnowFlakeIdGenerator(long dataCenterId, long machineId) {
        if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
            throw new IllegalArgumentException("dataCenterId can't be greater than MAX_DATA_CENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.dataCenterId = dataCenterId;
        this.machineId = machineId;
    }

    /**
     * 產(chǎn)生下一個ID
     */
    public synchronized long nextId() {
        long currStamp = getNewStamp();
        if (currStamp < lastTimestamp) {
            return futureId();
        }

        if (currStamp == lastTimestamp) {
            //相同毫秒內(nèi),序列號自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列數(shù)已經(jīng)達(dá)到最大
            if (sequence == 0L) {
                currStamp = getNextMill();
            }
        } else {
            //不同毫秒內(nèi),序列號置為0
            sequence = 0L;
        }

        lastTimestamp = currStamp;

        return (currStamp - START_STAMP) << TIMESTAMP_LEFT //時間戳部分
                | dataCenterId << DATA_CENTER_LEFT       //數(shù)據(jù)中心部分
                | machineId << MACHINE_LEFT             //機器標(biāo)識部分
                | sequence;                             //序列號部分
    }

    /**
     * 發(fā)生時鐘回?fù)軙r借用未來時間生成Id,避免運行過程中任務(wù)調(diào)度和工作流直接進入不可用狀態(tài)
     * 注:該方式不可解決原算法中停服狀態(tài)下時鐘回?fù)軐?dǎo)致的重復(fù)id問題
     */
    private long futureId() {
        sequence = (sequence + 1) & MAX_SEQUENCE;
        if (sequence == 0L) {
            lastTimestamp = lastTimestamp + 1;
        }

        return (lastTimestamp - START_STAMP) << TIMESTAMP_LEFT //時間戳部分
                | dataCenterId << DATA_CENTER_LEFT       //數(shù)據(jù)中心部分
                | machineId << MACHINE_LEFT             //機器標(biāo)識部分
                | sequence;                             //序列號部分
    }

    private long getNextMill() {
        long mill = getNewStamp();
        while (mill <= lastTimestamp) {
            mill = getNewStamp();
        }
        return mill;
    }

    private long getNewStamp() {
        return System.currentTimeMillis();
    }
}
SnowFlakeIdGenerator的dataCenterId(最大值為3)和machineId(最大值為16383),sequence最大值為63

小結(jié)

PowerJob的IdGenerateService通過serverInfoService.fetchServiceInfo().getId()獲取machineId,最后創(chuàng)建SnowFlakeIdGenerator,其DATA_CENTER_ID為0;其allocate返回的是snowFlakeIdGenerator.nextId();其InstanceInfoDO的instanceId就是idGenerateService.allocate()生成的。

以上就是PowerJob的IdGenerateService工作流程源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于PowerJob IdGenerateService的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 為什么mybatis中的SqlSession一定要關(guān)閉

    為什么mybatis中的SqlSession一定要關(guān)閉

    這篇文章主要介紹了為什么mybatis中的SqlSession一定要關(guān)閉,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringBoot項目啟動時提示程序包不存在和找不到符號的處理方法

    SpringBoot項目啟動時提示程序包不存在和找不到符號的處理方法

    最近接手同事開發(fā)的一個Springboot工作項目,從svn上整體拉取下來后,構(gòu)建完成后,啟動的時候遇到了程序包找不到的情況,所以本文記錄了SpringBoot項目啟動時提示程序包不存在和找不到符號的處理方法,需要的朋友可以參考下
    2024-05-05
  • Java 鏈表的定義與簡單實例

    Java 鏈表的定義與簡單實例

    這篇文章主要介紹了 Java 鏈表的定義與簡單實例的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • SpringBoot同時集成Mybatis和Mybatis-plus框架

    SpringBoot同時集成Mybatis和Mybatis-plus框架

    在實際開發(fā)中,項目里面一般都是Mybatis和Mybatis-Plus公用,但是公用有版本不兼容的問題,本文主要介紹了Spring Boot項目中同時集成Mybatis和Mybatis-plus,具有一檔的參考價值,感興趣的可以了解一下
    2024-12-12
  • java+testng+selenium的自動化測試實例

    java+testng+selenium的自動化測試實例

    這篇文章主要介紹了java+testng+selenium的自動化測試實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 解決Spring中@Value注解取值為null問題

    解決Spring中@Value注解取值為null問題

    近期應(yīng)用中因業(yè)務(wù)迭代需要接入 user 客戶端,接入后總是啟動失敗,報注冊 user bean 依賴的配置屬性為 null,所以接下來小編就和大家一起排查分析這個問題,感興趣的小伙伴跟著小編一起來看看吧
    2023-08-08
  • Java基礎(chǔ)-Java常量和常量值

    Java基礎(chǔ)-Java常量和常量值

    這篇文章主要介紹了Java基礎(chǔ)-Java常量和常量值,在程序中存在大量的數(shù)據(jù)來代表程序的狀態(tài),其中有些數(shù)據(jù)在程序運行過程中值不能發(fā)生改變,這些數(shù)據(jù)在程序中被叫做常量,下面文章對Java常量和常量值的詳細(xì)內(nèi)容,需要的小伙伴可以參考一下
    2022-01-01
  • 如何利用Spring的@Import擴展點與spring進行無縫整合

    如何利用Spring的@Import擴展點與spring進行無縫整合

    這篇文章主要介紹了如何利用Spring的@Import擴展點與spring進行無縫整合的實例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Java面試題沖刺第九天--MyBatis

    Java面試題沖刺第九天--MyBatis

    這篇文章主要為大家分享了最有價值的三道MyBatis框架面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java 重連機制的幾種實現(xiàn)方法

    Java 重連機制的幾種實現(xiàn)方法

    本文主要介紹了Java 重連機制的幾種實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-02-02

最新評論

大连市| 福鼎市| 施秉县| 团风县| 边坝县| 禄劝| 镇巴县| 息烽县| 武平县| 安西县| 勐海县| 勐海县| 叶城县| 奉化市| 读书| 夏邑县| 固镇县| 县级市| 新蔡县| 巫山县| 宿松县| 曲阜市| 曲麻莱县| 梁山县| 昆山市| 紫阳县| 靖江市| 北宁市| 盘锦市| 扶绥县| 简阳市| 长岛县| 鄂托克旗| 阿巴嘎旗| 施甸县| 枞阳县| 临清市| 临西县| 遂平县| 柳州市| 静海县|