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

【分布式技術(shù)專題】「分布式ID系列」百度開源的分布式高性能的唯一ID生成器UidGenerator

這篇具有很好參考價(jià)值的文章主要介紹了【分布式技術(shù)專題】「分布式ID系列」百度開源的分布式高性能的唯一ID生成器UidGenerator。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

UidGenerator是什么

UidGenerator是百度開源的一款分布式高性能的唯一ID生成器,更詳細(xì)的情況可以查看官網(wǎng)集成文檔

uid-generator是基于Twitter開源的snowflake算法實(shí)現(xiàn)的一款唯一主鍵生成器(數(shù)據(jù)庫表的主鍵要求全局唯一是相當(dāng)重要的)。要求java8及以上版本。

snowflake算法

Snowflake算法描述:指定機(jī)器 & 同一時(shí)刻 & 某一并發(fā)序列,是唯一的。據(jù)此可生成一個(gè)64 bits的唯一ID(long)。

將long的64位分為3部分,時(shí)間戳、工作機(jī)器id和序列號,位數(shù)分配如下:

百度uidgenerator,分布式&微服務(wù)技術(shù)體系,分布式,開源

時(shí)間戳部分的時(shí)間單位一般為毫秒,也就是說1臺工作機(jī)器1毫秒可產(chǎn)生4096個(gè)id(2的12次方)。

UidGenerator算法

與原始的snowflake算法不同,uid-generator支持自定義時(shí)間戳、工作機(jī)器id和序列號等各部分的位數(shù),以應(yīng)用于不同場景。

百度uidgenerator,分布式&微服務(wù)技術(shù)體系,分布式,開源

  • sign(1bit):固定1bit符號標(biāo)識,即生成的UID為正數(shù)。
  • delta seconds (28 bits):當(dāng)前時(shí)間,相對于時(shí)間基點(diǎn)"2016-05-20"的增量值,單位:秒,最多可支持約8.7年
  • worker id (22 bits):機(jī)器id,最多可支持約420w次機(jī)器啟動(dòng)。內(nèi)置實(shí)現(xiàn)為在啟動(dòng)時(shí)由數(shù)據(jù)庫分配,默認(rèn)分配策略為用后即棄,后續(xù)可提供復(fù)用策略。
  • sequence (13 bits):每秒下的并發(fā)序列,13 bits可支持每秒8192個(gè)并發(fā)。

這些字段的長度可以根據(jù)具體的應(yīng)用需要進(jìn)行動(dòng)態(tài)的調(diào)整,滿足總長度為64位即可。

Snowflake和UidGenerator的對比

百度的worker id的生成策略和美團(tuán)的生成策略不太一樣,美團(tuán)的snowflake主要利用本地配置的port和IP來唯一確定一個(gè)workid,美團(tuán)的這種生成方式還是可以由于手工配置錯(cuò)誤造成port重復(fù),最終產(chǎn)生重復(fù)ID的風(fēng)險(xiǎn),百度的這種生成方式每次都是新增的,可能會(huì)一段時(shí)間后worker id用完的情況,人工配置錯(cuò)誤的可能性很小了。

源碼分析

DefaultUidGenerator

DefaultUidGenerator的產(chǎn)生id的方法與基本上就是常見的snowflake算法實(shí)現(xiàn),僅有一些不同,如以秒為為單位而不是毫秒。DefaultUidGenerator的產(chǎn)生id的方法如下。

 protected synchronized long nextId() {
        long currentSecond = getCurrentSecond();

        if (currentSecond < lastSecond) {
            long refusedSeconds = lastSecond - currentSecond;
            throw new UidGenerateException("Clock moved backwards. Refusing for %d seconds", refusedSeconds);
        }

        if (currentSecond == lastSecond) {
            sequence = (sequence + 1) & bitsAllocator.getMaxSequence();

            if (sequence == 0) {
                currentSecond = getNextSecond(lastSecond);
            }

        } else {
            sequence = 0L;
        }
        lastSecond = currentSecond;

        return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, sequence);
    }

nextId方法主要負(fù)責(zé)ID的生成,這種實(shí)現(xiàn)方式很簡單,如果毫秒數(shù)未發(fā)生變化,在序列號加一即可,毫秒數(shù)發(fā)生變化,重置Sequence為0(Leaf文章中講過,重置為0會(huì)造成如果利用這個(gè)ID分表的時(shí)候,并發(fā)量不大的時(shí)候,sequence字段會(huì)一直為0等,會(huì)出現(xiàn)數(shù)據(jù)傾斜)

