像新浪那种不定位数的数字的UID,Node.js有啥好方法生成,求推荐
像新浪那种不定位数的数字的UID,Node.js有啥好方法生成,求推荐
小弟对这方面毫无经验,希望得到指导
当然可以!像新浪这样的公司通常会使用一种高效的分布式ID生成算法来生成不定位数的数字UID。其中比较知名的是Twitter的Snowflake算法。Snowflake算法能够生成全局唯一的64位整数ID,并且具备高性能、高可用性和分布式特性。
Snowflake算法的特点:
- 唯一性:生成的ID在整个系统中是唯一的。
- 趋势递增:生成的ID是递增的,便于排序和分页。
- 无状态:服务节点无需存储额外信息即可生成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
是起始时间戳,用于计算相对于起始时间的时间差。workerId
和datacenterId
用于区分不同的工作节点和服务节点,确保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。你需要传入workerId
和datacenterId
参数来标识不同的工作节点和数据中心。每次调用nextId
方法时,它会生成一个新的ID。注意这里的ID生成策略适用于分布式系统,如果是在单机环境下使用,可以选择更简单的方案。
这个算法确保了生成的ID在全球范围内的唯一性,非常适合需要生成大量唯一标识符的应用场景。