The unique ID may be unique identification data to generate a unique ID in a distributed system solutions There are many common ways about the following three ways:
- Dependency database, such as Oracle or MySQL from additional sequences, etc.
- UUID random number
- snowflake snowflake algorithm
First, the inadequacies of database programs and UUID
Using a database increment sequence:
- When separate read and write, only the master node can be written, there may be the risk of single point of failure
- Sub-table and warehouses, data migration, consolidation and so much trouble
UUID random number:
- Using meaningless string, not sorted
- UUID string stored, when the amount of data query efficiency is relatively low
Second, on the snow algorithm
There is a saying that nature does not exist two identical snowflakes. Each snowflake has its own unique shape beautiful and unique. Snow also said that algorithm generated unique ID like snowflakes.
1. The composition structure
Generally comprises: first invalid character, timestamp difference into four parts, the machine (process) encoding SEQ ID NO composition
2. Features (increment, orderly and suitable for distributed scenarios)
- Time position: it can be sorted according to time and help speed up the search
- Id bit machine: be applied to each node of a distributed environment of multi-node identifier may be specifically designed to divide the length of the machine 10 according to the bit nodes and deployment, such that the process division of five bits, etc.
- SEQ ID bit: is a series of self-energizing id, the same node can support the same number of milliseconds to generate a plurality of ID, 12-bit sequence number counter for each support node generates an ID number every 4096 ms
snowflake algorithm can be modified according to certain projects as well as their needs.
Third, the shortcomings of the algorithm snow
Snow algorithms on a stand-alone system ID is increasing, but in the case of multi-node distributed system, the clock does not guarantee that all the nodes are not perfectly synchronized, it is possible that this is not a global increment will appear.
Fourth, the code that implements the algorithm snow
Package com.lw.coodytest.snawflake; / ** * @Classname SnakeFlake * @Description on Twitter distributed algorithm snow self-energizing ID Snowflake (the Java) * Snowflake following structure (with each section - apart): <br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 0000000000 - 000000000000 <br> * 1-bit identifier, as long basic types are signed in Java, the most significant bit is the sign bit, 0 is a positive number, a negative number is 1, so generally id is a positive number, the most significant bit is <br> 0 * 41 cut time (milliseconds), it is noted than 41 times the cross-sectional cut-off storage time of the current time, but the difference between the storage time truncated (cut-off the current time - the start time of cut ) * value obtained), where the start time of a truncated, generally the time we start using id generator, designated by our program (following program IdWorker class attributes startTime below). * 41 cut time can be used 69 years, in = T (1L << 41 is) / (1000L * 60 * 60 * 24 * 365) = 69 <br> * 10-bit data bit machine can be deployed in 1024 nodes, and including 5 datacenterId <br> 5 workerId * 12 sequence count within milliseconds, 12 count the sequence number of each support node (the same machine, the same cut-off time) to produce the ID number 4096 per millisecond < br> * Add up to just 64 for a Long type. <br> * Snowflake advantage is that the overall increment in time order, and do not generate collisions ID (as distinguished from the data center ID and machine ID) throughout the distributed system, and high efficiency, * tested, per second can be Snowflake produce about 260,000 ID. @Author LW * * @date 2020-03-17 14:21 * / public class SnowflakeIdWorker { / ** * Start time cut * / Private static Final Long twepoch = 1420041600000L ; / ** * number of bits occupied by the machine id * / Private static Final Long workerIdBits = 5L ; / ** * id identifying occupied data bits * / Private static Final Long datacenterIdBits = 5L ; / ** * Support for maximum machine id, the result is 31 (this shift algorithm can quickly calculate the maximum number of decimal several binary number can represent) * / Private static Final Long maxWorkerId -1L = ^ (-1L << workerIdBits ); / ** * the maximum data identification id, result 31 is * / Private static Final Long maxDatacenterId -1L = ^ (-1L << datacenterIdBits); / ** * occupied in sequence id median * / Private static Final Long sequenceBits = 12L ; / ** * machine ID 12 to the left * / Private static Final Long workerIdShift = sequenceBits; / ** * Id identification data to the left by 17 (+ 12 is. 5) * / Private static Final Long datacenterIdShift + = sequenceBits workerIdBits; / ** * time to cut the left 22 (. 5 + + 12 is. 5) * / Private static Final Long workerIdBits + + = sequenceBits timestampLeftShift datacenterIdBits; / ** * generating a mask sequence, here 4095 (0b111111111111 = 0xFFF = 4095) * / Private static Final Long sequenceMask -1L = ^ (-1L << sequenceBits); / ** * working machine ID (0 ~ 31) * / Private Long workerId; / ** * data center ID (0 ~ 31) * / Private Long datacenterId; / ** * milliseconds sequence (0 ~ 4095) * / Private Long Sequence = 0L ; / ** * time cut previously generated ID * / Private Long LastTimestamp = -1L ; / ** * constructor * * @param workerId Job ID (~ 31 is 0) * @param datacenterId data center ID (~ 31 is 0) * / public SnowflakeIdWorker ( 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; } /** * 获得下一个ID (该方法是线程安全的) * * @return SnowflakeId */ public the synchronized Long nextId () { Long timestamp = TIMEGEN (); // if the current time is less than the timestamp of the last generation ID, indicating the system clock backoff time should be thrown through the IF (timestamp < LastTimestamp) { the throw new new a RuntimeException ( String.Format ( "Clock Moved Backwards ID for refusing to generate% D milliseconds.", LastTimestamp - timestamp)); } // if it is generated at the same time, the sequence is performed within milliseconds IF (LastTimestamp == timestamp) { sequence = (sequence +. 1) & sequenceMask; // millisecond sequence overflow IF (sequence == 0) { // blocking the next millisecond, obtain a new timestamp timestamp = tilNextMillis (LastTimestamp); } } // time stamp change, the reset sequence milliseconds the else { Sequence = 0L ; } // last time the generated ID cut LastTimestamp = timestamp; // shift to the fight and ORed together form a 64-bit ID return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | Sequence; } / ** * Blocking the next millisecond, until a new timestamp * * @param LastTimestamp last time generating sectional ID * @return current timestamp * / protected Long tilNextMillis ( Long LastTimestamp) { Long timestamp = TIMEGEN (); the while ( timestamp <= LastTimestamp) { timestamp = TIMEGEN (); } return timestamp; } / ** * returns the current time in milliseconds * * @return current time (ms) * / protected Long timeGen() { return System.currentTimeMillis(); } public static void main(String[] args) { SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0); for (int i = 0; i < 1000; i++) { long id = idWorker.nextId(); System.out.println(Long.toBinaryString(id)); System.out.println(id); } } }