CachedUidGenerator

CachedUidGenerator支持緩存生成的id。

  • 【采用RingBuffer來緩存已生成的UID, 并行化UID的生產(chǎn)和消費(fèi)】
  • 【UidGenerator通過借用未來時(shí)間來解決sequence天然存在的并發(fā)限制】
基本實(shí)現(xiàn)原理

正如名字體現(xiàn)的那樣,這是一種緩存型的ID生成方式,當(dāng)剩余ID不足的時(shí)候,會(huì)異步的方式重新生成一批ID緩存起來,后續(xù)請求的時(shí)候直接的時(shí)候直接返回現(xiàn)成的ID即可。

在實(shí)現(xiàn)上, UidGenerator通過借用未來時(shí)間來解決sequence天然存在的并發(fā)限制; 采用RingBuffer來緩存已生成的UID, 并行化UID的生產(chǎn)和消費(fèi), 同時(shí)對CacheLine補(bǔ)齊,避免了由RingBuffer帶來的硬件級「偽共享」問題. 最終單機(jī)QPS可達(dá)600萬。

使用RingBuffer緩存生成的id。RingBuffer是個(gè)環(huán)形數(shù)組,默認(rèn)大小為8192個(gè),里面緩存著生成的id。

CachedUidGenerator采用了雙RingBuffer,Uid-RingBuffer用于存儲Uid、Flag-RingBuffer用于存儲Uid狀態(tài)(是否可填充、是否可消費(fèi))

由于數(shù)組元素在內(nèi)存中是連續(xù)分配的,可最大程度利用CPU cache以提升性能。但同時(shí)會(huì)帶來「偽共享」FalseSharing問題,為此在Tail、Cursor指針、Flag-RingBuffer中采用了CacheLine 補(bǔ)齊方式。

獲取id

會(huì)從ringbuffer中拿一個(gè)id,支持并發(fā)獲取


    public long getUID() {
        try {
            return ringBuffer.take();
        } catch (Exception e) {
            LOGGER.error("Generate unique id exception. ", e);
            throw new UidGenerateException(e);
        }
    }
RingBuffer緩存已生成的id

RingBuffer為環(huán)形數(shù)組,默認(rèn)容量為sequence可容納的最大值(8192個(gè)),可以通過boostPower參數(shù)設(shè)置大小。幾個(gè)重要的數(shù)據(jù)結(jié)構(gòu),采用了RingBuffer的方式來緩存相關(guān)UID信息。

tail指針、Cursor指針用于環(huán)形數(shù)組上讀寫slot:

Tail指針

指向當(dāng)前最后一個(gè)可用的UID位置:表示Producer生產(chǎn)的最大序號(此序號從0開始,持續(xù)遞增)。Tail不能超過Cursor,即生產(chǎn)者不能覆蓋未消費(fèi)的slot。當(dāng)Tail已趕上curosr,此時(shí)可通過rejectedPutBufferHandler指定PutRejectPolicy

Cursor指針

指向下一個(gè)獲取UID的位置,其一定是小于Tail:表示Consumer消費(fèi)到的最小序號(序號序列與Producer序列相同)。Cursor不能超過Tail,即不能消費(fèi)未生產(chǎn)的slot。當(dāng)Cursor已趕上tail,此時(shí)可通過rejectedTakeBufferHandler指定TakeRejectPolicy

Tail - Cursor表示的是現(xiàn)在可用的UID數(shù)量,當(dāng)可用UID數(shù)量小于一定閾值的時(shí)候會(huì)重新添加一批新的UID在RingBuffer中。

百度uidgenerator,分布式&amp;微服務(wù)技術(shù)體系,分布式,開源

填充id
  • RingBuffer填充時(shí)機(jī)
    • 程序啟動(dòng)時(shí),將RingBuffer填充滿,緩存著8192個(gè)id
    • 在調(diào)用getUID()獲取id時(shí),檢測到RingBuffer中的剩余id個(gè)數(shù)小于總個(gè)數(shù)的50%,將RingBuffer填充滿,使其緩存8192個(gè)id。
    • 定時(shí)填充(可配置是否使用以及定時(shí)任務(wù)的周期)

因?yàn)閐elta seconds部分是以秒為單位的,所以1個(gè)worker 1秒內(nèi)最多生成的id書為8192個(gè)(2的13次方)。從上可知,支持的最大qps為8192,所以通過緩存id來提高吞吐量。

