自增id算法snowflake

Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序(方便客户端排序),并且在分布式系统中不同机器产生的id必须不同。

snowflake生成64的id,刚好使用long来保存,结构如下:

1位标识,由于long基本类型在java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0

41位时间截,注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69

10位的数据机器位,可以部署在1024个节点

12位序列,同一时间截,同一机器,可以生成4096个id

使用java实现:

public class IdWorker {
	
	//开始该类生成ID的时间截
	private final long startTime = 1463834116272L;
	
	//机器id所占的位数
	private long workerIdBits = 5L;
	
	//数据标识id所占的位数
	private long datacenterIdBits = 5L;
	
	//支持的最大机器id
	private long maxWorkerId = -1L ^ (-1L << workerIdBits);
	
	//支持的最大数据标识id
	private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
	
	//序列在id中占的位数
	private long sequenceBits = 12L;
	
	//机器id向左移的位数
	private long workerIdLeftShift = sequenceBits;
	
	//数据标识id向左移的位数
	private long datacenterIdLeftShift = workerIdBits + workerIdLeftShift;
	
	//时间截向左移的位置
	private long timestampLeftShift = datacenterIdBits + datacenterIdLeftShift;
	
	//生成序列的掩码
	private long sequenceMask = -1 ^ (-1 << sequenceBits);
	
	private long workerId;
	
	private long datacenterId;
	
	//同一个时间截内生成的序列数,初始值是0,从0开始
	private long sequence = 0L;
	
	//上次生成id的时间截
	private long lastTimestamp = -1L;
	
	public IdWorker(long workerId, long datacenterId){
		if(workerId < 0 || workerId > maxWorkerId){
			throw new IllegalArgumentException(
			    String.format("workerId[%d] is less than 0 or greater than maxWorkerId[%d].", workerId, maxWorkerId));
		}
		if(datacenterId < 0 || datacenterId > maxDatacenterId){
			throw new IllegalArgumentException(
				String.format("datacenterId[%d] is less than 0 or greater than maxDatacenterId[%d].", datacenterId, maxDatacenterId));
		}
		this.workerId = workerId;
		this.datacenterId = datacenterId;
	}
	
	//生成id
	public synchronized long nextId(){
		long timestamp = timeGen();
		if(timestamp < lastTimestamp){
			throw new RuntimeException(
				String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
		}
		//表示是同一时间截内生成的id
		if(timestamp == lastTimestamp){
			sequence = (sequence + 1) & sequenceMask;
			//说明当前时间生成的序列数已达到最大
			if(sequence == 0){
				//生成下一个毫秒级的序列
				timestamp = tilNextMillis();
				//序列从0开始
				sequence = 0L;
			}
		}else{
			//新的时间截,则序列从0开始
			sequence = 0L;
		}
		
		lastTimestamp = timestamp;
		
		return ((timestamp - startTime) << timestampLeftShift) //时间截部分
			| (datacenterId << datacenterIdLeftShift) //数据标识id部分
			| (workerId << workerIdLeftShift) //机器id部分
			| sequence; //序列部分
	}
	
	protected long tilNextMillis(){
		long timestamp = timeGen();
		while(timestamp <= lastTimestamp){
			timestamp = timeGen();
		}
		return timestamp;
	}
	
	protected long timeGen(){
		return System.currentTimeMillis();
	}
	
	//测试
	public static void main(String[] args){
		IdWorker idWorker = new IdWorker(31, 31);
		for(int i = 0; i < 1000; i++){
			System.out.println(idWorker.nextId());
		}
	}

}

转自

http://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8%87%AA%E5%A2%9Eid%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3/

http://www.devnote.cn/article/420.html


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值