twitter的snowflake算法

推特的工程师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);
  }
}

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

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");
    }

}

时间: 2024-08-10 19:15:45

twitter的snowflake算法的相关文章

twitter的snowflake算法(C#版本)

转自:http://blog.csdn.net/kinwyb/article/details/50238505 使用twitter的snowflake算法生成唯一ID. 在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位+机器ID 10位+毫秒内序列12位. /// <summary> /// 根据twitter的snowflake算法生成唯一ID /// snowflake算法

C# 根据twitter的snowflake算法生成唯一ID

C# 版算法: 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Demo 8 { 9 10 /// <summary> 11 /// 根据twitter的snowflake算法生成唯一ID 12 /// snowflake算法 64 位 13 /// 0---000

使用SnowFlake算法生成唯一ID

转自:https://segmentfault.com/a/1190000007769660 考虑过的方法有 直接用时间戳,或者以此衍生的一系列方法 Mysql自带的uuid 以上两种方法都可以查到就不多做解释了 最终选择了Twitter的SnowFlake算法 这个算法的好处很简单可以在每秒产生约400W个不同的16位数字ID(10进制) 原理很简单 ID由64bit组成 其中 第一个bit空缺 41bit用于存放毫秒级时间戳 10bit用于存放机器id 12bit用于存放自增ID 除了最高位

snowflake算法(java版)

 转自:http://www.cnblogs.com/haoxinyue/p/5208136.html 1. 数据库自增长序列或字段 最常见的方式.利用数据库,全数据库唯一. 优点: 1)简单,代码方便,性能可以接受. 2)数字ID天然排序,对分页或者需要排序的结果很有帮助. 缺点: 1)不同数据库语法和实现不同,数据库迁移的时候或多数据库版本支持的时候需要处理. 2)在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成.有单点故障的风险. 3)在性能达不到要求的情况下,比较难于扩展.

一篇文章彻底搞懂snowflake算法及百度美团的最佳实践

写在前面的话 一提到分布式ID自动生成方案,大家肯定都非常熟悉,并且立即能说出自家拿手的几种方案,确实,ID作为系统数据的重要标识,重要性不言而喻,而各种方案也是历经多代优化,请允许我用这个视角对分布式ID自动生成方案进行分类: 实现方式 完全依赖数据源方式 ID的生成规则,读取控制完全由数据源控制,常见的如数据库的自增长ID,序列号等,或Redis的INCR/INCRBY原子操作产生顺序号等. 半依赖数据源方式 ID的生成规则,有部分生成因子需要由数据源(或配置信息)控制,如snowflake

彻底搞懂snowflake算法及百度美团的最佳实践

写在前面的话 一提到分布式ID自动生成方案,大家肯定都非常熟悉,并且立即能说出自家拿手的几种方案,确实,ID作为系统数据的重要标识,重要性不言而喻,而各种方案也是历经多代优化,请允许我用这个视角对分布式ID自动生成方案进行分类: 实现方式 完全依赖数据源方式 ID的生成规则,读取控制完全由数据源控制,常见的如数据库的自增长ID,序列号等,或Redis的INCR/INCRBY原子操作产生顺序号等. 半依赖数据源方式 ID的生成规则,有部分生成因子需要由数据源(或配置信息)控制,如snowflake

通过rest接口获取自增id (twitter snowflake算法)

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

分布式唯一id:snowflake算法思考

匠心零度 转载请注明原创出处,谢谢! 缘起 为什么会突然谈到分布式唯一id呢?原因是最近在准备使用RocketMQ,看看官网介绍: 一句话,消息可能会重复,所以消费端需要做幂等.为什么消息会重复后续RocketMQ章节进行详细介绍,本节重点不在这里. 为了达到业务的幂等,必须要有这样一个id存在,需要满足下面几个条件: 同一业务场景要全局唯一. 该id必须是在消息的发送方进行产生发送到MQ. 消费端根据该id进行判断是否重复,确保幂等. 在那里产生,和消费端进行判断等和这个id没有关系,这个id

snowflake算法

1.snowflake算法ID生成器介绍 snowflake 是 twitter 开源的一个分布式ID 生成器 2.为什么使用snowflake (1) 主键自增弊端:不是全局id,当多表合并.构建数据仓库.进行数据分析.会导致主键冲突 (2) uuid或guid弊端:数据量过大 (3)全局redis生成弊端:内存开销大.网络开销大 (4)snowflake解决上述问题.效率高.经测试每秒可产生26万个id 3.生成原理 (1)采用64位二进制数结构 (2)第1位不用,保留 (3)后41位为时间