為什么叫借助未來時(shí)間?

因?yàn)槊棵胱疃嗌?192個(gè)id,當(dāng)1秒獲取id數(shù)多于8192時(shí),RingBuffer中的id很快消耗完畢,在填充RingBuffer時(shí),生成的id的delta seconds 部分只能使用未來的時(shí)間。(因?yàn)槭褂昧宋磥淼臅r(shí)間來生成id,所以上面說的是,【最多】可支持約8.7年)

注意:這里的RingBuffer不是Disruptor框架中的RingBuffer,但是借助了很多Disruptor中RingBuffer的設(shè)計(jì)思想,比如使用緩存行填充解決偽共享問題。

填充RingBuffer

    public void paddingBuffer() {
        LOGGER.info("Ready to padding buffer lastSecond:{}. {}", lastSecond.get(), ringBuffer);

        if (!running.compareAndSet(false, true)) {
            LOGGER.info("Padding buffer is still running. {}", ringBuffer);
            return;
        }

        boolean isFullRingBuffer = false;
        while (!isFullRingBuffer) {

            List uidList = uidProvider.provide(lastSecond.incrementAndGet());
            for (Long uid : uidList) {
                isFullRingBuffer = !ringBuffer.put(uid);
                if (isFullRingBuffer) {
                    break;
                }
            }
        }

        running.compareAndSet(true, false);
        LOGGER.info("End to padding buffer lastSecond:{}. {}", lastSecond.get(), ringBuffer);
    }

生成id(上面代碼中的uidProvider.provide調(diào)用的就是這個(gè)方法)


    protected List nextIdsForOneSecond(long currentSecond) {

        int listSize = (int) bitsAllocator.getMaxSequence() + 1;
        List uidList = new ArrayList<>(listSize);

        long firstSeqUid = bitsAllocator.allocate(currentSecond - epochSeconds, workerId, 0L);
        for (int offset = 0; offset < listSize; offset++) {
            uidList.add(firstSeqUid + offset);
        }

        return uidList;
    }
RingBuffer的代碼
public class RingBuffer {
    private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class);

    private static final int START_POINT = -1;
    private static final long CAN_PUT_FLAG = 0L;
    private static final long CAN_TAKE_FLAG = 1L;
    public static final int DEFAULT_PADDING_PERCENT = 50;

    private final int bufferSize;
    private final long indexMask;

    private final long[] slots;
    private final PaddedAtomicLong[] flags;

    private final AtomicLong tail = new PaddedAtomicLong(START_POINT);

    private final AtomicLong cursor = new PaddedAtomicLong(START_POINT);

    private final int paddingThreshold;

    private RejectedPutBufferHandler rejectedPutHandler = this::discardPutBuffer;

    private RejectedTakeBufferHandler rejectedTakeHandler = this::exceptionRejectedTakeBuffer;

    private BufferPaddingExecutor bufferPaddingExecutor;
代碼層面的優(yōu)化

代碼中通過字節(jié)的填充,來避免偽共享的產(chǎn)生。

多核處理器處理相互獨(dú)立的變量時(shí),一旦這些變量處于同一個(gè)緩存行,不同變量的操作均會(huì)造成這一個(gè)緩存行失效,影響緩存的實(shí)際效果,造成很大的緩存失效的性能問題。下面圖中線程處理不同的兩個(gè)變量,但這兩個(gè)變量的修改都會(huì)造成整個(gè)整個(gè)緩存行的失效,導(dǎo)致無效的加載、失效,出現(xiàn)了偽共享的問題

RingBuffer中通過定義一個(gè)PaddedAtomicLong來獨(dú)占一個(gè)緩存行,代碼中的實(shí)現(xiàn)填充可能需要根據(jù)具體的執(zhí)行系統(tǒng)做一些調(diào)整,保證其獨(dú)占一個(gè)緩存行即可。

take先關(guān)id的源碼

下面我們來看下如何獲取相關(guān)的UID

