Collisions when generating UUIDs in JavaScript?

2019-01-08 04:43发布

This relates to this question. I am using this answer to generate UUID in JavaScript:

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

This solution appeared to be working fine, however i am getting collisions. Here's what i have:

  • A web-app running in Google Chrome.
  • 16 users.
  • about 4000 UUIDs have been generated in the past 2 months by these users.
  • i got about 20 collisions - e.g. new UUID genereated today was the same as about 2 months ago (different user).

So the questions are:

  1. What's causing the issue?
  2. How can i avoid it?

5条回答
戒情不戒烟
2楼-- · 2019-01-08 05:01

The answer that originally posted this UUID solution was updated on 2017-06-28:

A good article from Chrome developers discussing the state of Math.random PRNG quality in Chrome, Firefox, and Safari. tl;dr - As of late-2015 it's "pretty good", but not cryptographic quality. To address that issue, here's an updated version of the above solution that uses ES6, the crypto API, and a bit of JS wizardy I can't take credit for:

function uuidv4() {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  )
}

console.log(uuidv4());

查看更多
甜甜的少女心
3楼-- · 2019-01-08 05:02

I wanted to post this as a comment to your question, but apparently StackOverflow won't let me.

I just ran a rudimentary test of 100,000 iterations in Chrome using the UUID algorithm you posted and got no collisions. Here's a code snippet:

var createGUID = function() {
    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);
    });
}

var testGUIDs = function(upperlimit) {
    alert('Doing collision test on ' + upperlimit + ' GUID creations.');
    var i=0, guids=[];
    while (i++<upperlimit) {
        var guid=createGUID();
        if (guids.indexOf(guid)!=-1) {
            alert('Collision with ' + guid + ' after ' + i + ' iterations');
        }
        guids.push(guid);
    }
    alert(guids.length + ' iterations completed.');
}

testGUIDs(100000);

Are you sure there isn't something else going on here?

查看更多
\"骚年 ilove
4楼-- · 2019-01-08 05:07

Indeed there are collisions but only under Google Chrome. Check out my experience on the topic here

http://devoluk.com/google-chrome-math-random-issue.html

Seems like collisions only happen on the first few calls of Math.random. Cause if you just run the createGUID / testGUIDs method above (which obviously was the first thing I tried) it just works with no collisions whatsoever.

So to make a full test one needs to restart Google Chrome, generate 32 byte, restart Chrome, generate, restart, generate...

查看更多
Melony?
5楼-- · 2019-01-08 05:22

My best guess is that Math.random() is broken on your system for some reason (bizarre as that sounds). This is the first report I've seen of anyone getting collisions.

node-uuid has a test harness that you can use to test the distribution of hex digits in that code. If that looks okay then it's not Math.random(), so then try substituting the UUID implementation you're using into the uuid() method there and see if you still get good results.

[Update: Just saw Veselin's report about the bug with Math.random() at startup. Since the problem is only at startup, the node-uuid test is unlikely to be useful. I'll comment in more detail on the devoluk.com link.]

查看更多
我只想做你的唯一
6楼-- · 2019-01-08 05:22

Just so that other folks can be aware of this - I was running into a surprisingly large number of apparent collisions using the UUID generation technique mentioned here. These collisions continued even after I switched to seedrandom for my random number generator. That had me tearing my hair out, as you can imagine.

I eventually figured out that the problem was (almost?) exclusively associated with Google's web crawler bots. As soon as I started ignoring requests with "googlebot" in the user-agent field, the collisions disappeared. I'm guessing that they must cache the results of JS scripts in some semi-intelligent way, with the end result that their spidering browser can't be counted on to behave the way that normal browsers do.

Just an FYI.

查看更多
登录 后发表回答