Distributed generation ID - Snow algorithm

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

 

Guess you like

Origin www.cnblogs.com/lwcode6/p/12511125.html