生成 UUID 的一致性哈希

5

我希望生成一个UUID字符串的一致性哈希,例如dcc549d8-bd0c-49c2-bff8-f6fa80fb7857,最好是一个0到N之间的数字。

怎样才能以最佳和最快的方式实现呢?

更新:我正在考虑使用CRC32。有什么利弊吗?

3个回答

6
您想要什么类型的哈希?选择“最佳”可能不是最快的,并且取决于您使用哈希的目的。
例如,对于md5,您可以执行以下操作:
var crypto = require('crypto');

var md5sum = crypto.createHash('md5');
md5sum.update(uuid);
var b64 = md5sum.digest('base64')

如果需要,您可以使用Base64库将其转换为数字。

Node加密模块提供了其他哈希算法,可能更适合您的情况(md5速度较快但不够安全)。文档链接:https://nodejs.org/api/crypto.html


我只需要在0-9之间的单个数字,以便我可以根据这个数字将x%的请求路由到不同的服务器。 - Madhur Ahuja
使用crc32怎么样? - Madhur Ahuja

5

如果考虑UUID的本质,可以看这个例子。 我会朝着这个方向去思考。

const INIT_NUMBER = 271;

function hash(uuid, N) {
  const x = uuid.split("-").reduce((a,b) => a ^ Number.parseInt(b, 16), INIT_NUMBER) ;
  return arguments.length === 1 ? x : x % N;
}

const a = hash("dcc549d8-bd0c-49c2-bff8-f6fa80fb7857");            
const b = hash("dcc549d8-bd0c-49c2-bff8-f6fa80fb7857", 256);

console.log(a, b);
  
  


1
如果您正在使用v4 UUID生成,除了两个数字以外,所有数字已经包含伪随机值,您只需要将它们提取到所需的形式即可。
从规范中可以看出:
4.4.  Algorithms for Creating a UUID from Truly Random or
      Pseudo-Random Numbers

   The version 4 UUID is meant for generating UUIDs from truly-random or
   pseudo-random numbers.

   The algorithm is as follows:

   o  Set the two most significant bits (bits 6 and 7) of the
      clock_seq_hi_and_reserved to zero and one, respectively.

   o  Set the four most significant bits (bits 12 through 15) of the
      time_hi_and_version field to the 4-bit version number from
      Section 4.1.3.

   o  Set all the other bits to randomly (or pseudo-randomly) chosen
      values.

为了提取伪随机值,我们只需删除由“ - ”分隔的第三和第四部分的第一个十六进制字符(其中包含4个最高有效位),并将其转换为所需的基数。由于UUID始终具有相同的长度,因此我们可以每次删除相同的索引(14和19)。
不幸的是,由于JavaScript只支持最多32位整数,我们需要将8个十六进制字符(32位)的Number.parseInt组分别输入,然后添加模数以最小化偏差。
因此,我们的代码如下:
function parseUUID(uuid, N) {
    var pseudorandomBytes = uuid.substring(0, 14) + uuid.substring(15, 19) + uuid.substring(20); // Splice out the bytes which contain metadata
    pseudorandomBytes = pseudorandomBytes.replace(/-/g, ""); // Remove all dashes
    var accumulator = 0; // Accumulate the sums modulo N of every eight hex characters and the remainder
    pseudorandomBytes.match(/.{1,8}/g).forEach(function (a) { accumulator = (accumulator + (Number.parseInt(a, 16) % N)) % N; });
    return accumulator; // Return the result
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接