public long take() {

        long currentCursor = cursor.get();
        long nextCursor = cursor.updateAndGet(old -> old == tail.get() ? old : old + 1);

        Assert.isTrue(nextCursor >= currentCursor, "Curosr can't move back");

        long currentTail = tail.get();
        if (currentTail - nextCursor < paddingThreshold) {
            LOGGER.info("Reach the padding threshold:{}. tail:{}, cursor:{}, rest:{}", paddingThreshold, currentTail,
                    nextCursor, currentTail - nextCursor);
            bufferPaddingExecutor.asyncPadding();
        }

        if (nextCursor == currentCursor) {
            rejectedTakeHandler.rejectTakeBuffer(this);
        }

        int nextCursorIndex = calSlotIndex(nextCursor);
        Assert.isTrue(flags[nextCursorIndex].get() == CAN_TAKE_FLAG, "Curosr not in can take status");

        long uid = slots[nextCursorIndex];
        flags[nextCursorIndex].set(CAN_PUT_FLAG);

        return uid;
    }

通過AtomicLong.updateAndGet來避免對整個(gè)方法進(jìn)行加鎖,獲取一個(gè)可以訪問的UID的游標(biāo)值,根據(jù)這個(gè)下標(biāo)獲取slots中相關(guān)的uid直接返回 緩存中可用的uid(Tail - Cursor)小于一定閾值的時(shí)候,需要啟動(dòng)另外一個(gè)線程來生成一批UID UID 的生成

public synchronized boolean put(long uid) { long currentTail = tail.get(); long currentCursor = cursor.get();


    long distance = currentTail - (currentCursor == START_POINT ? 0 : currentCursor);
    if (distance == bufferSize - 1) {
        rejectedPutHandler.rejectPutBuffer(this, uid);
        return false;
    }

    int nextTailIndex = calSlotIndex(currentTail + 1);
    if (flags[nextTailIndex].get() != CAN_PUT_FLAG) {
        rejectedPutHandler.rejectPutBuffer(this, uid);
        return false;
    }

    slots[nextTailIndex] = uid;
    flags[nextTailIndex].set(CAN_TAKE_FLAG);
    tail.incrementAndGet();

    return true;
}

獲取Tail的下標(biāo)值,如果緩存區(qū)滿的話直接調(diào)用RejectedPutHandler.rejectPutBuffer方法 未滿的話將UID放置在slots數(shù)組相應(yīng)的位置上,同時(shí)將Flags數(shù)組相應(yīng)的位置改為CAN_TAKE_FLAG CachedUidGenerator通過緩存的方式預(yù)先生成一批UID列表,可以解決UID獲取時(shí)候的耗時(shí),但這種方式也有不好點(diǎn),一方面需要耗費(fèi)內(nèi)存來緩存這部分?jǐn)?shù)據(jù),另外如果訪問量不大的情況下,提前生成的UID中的時(shí)間戳可能是很早之前的,DefaultUidGenerator應(yīng)該在大部分的場景中就可以滿足相關(guān)的需求了。

填充緩存行解決"偽共享"

關(guān)于偽共享,可以參考這篇文章《偽共享(false sharing),并發(fā)編程無聲的性能殺手》


    private final PaddedAtomicLong[] flags;

    private final AtomicLong tail = new PaddedAtomicLong(START_POINT);

    private final AtomicLong cursor = new PaddedAtomicLong(START_POINT)
PaddedAtomicLong的設(shè)計(jì)

public class PaddedAtomicLong extends AtomicLong {
    private static final long serialVersionUID = -3415778863941386253L;

    public volatile long p1, p2, p3, p4, p5, p6 = 7L;

    public PaddedAtomicLong() {
        super();
    }

    public PaddedAtomicLong(long initialValue) {
        super(initialValue);
    }

    public long sumPaddingToPreventOptimization() {
        return p1 + p2 + p3 + p4 + p5 + p6;
    }

}

Spring Boot工程集成全局唯一ID生成器 UidGenerator

基礎(chǔ)工程創(chuàng)建

官網(wǎng)集成文檔

創(chuàng)建數(shù)據(jù)表

執(zhí)行如下SQL

DROP TABLE IF EXISTS WORKER_NODE;
CREATE TABLE WORKER_NODE
(
ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
PORT VARCHAR(64) NOT NULL COMMENT 'port',
TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',
LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',
CREATED TIMESTAMP NOT NULL COMMENT 'created time',
PRIMARY KEY(ID)
)
 COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;

在使用的數(shù)據(jù)庫中創(chuàng)建表WORKER_NODE。(如果數(shù)據(jù)庫版本較低,需要將TIMESTAMP類型換成datetime(3),一勞永逸的做法就是直接將TIMESTAMP換成datetime(3))

