zoukankan      html  css  js  c++  java
  • 雪花算法

    在分布式系统中,会有生成全局唯一ID的需求,已有的解决方案中,UUID不便于索引,全局ID生成器自身会有性能瓶颈,雪花算法则很好的解决了这两个问题
    雪花算法生成的是一个64位的LONG值,主要由以下四个部分组成
    1、1位的保留位
    2、41位的时间戳(可以保证69年不重复)
    3、10位的机器ID(可供1024台机器使用)
    4、12位的自增序列号(从1-4096中循环使用)
    基于雪花算法的设计原则(时间戳+机器号+自增号)可以很方便的设计出符合自己需要的ID生成器,需要注意的是,雪花算法依赖于机器自身的时间,如果机器自身的时间存在问题,则可能出现重复ID,这个问题可以在生成器初始化时,连接时间服务器来解决。
    GITHUB上的雪花算法基于scala实现:
    https://github.com/twitter/snowflake
    基于Java的实现可参考,这个实现与twitter的实现略有不同,使用了保留位,可以生成139年不重复的ID:
    https://www.callicoder.com/distributed-unique-id-sequence-number-generator/
    import java.net.NetworkInterface;
    import java.security.SecureRandom;
    import java.time.Instant;
    import java.util.Enumeration;
    
    /**
     * Distributed Sequence Generator.
     * Inspired by Twitter snowflake: https://github.com/twitter/snowflake/tree/snowflake-2010
     *
     * This class should be used as a Singleton.
     * Make sure that you create and reuse a Single instance of SequenceGenerator per node in your distributed system cluster.
     */
    public class SequenceGenerator {
        private static final int TOTAL_BITS = 64;
        private static final int EPOCH_BITS = 42;
        private static final int NODE_ID_BITS = 10;
        private static final int SEQUENCE_BITS = 12;
    
        private static final int maxNodeId = (int)(Math.pow(2, NODE_ID_BITS) - 1);
        private static final int maxSequence = (int)(Math.pow(2, SEQUENCE_BITS) - 1);
    
        // Custom Epoch (January 1, 2015 Midnight UTC = 2015-01-01T00:00:00Z)
        private static final long CUSTOM_EPOCH = 1420070400000L;
    
        private final int nodeId;
    
        private volatile long lastTimestamp = -1L;
        private volatile long sequence = 0L;
    
        // Create SequenceGenerator with a nodeId
        public SequenceGenerator(int nodeId) {
            if(nodeId < 0 || nodeId > maxNodeId) {
                throw new IllegalArgumentException(String.format("NodeId must be between %d and %d", 0, maxNodeId));
            }
            this.nodeId = nodeId;
        }
    
        // Let SequenceGenerator generate a nodeId
        public SequenceGenerator() {
            this.nodeId = createNodeId();
        }
    
    
        public synchronized long nextId() {
            long currentTimestamp = timestamp();
    
            if(currentTimestamp < lastTimestamp) {
                throw new IllegalStateException("Invalid System Clock!");
            }
    
            if (currentTimestamp == lastTimestamp) {
                sequence = (sequence + 1) & maxSequence;
                if(sequence == 0) {
                    // Sequence Exhausted, wait till next millisecond.
                    currentTimestamp = waitNextMillis(currentTimestamp);
                }
            } else {
                // reset sequence to start with zero for the next millisecond
                sequence = 0;
            }
    
            lastTimestamp = currentTimestamp;
    
            long id = currentTimestamp << (TOTAL_BITS - EPOCH_BITS);
            id |= (nodeId << (TOTAL_BITS - EPOCH_BITS - NODE_ID_BITS));
            id |= sequence;
            return id;
        }
    
    
        // Get current timestamp in milliseconds, adjust for the custom epoch.
        private static long timestamp() {
            return Instant.now().toEpochMilli() - CUSTOM_EPOCH;
        }
    
        // Block and wait till next millisecond
        private long waitNextMillis(long currentTimestamp) {
            while (currentTimestamp == lastTimestamp) {
                currentTimestamp = timestamp();
            }
            return currentTimestamp;
        }
    
        private int createNodeId() {
            int nodeId;
            try {
                StringBuilder sb = new StringBuilder();
                Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
                while (networkInterfaces.hasMoreElements()) {
                    NetworkInterface networkInterface = networkInterfaces.nextElement();
                    byte[] mac = networkInterface.getHardwareAddress();
                    if (mac != null) {
                        for(int i = 0; i < mac.length; i++) {
                            sb.append(String.format("%02X", mac[i]));
                        }
                    }
                }
                nodeId = sb.toString().hashCode();
            } catch (Exception ex) {
                nodeId = (new SecureRandom().nextInt());
            }
            nodeId = nodeId & maxNodeId;
            return nodeId;
        }
    }
    

      

  • 相关阅读:
    Js获取当前日期时间及其它操作
    Java JDBC 基础知识
    java自动创建多级目录
    [Java]读取文件方法大全
    table固定首行(二)
    table固定首行(一)
    DIV滚动条
    查看本机开放的端口号,查看某个端口号是否被占用,查看被占用的端口号被哪个进程所占用,如何结束该进程
    DWZ SSH2 菜单树--使用Struts2 标签(iterator/set/if 组合使用)
    synchronized与lock,哪个效率更高
  • 原文地址:https://www.cnblogs.com/yytxdy/p/11387746.html
Copyright © 2011-2022 走看看