推特的工程师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 --- 0000000000 00 |
在上面的字符串中,第一位为未使用(实际上也可作为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