码迷,mamicode.com
首页 > 编程语言 > 详细

twitter的snowflake算法

时间:2016-07-30 18:00:29      阅读:234      评论:0      收藏:0      [点我收藏+]

标签:

推特的工程师snowflake也提出了一个在分布式系统中生成唯一序列的方法;

java中的UUID也是一种可取的方法,他的缺点是序列号太长了。

snowflake算法最原始的形式是用scala语言写的https://github.com/twitter/snowflake/releases/tag/snowflake-2010

核心代码为其IdWorker这个类实现,其原理结构如下,分别用一个0表示一位,用—分割开部分的作用:

 

1 0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000

在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。

java实现:

技术分享
package mine;

import util.Trie;

/** Snowflake */
public class IdWorker {
 
  private final long twepoch = 1288834974657L;
  private final long workerIdBits = 5L;
  private final long datacenterIdBits = 5L;
  private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
  private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
  private final long sequenceBits = 12L;
  private final long workerIdShift = sequenceBits;
  private final long datacenterIdShift = sequenceBits + workerIdBits;
  private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
  private final long sequenceMask = -1L ^ (-1L << sequenceBits);
 
  private long workerId;
  private long datacenterId;
  private long sequence = 0L;
  private long lastTimestamp = -1L;
 
  public IdWorker(long workerId, long datacenterId) {
    if (workerId > maxWorkerId || workerId < 0) {
      throw new IllegalArgumentException(String.format("worker Id can‘t be greater than %d or less than 0", maxWorkerId));
    }
    if (datacenterId > maxDatacenterId || datacenterId < 0) {
      throw new IllegalArgumentException(String.format("datacenter Id can‘t be greater than %d or less than 0", maxDatacenterId));
    }
    this.workerId = workerId;
    this.datacenterId = datacenterId;
  }
 
  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));
    }
    if (lastTimestamp == timestamp) {
      sequence = (sequence + 1) & sequenceMask;
      if (sequence == 0) {
        timestamp = tilNextMillis(lastTimestamp);
      }
    } else {
      sequence = 0L;
    }
 
    lastTimestamp = timestamp;
 
    return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
  }
 
  protected long tilNextMillis(long lastTimestamp) {
    long timestamp = timeGen();
    while (timestamp <= lastTimestamp) {
      timestamp = timeGen();
    }
    return timestamp;
  }
 
  protected long timeGen() {
    return System.currentTimeMillis();
  }
 
  private static Trie trie=new Trie();
  public static void main(String[] args) {
      long time0 = System.currentTimeMillis();
      IdWorker idWorker = new IdWorker(0, 0);
      for (int i = 0; i < 3000000; i++) {
          long id = idWorker.nextId();
          trie.insert(""+id);
          //System.out.println(id);
      }
      long time = (int)((System.currentTimeMillis()-time0)/1000);
      System.out.println("Time:"+time+"s  conflict:"+trie.count);
  }
}
View Code

测试:一百万条数据都没有冲突;

技术分享
package mine;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import util.Trie;

public class IdWorkerTest extends Thread{
    private static Trie trie=new Trie();
    private static Object lock = new Object();
    private static int count=0;
    static IdWorker worker = new IdWorker(0,0);
    public void run(){
        long squence =worker.nextId();
        System.out.println(squence);
        synchronized(lock){
            trie.insert(""+squence);    
            count++;
            if(count%100==0){        
                System.out.println("生成第"+count+"条数据  冲突计数:"+trie.count);
            }
        }
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int n =10000;
        ExecutorService executor = Executors.newFixedThreadPool(n);
        for(int i=0;i<100*n;i++){
            Thread thread = new IdWorkerTest();
            executor.execute(thread);
        }
        executor.shutdown();
        while(!executor.isTerminated()){}
        System.out.println("生成第"+count+"条数据  冲突计数:"+trie.count);
        System.out.println("done");
    }

}
View Code

 

twitter的snowflake算法

标签:

原文地址:http://www.cnblogs.com/yuanzhenliu/p/5721275.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!