zoukankan      html  css  js  c++  java
  • JS 雪花算法生成随机 ID

    生成一个随机的 ID 有很多种做法,比如说 GUID 和 UUID。但如果想要有序,可以插入数据库中做数字主键,那就有了雪花算法。雪花算法得到的是个比较大的数字,比较大,而 JS 中 Number 类型的最大值 Number.MAX_SAFE_INTEGER:9007199254740991,那这样运算会溢出。所幸的是网上有很多 BigInt 的类库,现在 ES10 标准就包括了它,并且 Chrome 67 也实现了支持。

    原理

    下图出自理解分布式id生成算法

    SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图:

    代码

    var Snowflake = (function() {
        function Snowflake(_workerId, _dataCenterId, _sequence) {
            this.twepoch = 1288834974657n;
            //this.twepoch = 0n;
            this.workerIdBits = 5n;
            this.dataCenterIdBits = 5n;
            this.maxWrokerId = -1n ^ (-1n << this.workerIdBits); // 值为:31
            this.maxDataCenterId = -1n ^ (-1n << this.dataCenterIdBits); // 值为:31
            this.sequenceBits = 12n;
            this.workerIdShift = this.sequenceBits; // 值为:12
            this.dataCenterIdShift = this.sequenceBits + this.workerIdBits; // 值为:17
            this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.dataCenterIdBits; // 值为:22
            this.sequenceMask = -1n ^ (-1n << this.sequenceBits); // 值为:4095
            this.lastTimestamp = -1n;
            //设置默认值,从环境变量取
            this.workerId = 1n;
            this.dataCenterId = 1n;
            this.sequence = 0n;
            if (this.workerId > this.maxWrokerId || this.workerId < 0) {
                throw new Error('_workerId must max than 0 and small than maxWrokerId-[' + this.maxWrokerId + ']');
            }
            if (this.dataCenterId > this.maxDataCenterId || this.dataCenterId < 0) {
                throw new Error('_dataCenterId must max than 0 and small than maxDataCenterId-[' + this.maxDataCenterId + ']');
            }
    
            this.workerId = BigInt(_workerId);
            this.dataCenterId = BigInt(_dataCenterId);
            this.sequence = BigInt(_sequence);
        }
        Snowflake.prototype.tilNextMillis = function(lastTimestamp) {
            var timestamp = this.timeGen();
            while (timestamp <= lastTimestamp) {
                timestamp = this.timeGen();
            }
            return BigInt(timestamp);
        };
        Snowflake.prototype.timeGen = function() {
            return BigInt(Date.now());
        };
        Snowflake.prototype.nextId = function() {
            var timestamp = this.timeGen();
            if (timestamp < this.lastTimestamp) {
                throw new Error('Clock moved backwards. Refusing to generate id for ' +
                    (this.lastTimestamp - timestamp));
            }
            if (this.lastTimestamp === timestamp) {
                this.sequence = (this.sequence + 1n) & this.sequenceMask;
                if (this.sequence === 0n) {
                    timestamp = this.tilNextMillis(this.lastTimestamp);
                }
            } else {
                this.sequence = 0n;
            }
            this.lastTimestamp = timestamp;
            return ((timestamp - this.twepoch) << this.timestampLeftShift) |
                (this.dataCenterId << this.dataCenterIdShift) |
                (this.workerId << this.workerIdShift) |
                this.sequence;
        };
        return Snowflake;
    }());
    

    注意代码中的 this.twepoch = 1288834974657n;。如果 ((timestamp - 1288834974657) << 32) 超过long类型数据范围,怎么办?可以保证69年不超,1288834974657这个初始值是可以设置的。

    使用如下

    console.time();
    var tempSnowflake = new Snowflake(1n, 1n, 0n);
    var tempIds = [];
    for (var i = 0; i < 10000; i++) {
        var tempId = tempSnowflake.nextId();
        console.log(tempId);
        if (tempIds.indexOf(tempId) < 0) {
            tempIds.push(tempId);
        }
    }
    console.log(tempIds.length);
    console.timeEnd();
    

    附录-GUID/UUID

    原文:https://www.cnblogs.com/snandy/p/3261754.html

    全局唯一标识符(GUID,Globally Unique Identifier)也称作 UUID(Universally Unique IDentifier) 。

    GUID是一种由算法生成的二进制长度为128位的数字标识符。GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中的 x 是 0-9 或 a-f 范围内的一个32位十六进制数。在理想情况下,任何计算机和计算机集群都不会生成两个相同的GUID。

    GUID 的总数达到了2128(3.4×1038)个,所以随机生成两个相同GUID的可能性非常小,但并不为0。GUID一词有时也专指微软对UUID标准的实现。

    function guid() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r&0x3 | 0x8);
            return v.toString(16);
        });
    }
    

    由于在Java中64bit的整数是long类型,所以在Java中SnowFlake算法生成的id就是long来存储的。

    SnowFlake可以保证:

    • 所有生成的id按时间趋势递增
    • 整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)
  • 相关阅读:
    Java之事件处理
    Java之图形程序设计
    小议设置path环境变量
    关于JAVA中的编译和解释执行
    并发工具类 CountDownLatch
    线程池
    Properties的小问题
    转换流
    TCP中客户端和服务器的理解
    leetcode_160. 相交链表
  • 原文地址:https://www.cnblogs.com/everlose/p/12855745.html
Copyright © 2011-2022 走看看