欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)激活碼778899分享:分布式ID生成方式

柚子快報(bào)激活碼778899分享:分布式ID生成方式

http://yzkb.51969.com/

1.UUID

uuid方式存在問題:占用字節(jié)數(shù)比較大;ID比較隨機(jī),作為MySQL主鍵寫入庫(kù)時(shí),為了保證順序性將導(dǎo)致B+Tree節(jié)點(diǎn)分裂比較頻繁,影響IO性能。

2.數(shù)據(jù)庫(kù)方式

步長(zhǎng)step = 3,即為機(jī)器的數(shù)量。

??? 第一臺(tái)機(jī)器:起始值0,下一個(gè)ID位:0 + 0*3,0+1*3,0+2*3,..., ~ 0,3,6,9,...,3*n。 ??? 第一臺(tái)機(jī)器:起始值1,下一個(gè)ID位:1 + 0*3,1+1*3,1+2*3,..., ~ 1,4,7,10,...,3*n + 1。 ??? 第一臺(tái)機(jī)器:起始值2,下一個(gè)ID位:2 + 0*3,2+1*3,2+2*3,..., ~ 2,5,8,11,...,3*n + 2。

如果起初確認(rèn)Mysql機(jī)器數(shù)量為4,則每臺(tái)機(jī)器通過(guò)自增方式生成ID如下:

第一臺(tái):4 * n + 0。

第二臺(tái):4 * n + 1。

第三臺(tái):4 * n + 2。

第四臺(tái):4 * n + 3。

綜上,該方式每臺(tái)機(jī)器均衡負(fù)載后生成的ID均不會(huì)重復(fù)。每次請(qǐng)求均通過(guò)以下SQL申請(qǐng)新的ID:

begin;

REPLACE INTO Tickets64 (stub) VALUES ('a');

SELECT LAST_INSERT_ID();

commit;

其中,表Tickets64只有兩個(gè)字段,字段stub存在唯一索引。MySQL命令之replace保證每次更新stub值時(shí)如果存在該值則刪除后自增,否則直接自增。

備注:表Tickets64只有一行數(shù)據(jù),行鎖保證并發(fā)問題。

問題:運(yùn)行中途需要新增機(jī)器來(lái)增加并發(fā)性能,ID如何處理?

解答:觀察現(xiàn)有所有機(jī)器找到其中最大ID值,例如1800。其次,重新確定每臺(tái)機(jī)器的起始值,例如3000、3001、3002、...?!颈仨毚笥?800】。然后,再次修改Mysql自增的步長(zhǎng)。最后重啟所有機(jī)器。

以上這種方式存在的問題:

機(jī)器橫向擴(kuò)展比較麻煩。ID并非單調(diào)自增,而是趨勢(shì)自增。每次獲取ID都得操作數(shù)據(jù)庫(kù),高并發(fā)嚴(yán)重影響性能。

解決辦法之Leaf方案。

2.1.Leaf-segment數(shù)據(jù)庫(kù)方案

第一種Leaf-segment方案,在使用數(shù)據(jù)庫(kù)的方案上,做了如下改變: - 原方案每次獲取ID都得讀寫一次數(shù)據(jù)庫(kù),造成數(shù)據(jù)庫(kù)壓力大。改為利用proxy server批量獲取,每次獲取一個(gè)segment(step決定大小)號(hào)段的值。用完之后再去數(shù)據(jù)庫(kù)獲取新的號(hào)段,可以大大的減輕數(shù)據(jù)庫(kù)的壓力。 - 各個(gè)業(yè)務(wù)不同的發(fā)號(hào)需求用biz_tag字段來(lái)區(qū)分,每個(gè)biz-tag的ID獲取相互隔離,互不影響。如果以后有性能需求需要對(duì)數(shù)據(jù)庫(kù)擴(kuò)容,不需要上述描述的復(fù)雜的擴(kuò)容操作,只需要對(duì)biz_tag分庫(kù)分表就行。

數(shù)據(jù)庫(kù)設(shè)計(jì)方案如下:

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