引入Maven依賴
<dependencies>
	<dependency>
		<groupId>org.springframework.bootgroupId>
		<artifactId>spring-boot-starter-webartifactId>
	dependency>
	<dependency>
		<groupId>org.mybatis.spring.bootgroupId>
		<artifactId>mybatis-spring-boot-starterartifactId>
		<version>2.1.0version>
	dependency>
	<dependency>
		<groupId>org.springframework.bootgroupId>
		<artifactId>spring-boot-starter-testartifactId>
		<scope>testscope>
	dependency>

	<dependency>
		<groupId>mysqlgroupId>
		<artifactId>mysql-connector-javaartifactId>
		<scope>runtimescope>
		<version>8.0.12version>
	dependency>

	<dependency>
		<groupId>com.alibabagroupId>
		<artifactId>druid-spring-boot-starterartifactId>
		<version>1.1.9version>
	dependency>

	<dependency>
		<groupId>com.baidu.fsggroupId>
		<artifactId>uid-generatorartifactId>
		<version>1.0.0-SNAPSHOTversion>
	dependency>
dependencies>

互聯(lián)網(wǎng)jar包引入(本文用的是此方式)

在maven倉庫只找到了一個(gè)jar包。

<dependency>
    <groupId>com.xfvape.uidgroupId>
    <artifactId>uid-generatorartifactId>
    <version>0.0.4-RELEASEversion>
dependency>
排除沖突的依賴

uid-generator中依賴了logback和mybatis。一般在項(xiàng)目搭建過程中,springboot中已經(jīng)有了logback依賴,mybatis會(huì)作為單獨(dú)的依賴引入。如果版本和uid-generator中的依賴不一致的話,就會(huì)導(dǎo)致沖突。為了防止出現(xiàn)這些問題,直接排除一勞永逸。

<dependency>
    <groupId>com.baidu.fsggroupId>
    <artifactId>uid-generatorartifactId>
    <version>1.0.0-SNAPSHOTversion>
    <exclusions>
        <exclusion>
            <groupId>org.mybatisgroupId>
            <artifactId>*artifactId>
        exclusion>
    exclusions>
dependency>

排除沖突的依賴如下:(使用本地項(xiàng)目引入的方式也需要排除以下依賴)

<dependency>
    <groupId>com.xfvape.uidgroupId>
    <artifactId>uid-generatorartifactId>
    <version>0.0.4-RELEASEversion>
    <exclusions>
        <exclusion>
            <groupId>org.mybatisgroupId>
            <artifactId>*artifactId>
        exclusion>
    exclusions>
dependency>

我這里用的是mybatis-plus,mybatis-plus官方要求的是,如果要使用mybatis-plus,就不能再單獨(dú)引入mybatis了,所以我這里也是必須排除mybatis的。

配置SpringBoot核心配置

修改配置文件application.properties(注意MySQL地址、數(shù)據(jù)庫名稱賬戶等于之前建表的保持一致)

server.port=9999
spring.datasource.url=jdbc:mysql://*.*.*.*:3306/baiduUidGenerator?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=*
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
@MapperScan的dao層接口掃描:
核心對象裝配為spring的bean。

uid-generator提供了兩種生成器: DefaultUidGenerator、CachedUidGenerator。

如對UID生成性能有要求, 請使用CachedUidGenerator。這里裝配CachedUidGenerator,DefaultUidGenerator裝配方式是一樣的。

自定義DisposableWorkerIdAssigner

將源碼DisposableWorkerIdAssigner類加入到自己的項(xiàng)目中,并將其中的mapper方法修改成自己項(xiàng)目中的方法與啟動(dòng)類同級目錄新建DisposableWorkerIdAssigner內(nèi)容如下


public class DisposableWorkerIdAssigner implements WorkerIdAssigner {
    private static final Logger LOGGER = LoggerFactory.getLogger(DisposableWorkerIdAssigner.class);

    private WorkerNodeMapper workerNodeMapper;

    public long assignWorkerId() {

        WorkerNodeEntity workerNodeEntity = buildWorkerNode();

        workerNodeMapper.addWorkerNode(workerNodeEntity);
        LOGGER.info("Add worker node:" + workerNodeEntity);

        return workerNodeEntity.getId();
    }

