天天看點

分布式id建立

1.java自帶uuid方式.

生成的uuid太長,且不為數字類型,不是自增長,影響資料查詢效率

2.共享資料庫生成id,N機器可以使用自增(1+N)...(N+N)

資料庫壓力大,維護成本高,需部署多台機器

3.使用Twitter的snowflake

snowflake,前42位為時間截(普通的13位long型時間,占長為41位),5位為datacenterId,5位為workerId,11位為sequenceId;(各自占長可以自行調節)

要求不同機器時間一緻,否則id自增會發生問題

package com.quna.common.id.snowflake;

import java.util.Date;

import com.quna.common.id.IdGen;

public abstract class AbstractSnowflakeIdGen implements IdGen {

protected long lastTimestamp = -1;

protected long tilNextTimestamp() {

long nextTime = timestamp();

while (nextTime <= lastTimestamp) {

nextTime = timestamp();

}

return nextTime;

}

protected long timestamp() {

return System.currentTimeMillis();

}

protected abstract long timestampLeft();

public Date getDate(long nextId) {

long timestamp = (nextId >> timestampLeft());

return new Date(timestamp);

}

}

package com.quna.common.id.snowflake;

import com.quna.common.id.IdGen;

public class DatacenterSnowflakeIdGen extends AbstractSnowflakeIdGen implements IdGen{

private final long workerId;

private final long datacenterId;

private long sequence = 0;

private static final long datacenterBits = 5; //0~31

private static final long maxDatacenterId = -1L ^ (-1L << datacenterBits);

private static final long workerBits = 5; //0~31

private static final long maxWorkerId = -1L ^ (-1L << workerBits);

private static final long sequenceBits = 11; //0~2047;

private static final long sequenceMask = -1L ^ (-1L << sequenceBits);

private static final long timestampLeft = sequenceBits + workerBits + datacenterBits;//時間左移位置

private static final long datacenterIdLeft = sequenceBits + workerBits;//資料中心左移位置

private static final long workerIdLeft = sequenceBits;//工作id左移位置

public DatacenterSnowflakeIdGen(final int datacenterId,final int workerId) {

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

throw new IllegalArgumentException(String.format("datacenterId can't be greater than %d and less than 0", maxDatacenterId));

}

if (workerId < 0 || workerId > maxWorkerId) {

throw new IllegalArgumentException(String.format("workerId can't be greater than %d and less than 0", maxWorkerId));

}

this.datacenterId = datacenterId;

this.workerId = workerId;

}

public synchronized long nextId() {

long ct = timestamp();

if (ct < lastTimestamp) {

throw new IllegalArgumentException("時間調整過,時間錯亂");

}

if (ct == lastTimestamp) {

sequence = (sequence + 1) & sequenceMask;

if (sequence == 0) {

ct = tilNextTimestamp();

}

} else {

sequence = 0;

}

lastTimestamp = ct;

//System.out.println("timestamp:" + ct + ",timestampLeft:" + timestampLeft + ",workerId:" + workerId + ",sequence:" + sequence);

return (ct << timestampLeft) | (datacenterId << datacenterIdLeft) | (workerId << workerIdLeft) | sequence;

}

@Override

protected long timestampLeft() {

return timestampLeft;

}

}

繼續閱讀