Leaf服務(wù)可以很方便的線性擴(kuò)展,性能完全能夠支撐大多數(shù)業(yè)務(wù)場(chǎng)景。ID號(hào)碼是趨勢(shì)遞增的8byte的64位數(shù)字,滿足上述數(shù)據(jù)庫(kù)存儲(chǔ)的主鍵要求。容災(zāi)性高:Leaf服務(wù)內(nèi)部有號(hào)段緩存,即使DB宕機(jī),短時(shí)間內(nèi)Leaf仍能正常對(duì)外提供服務(wù)。可以自定義max_id的大小,非常方便業(yè)務(wù)從原有的ID方式上遷移過(guò)來(lái)。

缺點(diǎn):

ID號(hào)碼不夠隨機(jī),能夠泄露發(fā)號(hào)數(shù)量的信息,不太安全。TP999數(shù)據(jù)波動(dòng)大,當(dāng)號(hào)段使用完之后還是會(huì)hang在更新數(shù)據(jù)庫(kù)的I/O上,tg999數(shù)據(jù)會(huì)出現(xiàn)偶爾的尖刺。DB宕機(jī)會(huì)造成整個(gè)系統(tǒng)不可用。

2.2.Leaf-segment數(shù)據(jù)庫(kù)進(jìn)化方案之雙buffer優(yōu)化?

對(duì)于第二個(gè)缺點(diǎn),Leaf-segment做了一些優(yōu)化,簡(jiǎn)單的說(shuō)就是:

Leaf 取號(hào)段的時(shí)機(jī)是在號(hào)段消耗完的時(shí)候進(jìn)行的,也就意味著號(hào)段臨界點(diǎn)的ID下發(fā)時(shí)間取決于下一次從DB取回號(hào)段的時(shí)間,并且在這期間進(jìn)來(lái)的請(qǐng)求也會(huì)因?yàn)镈B號(hào)段沒有取回來(lái),導(dǎo)致線程阻塞。如果請(qǐng)求DB的網(wǎng)絡(luò)和DB的性能穩(wěn)定,這種情況對(duì)系統(tǒng)的影響是不大的,但是假如取DB的時(shí)候網(wǎng)絡(luò)發(fā)生抖動(dòng),或者DB發(fā)生慢查詢就會(huì)導(dǎo)致整個(gè)系統(tǒng)的響應(yīng)時(shí)間變慢。

為此,我們希望DB取號(hào)段的過(guò)程能夠做到無(wú)阻塞,不需要在DB取號(hào)段的時(shí)候阻塞請(qǐng)求線程,即當(dāng)號(hào)段消費(fèi)到某個(gè)點(diǎn)時(shí)就異步的把下一個(gè)號(hào)段加載到內(nèi)存中。而不需要等到號(hào)段用盡的時(shí)候才去更新號(hào)段。這樣做就可以很大程度上的降低系統(tǒng)的TP999指標(biāo)。