    private WorkerNodeEntity buildWorkerNode() {
        WorkerNodeEntity workerNodeEntity = new WorkerNodeEntity();
        if (DockerUtils.isDocker()) {
            workerNodeEntity.setType(WorkerNodeType.CONTAINER.value());
            workerNodeEntity.setHostName(DockerUtils.getDockerHost());
            workerNodeEntity.setPort(DockerUtils.getDockerPort());
        } else {
            workerNodeEntity.setType(WorkerNodeType.ACTUAL.value());
            workerNodeEntity.setHostName(NetUtils.getLocalAddress());
            workerNodeEntity.setPort(System.currentTimeMillis() + "-" + RandomUtils.nextInt(100000));
        }
        return workerNodeEntity;
    }
}

public class UidGeneratorConfig {

public DisposableWorkerIdAssigner disposableWorkerIdAssigner(){
	DisposableWorkerIdAssigner disposableWorkerIdAssigner = new DisposableWorkerIdAssigner();
	return  disposableWorkerIdAssigner;
}

	public CachedUidGenerator initCachedUidGenerator(WorkerIdAssigner workerIdAssigner) {
		CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
		cachedUidGenerator.setWorkerIdAssigner(workerIdAssigner);

		cachedUidGenerator.setBoostPower(3);
		cachedUidGenerator.setPaddingFactor(50);
		cachedUidGenerator.setScheduleInterval(60L);

		return cachedUidGenerator;
	}
}
詳細(xì)配置信息控制

    public DefaultUidGenerator defaultUidGenerator(WorkerIdAssigner disposableWorkerIdAssigner) {
        DefaultUidGenerator defaultUidGenerator = new DefaultUidGenerator();
     defaultUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner);

        defaultUidGenerator.setTimeBits(32);

        defaultUidGenerator.setWorkerBits(22);

        defaultUidGenerator.setSeqBits(9);
        defaultUidGenerator.setEpochStr("2020-01-01");

        return defaultUidGenerator;
    }

    public CachedUidGenerator cachedUidGenerator(WorkerIdAssigner disposableWorkerIdAssigner) {
        CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
        cachedUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner);

        cachedUidGenerator.setTimeBits(32);

        cachedUidGenerator.setWorkerBits(22);

        cachedUidGenerator.setSeqBits(9);
        cachedUidGenerator.setEpochStr("2020-01-01");

        cachedUidGenerator.setBoostPower(3);

        cachedUidGenerator.setScheduleInterval(60L);

        return cachedUidGenerator;
    }
mapper服務(wù)接口

與啟動(dòng)類同級目錄新建WorkerNodeMapper內(nèi)容如下


public interface WorkerNodeMapper {

    WorkerNodeEntity getWorkerNodeByHostPort( String host,  String port);

    void addWorkerNode(WorkerNodeEntity workerNodeEntity);
}
WorkerNodeMapper

<mapper namespace="org.zxp.uidgeneratortest.WorkerNodeMapper">
    <resultMap id="workerNodeRes"
               type="com.baidu.fsg.uid.worker.entity.WorkerNodeEntity">
        <id column="ID" jdbcType="BIGINT" property="id"/>
        <result column="HOST_NAME" jdbcType="VARCHAR" property="hostName"/>
        <result column="PORT" jdbcType="VARCHAR" property="port"/>
        <result column="TYPE" jdbcType="INTEGER" property="type"/>
        <result column="LAUNCH_DATE" jdbcType="DATE" property="launchDate"/>
        <result column="MODIFIED" jdbcType="TIMESTAMP" property="modified"/>
        <result column="CREATED" jdbcType="TIMESTAMP" property="created"/>
    resultMap>

    <insert id="addWorkerNode" useGeneratedKeys="true" keyProperty="id"
            parameterType="com.baidu.fsg.uid.worker.entity.WorkerNodeEntity">
		INSERT INTO WORKER_NODE
		(HOST_NAME,
		PORT,
		TYPE,
		LAUNCH_DATE,
		MODIFIED,
		CREATED)
		VALUES (
		#{hostName},
		#{port},
		#{type},
		#{launchDate},
		NOW(),
		NOW())
	insert>

    <select id="getWorkerNodeByHostPort" resultMap="workerNodeRes">
		SELECT
		ID,
		HOST_NAME,
		PORT,
		TYPE,
		LAUNCH_DATE,
		MODIFIED,
		CREATED
		FROM
		WORKER_NODE
		WHERE
		HOST_NAME = #{host} AND PORT = #{port}
	select>
mapper>

創(chuàng)建UidGenService邏輯類

public class UidGenService {

    private UidGenerator uidGenerator;
    public long getUid() {
        return uidGenerator.getUID();
    }
}

