像新浪那种不定位数的数字的UID,Node.js有啥好方法生成,求推荐

像新浪那种不定位数的数字的UID,Node.js有啥好方法生成,求推荐

小弟对这方面毫无经验,希望得到指导

6 回复

当然可以!像新浪这样的公司通常会使用一种高效的分布式ID生成算法来生成不定位数的数字UID。其中比较知名的是Twitter的Snowflake算法。Snowflake算法能够生成全局唯一的64位整数ID,并且具备高性能、高可用性和分布式特性。

Snowflake算法的特点:

  1. 唯一性:生成的ID在整个系统中是唯一的。
  2. 趋势递增:生成的ID是递增的,便于排序和分页。
  3. 无状态:服务节点无需存储额外信息即可生成ID。

示例代码

以下是一个基于Snowflake算法的Node.js实现:

class Snowflake {
    constructor(datacenterId, workerId) {
        this.twepoch = 1288834974657n; // 起始时间戳
        this.workerIdBits = 5n;
        this.datacenterIdBits = 5n;
        this.maxWorkerId = -1n ^ (-1n << this.workerIdBits);
        this.maxDatacenterId = -1n ^ (-1n << this.datacenterIdBits);
        this.sequenceBits = 12n;

        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.sequence = 0n;
        this.lastTimestamp = -1n;

        if (this.workerId > this.maxWorkerId || this.workerId < 0) {
            throw new Error(`worker Id can't be greater than ${this.maxWorkerId} or less than 0`);
        }
        if (this.datacenterId > this.maxDatacenterId || this.datacenterId < 0) {
            throw new Error(`datacenter Id can't be greater than ${this.maxDatacenterId} or less than 0`);
        }
    }

    static create(workerId, datacenterId) {
        return new Snowflake(workerId, datacenterId);
    }

    nextId() {
        let timestamp = this.timeGen();

        if (timestamp < this.lastTimestamp) {
            throw new Error(`Clock moved backwards.  Refusing to generate id for ${this.lastTimestamp - timestamp} milliseconds`);
        }

        if (this.lastTimestamp === timestamp) {
            this.sequence = (this.sequence + 1n) & (-(1n) << this.sequenceBits);
            if (this.sequence === 0n) {
                timestamp = this.tilNextMillis(this.lastTimestamp);
            }
        } else {
            this.sequence = 0n;
        }

        this.lastTimestamp = timestamp;

        return ((timestamp - this.twepoch) << (this.datacenterIdBits + this.workerIdBits + this.sequenceBits)) |
               (this.datacenterId << (this.workerIdBits + this.sequenceBits)) |
               (this.workerId << this.sequenceBits) |
               this.sequence;
    }

    timeGen() {
        return BigInt(Date.now());
    }

    tilNextMillis(lastTimestamp) {
        let timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }
}

// 使用示例
const snowflake = Snowflake.create(1, 1);
console.log(snowflake.nextId()); // 输出一个64位的唯一ID

解释

  • twepoch 是起始时间戳,用于计算相对于起始时间的时间差。
  • workerIddatacenterId 用于区分不同的工作节点和服务节点,确保ID的全局唯一性。
  • sequence 用于在同一毫秒内生成多个ID。

通过上述代码,你可以生成全局唯一的64位数字ID。这种方法适用于需要高效、唯一ID生成的场景,比如用户ID、订单ID等。


exports.uid = function(len) {
  return crypto.randomBytes(Math.ceil(len * 3 / 4))
    .toString('base64')
    .slice(0, len)
    .replace(/\//g, '-')
    .replace(/\+/g, '_');
};

在 connect 代码里看到得。

额,这个是有字母的啦,希望能找到一个纯数字的。。

我们在用一种叫fnv的hash算法,生成结果是纯数字的 LZ可以找找有没有js的实现。

twitter有个id生成策略叫做snowflakes ,我在用它的java版,还不错。这里是它的node版本

对于生成类似新浪那样的不定位数的数字UID,Node.js 提供了多种方案。一种常见的方法是使用分布式ID生成器,比如Twitter的Snowflake算法。Snowflake算法可以生成全局唯一的64位整数ID,并且能够保证在分布式环境下的唯一性。

下面提供一个简单的Snowflake实现示例,以便你理解如何生成这样的ID:

class Snowflake {
    constructor(workerId, datacenterId) {
        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.sequence = 0;

        // 时间起始标记点,作为基准,一般取系统的最近时间(当前时间减去固定的时间偏移)
        this.twepoch = 1288834974657n;

        // 工作机器ID占用的位数
        this.workerIdBits = 5n;
        // 数据中心ID占用的位数
        this.datacenterIdBits = 5n;
        // 序列号占用的位数
        this.sequenceBits = 12n;

        // 最大工作机器ID
        this.maxWorkerId = -1n ^ (-1n << this.workerIdBits);
        // 最大数据中心ID
        this.maxDatacenterId = -1n ^ (-1n << this.datacenterIdBits);

        // 序列号的最大值
        this.sequenceMask = -1n ^ (-1n << this.sequenceBits);

        // 工作机器ID向左移动的位数
        this.workerIdShift = this.sequenceBits;
        // 数据中心ID向左移动的位数
        this.datacenterIdShift = this.sequenceBits + this.workerIdBits;
        // 时间戳向左移动的位数
        this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.datacenterIdBits;

        // 上次生成ID的时间戳
        this.lastTimestamp = -1n;
    }

    async nextId() {
        let timestamp = this.timeGen();

        if (timestamp < this.lastTimestamp) {
            throw new Error(`Clock moved backwards. Refusing to generate id for ${this.lastTimestamp - timestamp} milliseconds`);
        }

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

    timeGen() {
        return BigInt(Date.now());
    }

    tilNextMillis(lastTimestamp) {
        let timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }
}

// 使用示例
const snowflake = new Snowflake(1, 1);
snowflake.nextId().then(id => console.log(id.toString()));

在这个例子中,Snowflake类负责生成64位的唯一ID。你需要传入workerIddatacenterId参数来标识不同的工作节点和数据中心。每次调用nextId方法时,它会生成一个新的ID。注意这里的ID生成策略适用于分布式系统,如果是在单机环境下使用,可以选择更简单的方案。

这个算法确保了生成的ID在全球范围内的唯一性,非常适合需要生成大量唯一标识符的应用场景。

回到顶部