public class SegmentIDGenImpl implements IDGen {

//tag 與 segment對(duì)應(yīng)關(guān)系

private Map cache = new ConcurrentHashMap();

public Result get(final String key) {

if (cache.containsKey(key)) {

SegmentBuffer buffer = cache.get(key);

if (!buffer.isInitOk()) {// 雙檢加鎖

synchronized (buffer) {

if (!buffer.isInitOk()) {

updateSegmentFromDb(key, buffer.getCurrent());

buffer.setInitOk(true);

}

}

}

return getIdFromSegmentBuffer(cache.get(key));

}

return new Result(EXCEPTION_ID_KEY_NOT_EXISTS, Status.EXCEPTION);

}

public void updateSegmentFromDb(String key, Segment segment) {

StopWatch sw = new Slf4JStopWatch();

SegmentBuffer buffer = segment.getBuffer();

LeafAlloc leafAlloc;

if (!buffer.isInitOk()) {

//UPDATE T_LEAF_ALLOC SET MAX_ID = MAX_ID + STEP WHERE BIZ_TAG = #{tag}

// mysql 寫操作不存在并發(fā)問題。初始化完畢MAX_ID

leafAlloc = dao.updateMaxIdAndGetLeafAlloc(key);

buffer.setStep(leafAlloc.getStep());

buffer.setMinStep(leafAlloc.getStep());//leafAlloc中的step為DB中的step

} else if (buffer.getUpdateTimestamp() == 0) {

leafAlloc = dao.updateMaxIdAndGetLeafAlloc(key);

buffer.setUpdateTimestamp(System.currentTimeMillis());

buffer.setStep(leafAlloc.getStep());

buffer.setMinStep(leafAlloc.getStep());//leafAlloc中的step為DB中的step

} else {

long duration = System.currentTimeMillis() - buffer.getUpdateTimestamp();

int nextStep = buffer.getStep();

if (duration < SEGMENT_DURATION) {

if (nextStep * 2 > MAX_STEP) {

//do nothing

} else {

nextStep = nextStep * 2;

}

} else if (duration < SEGMENT_DURATION * 2) {

//do nothing with nextStep

} else {

nextStep = nextStep / 2 >= buffer.getMinStep() ? nextStep / 2 : nextStep;

}

logger.info("leafKey[{}], step[{}], duration[{}mins], nextStep[{}]", key, buffer.getStep(), String.format("%.2f",((double)duration / (1000 * 60))), nextStep);

LeafAlloc temp = new LeafAlloc();

temp.setKey(key);

temp.setStep(nextStep);

leafAlloc = dao.updateMaxIdByCustomStepAndGetLeafAlloc(temp);

buffer.setUpdateTimestamp(System.currentTimeMillis());

buffer.setStep(nextStep);

buffer.setMinStep(leafAlloc.getStep());//leafAlloc的step為DB中的step

}

// must set value before set max

long value = leafAlloc.getMaxId() - buffer.getStep();

segment.getValue().set(value);

segment.setMax(leafAlloc.getMaxId());

segment.setStep(buffer.getStep());

sw.stop("updateSegmentFromDb", key + " " + segment);

}

public Result getIdFromSegmentBuffer(final SegmentBuffer buffer) {

// 一個(gè)進(jìn)程中,存在并發(fā)訪問cache中某個(gè)tag

while (true) {

buffer.rLock().lock();

try {

// 從雙buffer中獲取當(dāng)前Segment

final Segment segment = buffer.getCurrent();

// 如果當(dāng)前步長(zhǎng)內(nèi),ID使用率已經(jīng)達(dá)到步長(zhǎng)的90%,則需要切換buffer

if (!buffer.isNextReady() && (segment.getIdle() < 0.9 * segment.getStep()) && buffer.getThreadRunning().compareAndSet(false, true)) {

service.execute(new Runnable() {

@Override

public void run() {

//獲取到第二個(gè)Segment

Segment next = buffer.getSegments()[buffer.nextPos()];

boolean updateOk = false;

try {

// 初始化第二個(gè)Segment對(duì)應(yīng)的其實(shí)ID,以及步長(zhǎng)

updateSegmentFromDb(buffer.getKey(), next);

updateOk = true;

} catch (Exception e) {

logger.warn(buffer.getKey() + " updateSegmentFromDb exception", e);

} finally {

if (updateOk) {

buffer.wLock().lock();

buffer.setNextReady(true);

buffer.getThreadRunning().set(false);

buffer.wLock().unlock();

} else {

buffer.getThreadRunning().set(false);

}

}

}

});

}

// 在當(dāng)前步長(zhǎng)中獲取下一個(gè)ID

long value = segment.getValue().getAndIncrement();

if (value < segment.getMax()) {// 沒有達(dá)到最大ID之前,均成功返回

return new Result(value, Status.SUCCESS);

}

} finally {

buffer.rLock().unlock();

}

//以下執(zhí)行說(shuō)明ID已經(jīng)達(dá)到最大值

waitAndSleep(buffer);

buffer.wLock().lock();

try {

final Segment segment = buffer.getCurrent();

long value = segment.getValue().getAndIncrement();

if (value < segment.getMax()) {//以下成立,說(shuō)明上述定時(shí)任務(wù)切換Segment成功

return new Result(value, Status.SUCCESS);

}

if (buffer.isNextReady()) {//

buffer.switchPos();

buffer.setNextReady(false);

} else {

return new Result(EXCEPTION_ID_TWO_SEGMENTS_ARE_NULL, Status.EXCEPTION);

}

} finally {

buffer.wLock().unlock();

}

}

}

}

2.3.Leaf高可用容災(zāi)

對(duì)于第三點(diǎn)“DB可用性”問題,我們目前采用一主兩從的方式,同時(shí)分機(jī)房部署,Master和Slave之間采用半同步方式同步數(shù)據(jù)。同時(shí)使用公司Atlas數(shù)據(jù)庫(kù)中間件(已開源,改名為DBProxy)做主從切換。當(dāng)然這種方案在一些情況會(huì)退化成異步模式,甚至在非常極端情況下仍然會(huì)造成數(shù)據(jù)不一致的情況,但是出現(xiàn)的概率非常小。如果你的系統(tǒng)要保證100%的數(shù)據(jù)強(qiáng)一致,可以選擇使用“類Paxos算法”實(shí)現(xiàn)的強(qiáng)一致MySQL方案,如MySQL 5.7前段時(shí)間剛剛GA的MySQL Group Replication。但是運(yùn)維成本和精力都會(huì)相應(yīng)的增加,根據(jù)實(shí)際情況選型即可。