分享資源

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-4Yf1KiFl-1692670384862)(https://pic.imgdb.cn/item/64d0dc6a1ddac507cc857b30.png)]
獲取以上資源請?jiān)L問開源項(xiàng)目 點(diǎn)擊跳轉(zhuǎn)文章來源地址http://www.zghlxwxcb.cn/news/detail-762803.html

到了這里,關(guān)于【分布式技術(shù)專題】「分布式ID系列」百度開源的分布式高性能的唯一ID生成器UidGenerator的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • 云事業(yè)群CTO線技術(shù)晉升考核機(jī)試題-分布式專題-B 分布式事務(wù)

    出題人:湖北TL田超凡 注意:本部分機(jī)試題均為 簡答題 ,每題字?jǐn)?shù)不少于50字,采用人工閱卷方式批改 通過標(biāo)準(zhǔn):答對 15 題以上 方可通過本部分測驗(yàn)。 1 什么是事務(wù)?事務(wù)的特性有哪些? 2 分布式事務(wù)產(chǎn)生的背景? 3 簡述CAP定律和BASE理論? 4 2PC和3PC的作用? 5 2PC實(shí)現(xiàn)原理

    2024年02月13日
    瀏覽(20)
  • 【分布式技術(shù)專題】「分布式技術(shù)架構(gòu)」 探索Tomcat技術(shù)架構(gòu)設(shè)計(jì)模式的奧秘(Server和Service組件原理分析)

    【分布式技術(shù)專題】「分布式技術(shù)架構(gòu)」 探索Tomcat技術(shù)架構(gòu)設(shè)計(jì)模式的奧秘(Server和Service組件原理分析)

    Tomcat的總體結(jié)構(gòu)從外到內(nèi)進(jìn)行分布,最大范圍的服務(wù)容器是Server組件,Service服務(wù)組件(可以有多個(gè)同時(shí)存在),Connector(連接器)、Container(容器服務(wù)),其他組件:Jasper(Jasper解析)、Naming(命名服務(wù))、Session(會(huì)話管理)、Logging(日志管理)、JMX(Java 管理器擴(kuò)展服務(wù)

    2024年01月24日
    瀏覽(89)
  • 云事業(yè)群CTO線技術(shù)晉升考核機(jī)試題-分布式專題-D 分布式數(shù)據(jù)同步

    ? 作者:田超凡 1 緩存一致性產(chǎn)生背景 答:當(dāng)需要頻繁訪問數(shù)據(jù)庫的時(shí)候,雖然數(shù)據(jù)庫底層基于B+索引檢索數(shù)據(jù),但是仍然會(huì)十分消耗磁盤IO資源,導(dǎo)致數(shù)據(jù)庫訪問壓力增加。 此時(shí)可以基于緩存設(shè)計(jì)來減輕數(shù)據(jù)庫訪問壓力。 2 多級緩存架構(gòu)設(shè)計(jì)方案 答:多級緩存架構(gòu)設(shè)計(jì)采用

    2024年02月16日
    瀏覽(56)
  • 云事業(yè)群CTO線技術(shù)晉升考核機(jī)試題-分布式專題-C 分布式任務(wù)調(diào)度

    作者:田超凡 1 傳統(tǒng)的定時(shí)任務(wù)存在那些缺點(diǎn) 答:傳統(tǒng)定時(shí)任務(wù)的缺點(diǎn): 定時(shí)任務(wù)邏輯和業(yè)務(wù)邏輯在一個(gè)服務(wù)中,是強(qiáng)耦合的,沒有實(shí)現(xiàn)完全解耦,當(dāng)定時(shí)任務(wù)邏輯出現(xiàn)問題,也會(huì)影響業(yè)務(wù)邏輯的執(zhí)行。 定時(shí)任務(wù)非常消耗cpu資源,可能會(huì)影響業(yè)務(wù)線程的執(zhí)行。 服務(wù)器集群環(huán)

    2024年02月15日
    瀏覽(50)
  • 云事業(yè)群CTO線技術(shù)晉升考核機(jī)試題-分布式專題-F 分布式服務(wù)鏈路動(dòng)態(tài)追蹤

    作者:田超凡 1 分布式服務(wù)鏈路動(dòng)態(tài)追蹤產(chǎn)生的背景 答:在分布式微服務(wù)系統(tǒng)中,隨著業(yè)務(wù)的發(fā)展,系統(tǒng)的規(guī)模也越來越大,服務(wù)和服務(wù)之間的調(diào)用關(guān)系也越來越復(fù)雜。比如一次HTTP請求可能會(huì)在多個(gè)服務(wù)和服務(wù)之間進(jìn)行多次組合調(diào)用,在這個(gè)過程中,當(dāng)一個(gè)服務(wù)出現(xiàn)故障,

    2024年02月16日
    瀏覽(60)
  • 【分布式技術(shù)專題】RocketMQ延遲消息實(shí)現(xiàn)原理和源碼分析

    【分布式技術(shù)專題】RocketMQ延遲消息實(shí)現(xiàn)原理和源碼分析

    痛點(diǎn)背景 業(yè)務(wù)場景 假設(shè)有這么一個(gè)需求,用戶下單后如果30分鐘未支付,則該訂單需要被關(guān)閉。你會(huì)怎么做? 之前方案 最簡單的做法,可以服務(wù)端啟動(dòng)個(gè)定時(shí)器,隔個(gè)幾秒掃描數(shù)據(jù)庫中待支付的訂單,如果(當(dāng)前時(shí)間-訂單創(chuàng)建時(shí)間)30分鐘,則關(guān)閉訂單。 方案評估 優(yōu)點(diǎn):是實(shí)

    2024年02月13日
    瀏覽(24)
  • 云事業(yè)群CTO線技術(shù)晉升考核機(jī)試題-分布式專題-G 分布式冪等架構(gòu)設(shè)計(jì)

    作者:田超凡 1 冪等的基本概念 答:冪等指的是同一塊業(yè)務(wù)邏輯重復(fù)多次執(zhí)行時(shí),只能令其生效一次,防止重復(fù)執(zhí)行。 2 冪等的發(fā)生場景 答: RPC 調(diào)用接口的冪等性問題 MQ 消費(fèi)者防止重復(fù)消費(fèi)的冪等性問題 定時(shí)任務(wù)防止重復(fù)執(zhí)行的冪等性問題 3 RPC調(diào)用接口的冪等性問題產(chǎn)生

    2024年02月16日
    瀏覽(119)
  • 【分布式技術(shù)專題】「單點(diǎn)登錄技術(shù)架構(gòu)」一文帶領(lǐng)你好好認(rèn)識以下Saml協(xié)議的運(yùn)作機(jī)制和流程模式

    【分布式技術(shù)專題】「單點(diǎn)登錄技術(shù)架構(gòu)」一文帶領(lǐng)你好好認(rèn)識以下Saml協(xié)議的運(yùn)作機(jī)制和流程模式

    傳統(tǒng)上,企業(yè)應(yīng)用程序在公司網(wǎng)絡(luò)中部署和運(yùn)行。為了獲取有關(guān)用戶的信息,如用戶配置文件和組信息,這些應(yīng)用程序中的許多都是為與公司目錄(如Microsoft Active Directory)集成而構(gòu)建的。更重要的是,通常使用目錄存儲和驗(yàn)證用戶的憑據(jù)。例如,如果您使用在本地運(yùn)行的Share

    2024年02月05日
    瀏覽(21)
  • 【分布式】分布式ID

    【分布式】分布式ID

    分布式場景下,一張表可能分散到多個(gè)數(shù)據(jù)結(jié)點(diǎn)上。因此需要一些分布式ID的解決方案。 分布式ID需要有幾個(gè)特點(diǎn): 全局唯一(必要) :在多個(gè)庫的主鍵放在一起也不會(huì)重復(fù) 有序(必要) :避免頻繁觸發(fā)索引重建 信息安全 :ID連續(xù),可以根據(jù)訂單編號計(jì)算一天的單量,造成

    2024年02月07日
    瀏覽(29)
  • 開源:Taurus.DTC 微服務(wù)分布式事務(wù)框架,支持 .Net 和 .Net Core 雙系列版本

    開源:Taurus.DTC 微服務(wù)分布式事務(wù)框架,支持 .Net 和 .Net Core 雙系列版本

    在經(jīng)過1年多的深思,十幾年的框架編寫技術(shù)沉淀下,花了近一個(gè)月的時(shí)間,終于又為 .Net 及 .Net Core 的微服務(wù)系列框架貢獻(xiàn)當(dāng)中的一個(gè)重要組件。 https://github.com/cyq1162/Taurus.DTC ? 由于 CYQ.Data?Orm 組件本身支持10多種數(shù)據(jù)庫,因此提供的包,只根據(jù)消息隊(duì)列的需要分拆提供。 默

    2024年02月02日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包