• Twitter开源分布式自增ID算法snowflake


    分布式唯一ID

    一、UUID

    优点

    * 生成ID性能非常好

    * 简单,代码方便

    * 全球唯一

    缺点

    *  uuid没有顺序,不能保证自增

    * 太长,使用字符串存储,作为主键建立索引查询效率低

    二、snowflake 雪花算法

    18位 数字

    算法:通过时间戳 + 机器码 + 序列码

    数据库用 bigint 只占8个字节

    代码:

    public class IdWorker {
        //protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);
        
        private long workerId;
        private long datacenterId;
        private long sequence = 0L;
     
        private long twepoch = 1288834974657L;
     
        private long workerIdBits = 5L;
        private long datacenterIdBits = 5L;
        private long maxWorkerId = -1L ^ (-1L << workerIdBits);
        private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
        private long sequenceBits = 12L;
     
        private long workerIdShift = sequenceBits;
        private long datacenterIdShift = sequenceBits + workerIdBits;
        private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
        private long sequenceMask = -1L ^ (-1L << sequenceBits);
     
        private long lastTimestamp = -1L;
     
        public IdWorker(long workerId, long datacenterId) {
            // sanity check for workerId
            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;
           // LOG.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));
        }
     
        public synchronized long nextId() {
            long timestamp = timeGen();
     
            if (timestamp < lastTimestamp) {
               // LOG.error(String.format("clock is moving backwards.  Rejecting requests until %d.", 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();
        }
    }

    调用

    IdWorker idWorker1 = new IdWorker(1,0);
                
                for (int i = 0; i < 20; i++) {
                    long id = idWorker1.nextId();
                    System.out.println(id);
            }
  • 相关阅读:
    JavaScript在Javascript中为String对象添加trim,ltrim,rtrim方法
    JavaScriptjs写的俄罗斯方块
    WinForm中“嵌入的资源”和“资源文件”数据的获取方式
    Facade模式(外观模式)
    windows服务安装程序中如何安装后自动启动
    水晶报表之主从多表数据源批量预览及打印开发设计
    IP地址分类简介
    水晶报表之各节的作用
    水晶报表开发之常用代码以及注意事项
    .Net中后台线程和前台线程的区别
  • 原文地址:https://www.cnblogs.com/lyon91/p/8919319.html
Copyright © 2020-2023  润新知