3.Leaf-snowflake方案

Leaf-segment方案可以生成趨勢(shì)遞增的ID,同時(shí)ID號(hào)是可計(jì)算的,不適用于訂單ID生成場(chǎng)景,比如競(jìng)對(duì)在兩天中午12點(diǎn)分別下單,通過(guò)訂單id號(hào)相減就能大致計(jì)算出公司一天的訂單量,這個(gè)是不能忍受的。面對(duì)這一問題,我們提供了 Leaf-snowflake方案。

public class SnowFlake {

/**

* 起始的時(shí)間戳

*/

private final static long START_STMP = 1480166465631L;

/**

* 每一部分占用的位數(shù)

*/

private final static long SEQUENCE_BIT = 12; //序列號(hào)占用的位數(shù)

private final static long MACHINE_BIT = 5; //機(jī)器標(biāo)識(shí)占用的位數(shù)

private final static long DATACENTER_BIT = 5;//數(shù)據(jù)中心占用的位數(shù)

/**

* 每一部分的最大值

*/

private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);

private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);

private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

/**

* 每一部分向左的位移

*/

private final static long MACHINE_LEFT = SEQUENCE_BIT;

private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;

private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

private long datacenterId; //數(shù)據(jù)中心

private long machineId; //機(jī)器標(biāo)識(shí)

private long sequence = 0L; //序列號(hào)

private long lastStmp = -1L;//上一次時(shí)間戳

public SnowFlake(long datacenterId, long machineId) {

if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {

throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_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)生下一個(gè)ID

* @return

* 同步鎖的保證:同一毫秒內(nèi)可能存在多個(gè)請(qǐng)求競(jìng)爭(zhēng)得到同步鎖。

*/

public synchronized long nextId() {

long currStmp = getNewstmp();

/**

* 同一毫秒內(nèi)允許 MAX_SEQUENCE(4095)個(gè)請(qǐng)求先后生成ID。多余的請(qǐng)求因?yàn)橐韵聴l件的成立拒絕生成

*/

if (currStmp < lastStmp) {

throw new RuntimeException("Clock moved backwards. Refusing to generate id");

}

if (currStmp == lastStmp) {

//相同毫秒內(nèi),序列號(hào)自增

sequence = (sequence + 1) & MAX_SEQUENCE;

//同一毫秒的序列數(shù)已經(jīng)達(dá)到最大

if (sequence == 0L) {

currStmp = getNextMill();

}

} else {

//不同毫秒內(nèi),序列號(hào)置為0

sequence = 0L;

}

lastStmp = currStmp;

/**

* 在64位字節(jié)中通過(guò) 或 操作將 時(shí)間戳、數(shù)據(jù)中心、機(jī)器標(biāo)識(shí)、序列號(hào)4部分放到對(duì)應(yīng)字節(jié)范圍內(nèi)。

* 注意:對(duì)于同一個(gè)項(xiàng)目,datacenterId、machineId可能是不變的。如果隨便更改時(shí)間戳起始值之START_STMP值可能導(dǎo)致分布式ID存在相同的情況。

*

* 在分布式ID 64個(gè)字節(jié)中,41個(gè)字節(jié)作為時(shí)間戳,其對(duì)應(yīng)的最大值為2^41。41 位的時(shí)間位是2 ^ 41 / (365 * 24 * 3600 * 1000) = 69 年。

* currStmp - START_STMP 是指距離當(dāng)年之后的69年內(nèi)。

* 如果直接用 currStmp 替代,則表示距離1970年后的69年,以2024年為例最多可用15年。

*/

return (currStmp - START_STMP) << TIMESTMP_LEFT //時(shí)間戳部分

| datacenterId << DATACENTER_LEFT //數(shù)據(jù)中心部分

| machineId << MACHINE_LEFT //機(jī)器標(biāo)識(shí)部分

| sequence; //序列號(hào)部分

}

private long getNextMill() {

long mill = getNewstmp();

while (mill <= lastStmp) {

mill = getNewstmp();

}

return mill;

}

private long getNewstmp() {

return System.currentTimeMillis();

}

public static void m1() {

SnowFlake snowFlake = new SnowFlake(2, 3);

for (int i = 0; i < (1 << 12); i++) {

System.out.println(snowFlake.nextId());

}

}

}

3.1.解決時(shí)鐘回?fù)軉栴}

時(shí)鐘回?fù)軐?dǎo)致的問題存在兩個(gè):獲取分布式ID & 服務(wù)啟動(dòng)流程。

3.1.1.服務(wù)啟動(dòng)

因?yàn)檫@種方案依賴時(shí)間,如果機(jī)器的時(shí)鐘發(fā)生了回?fù)?,那么就?huì)有可能生成重復(fù)的ID號(hào),需要解決時(shí)鐘回退的問題。

參見上圖整個(gè)啟動(dòng)流程圖,服務(wù)啟動(dòng)時(shí)首先檢查自己是否寫過(guò)ZooKeeper leaf_forever節(jié)點(diǎn):

若寫過(guò),則用自身系統(tǒng)時(shí)間與leaf_forever/${self}節(jié)點(diǎn)記錄時(shí)間做比較,若小于leaf_forever/${self}時(shí)間則認(rèn)為機(jī)器時(shí)間發(fā)生了大步長(zhǎng)回?fù)?,服?wù)啟動(dòng)失敗并報(bào)警。若未寫過(guò),證明是新服務(wù)節(jié)點(diǎn),直接創(chuàng)建持久節(jié)點(diǎn)leaf_forever/${self}并寫入自身系統(tǒng)時(shí)間,接下來(lái)綜合對(duì)比其余Leaf節(jié)點(diǎn)的系統(tǒng)時(shí)間來(lái)判斷自身系統(tǒng)時(shí)間是否準(zhǔn)確,具體做法是取leaf_temporary下的所有臨時(shí)節(jié)點(diǎn)(所有運(yùn)行中的Leaf-snowflake節(jié)點(diǎn))的服務(wù)IP:Port,然后通過(guò)RPC請(qǐng)求得到所有節(jié)點(diǎn)的系統(tǒng)時(shí)間,計(jì)算sum(time)/nodeSize。若abs( 系統(tǒng)時(shí)間-sum(time)/nodeSize ) < 閾值,認(rèn)為當(dāng)前系統(tǒng)時(shí)間準(zhǔn)確,正常啟動(dòng)服務(wù),同時(shí)寫臨時(shí)節(jié)點(diǎn)leaf_temporary/${self} 維持租約。否則認(rèn)為本機(jī)系統(tǒng)時(shí)間發(fā)生大步長(zhǎng)偏移,啟動(dòng)失敗并報(bào)警。每隔一段時(shí)間(3s)上報(bào)自身系統(tǒng)時(shí)間寫入leaf_forever/${self}。

?

public class SnowflakeIDGenImpl implements IDGen {

public SnowflakeIDGenImpl(String zkAddress, int port, long twepoch) {

this.twepoch = twepoch;

Preconditions.checkArgument(timeGen() > twepoch, "Snowflake not support twepoch gt currentTime");

final String ip = Utils.getIp();

SnowflakeZookeeperHolder holder = new SnowflakeZookeeperHolder(ip, String.valueOf(port), zkAddress);

boolean initFlag = holder.init();

Preconditions.checkArgument(workerId >= 0 && workerId <= maxWorkerId, "workerID must gte 0 and lte 1023");

}

}

public class SnowflakeZookeeperHolder {

public boolean init() {

try {

CuratorFramework curator = createWithOptions(connectionString, new RetryUntilElapsed(1000, 4), 10000, 6000);

curator.start();

Stat stat = curator.checkExists().forPath(PATH_FOREVER);

if (stat == null) {

//不存在根節(jié)點(diǎn),機(jī)器第一次啟動(dòng),創(chuàng)建/snowflake/ip:port-000000000,并上傳數(shù)據(jù)

zk_AddressNode = createNode(curator);

//worker id 默認(rèn)是0

updateLocalWorkerID(workerID);

//定時(shí)上報(bào)本機(jī)時(shí)間給forever節(jié)點(diǎn):其實(shí)就是一個(gè)定時(shí)任務(wù),每隔3秒上報(bào)一次當(dāng)前時(shí)間啊

ScheduledUploadData(curator, zk_AddressNode);

return true;

} else {

Map nodeMap = Maps.newHashMap();//ip:port->00001

Map realNode = Maps.newHashMap();//ip:port->(ipport-000001)

//存在根節(jié)點(diǎn),先檢查是否有屬于自己的根節(jié)點(diǎn)

List keys = curator.getChildren().forPath(PATH_FOREVER);

for (String key : keys) {

String[] nodeKey = key.split("-");

realNode.put(nodeKey[0], key);

nodeMap.put(nodeKey[0], Integer.parseInt(nodeKey[1]));

}

Integer workerid = nodeMap.get(listenAddress);

if (workerid != null) {

//有自己的節(jié)點(diǎn),zk_AddressNode=ip:port

zk_AddressNode = PATH_FOREVER + "/" + realNode.get(listenAddress);

workerID = workerid;//啟動(dòng)worder時(shí)使用會(huì)使用

if (!checkInitTimeStamp(curator, zk_AddressNode)) {

throw new CheckLastTimeException("init timestamp check error,forever node timestamp gt this node time");

}

//準(zhǔn)備創(chuàng)建臨時(shí)節(jié)點(diǎn)

doService(curator);

// 將workerID 初始化在 leaf 服務(wù)本地磁盤內(nèi)部,一旦zk出現(xiàn)問題可以從本地磁盤獲取該workerID

updateLocalWorkerID(workerID);

} else {

//表示新啟動(dòng)的節(jié)點(diǎn),創(chuàng)建持久節(jié)點(diǎn) ,不用check時(shí)間

String newNode = createNode(curator);

zk_AddressNode = newNode;

String[] nodeKey = newNode.split("-");

workerID = Integer.parseInt(nodeKey[1]);

doService(curator);

updateLocalWorkerID(workerID);

LOGGER.info("[New NODE]can not find node on forever node that endpoint ip-{} port-{} workid-{},create own node on forever node and start SUCCESS ", ip, port, workerID);

}

}

} catch (Exception e) {

LOGGER.error("Start node ERROR {}", e);

try {

// 如果 zk 出現(xiàn)問題,從本地磁盤獲取workerID

Properties properties = new Properties();

properties.load(new FileInputStream(new File(PROP_PATH.replace("{port}", port + ""))));

workerID = Integer.valueOf(properties.getProperty("workerID"));

LOGGER.warn("START FAILED ,use local node file properties workerID-{}", workerID);

} catch (Exception e1) {

LOGGER.error("Read file error ", e1);

return false;

}

}

return true;

}

}

public class SnowflakeIDGenImpl implements IDGen {

public synchronized Result get(String key) {//獲取分布式事務(wù)ID

long timestamp = timeGen();

if (timestamp < lastTimestamp) {//出現(xiàn)了時(shí)鐘回?fù)墁F(xiàn)象

long offset = lastTimestamp - timestamp;

if (offset <= 5) {

try {

wait(offset << 1);// 等待一段時(shí)間:時(shí)鐘回?fù)軙r(shí)間段

timestamp = timeGen();// 再次獲取新的時(shí)間

if (timestamp < lastTimestamp) {

return new Result(-1, Status.EXCEPTION);

}

} catch (InterruptedException e) {

LOGGER.error("wait interrupted");

return new Result(-2, Status.EXCEPTION);

}

} else {

return new Result(-3, Status.EXCEPTION);

}

}

if (lastTimestamp == timestamp) {

sequence = (sequence + 1) & sequenceMask;

if (sequence == 0) {

//seq 為0的時(shí)候表示是下一毫秒時(shí)間開始對(duì)seq做隨機(jī)

sequence = RANDOM.nextInt(100);

timestamp = tilNextMillis(lastTimestamp);

}

} else {

//如果是新的ms開始

sequence = RANDOM.nextInt(100);

}

lastTimestamp = timestamp;

// 返回最終的分布式ID

long id = ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;

return new Result(id, Status.SUCCESS);

}

}

Leaf——美團(tuán)點(diǎn)評(píng)分布式ID生成系統(tǒng)

柚子快報(bào)激活碼778899分享:分布式ID生成方式

http://yzkb.51969.com/

精彩內(nèi)容

評(píng)論可見,查看隱藏內(nèi)容
大家都在看:

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19002166.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