Столкновения при генерации UUID-ы на JavaScript?
Это относится к этот вопрос. Я использую ответ для создания UUID в 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);
});
Это решение, казалось, работает нормально, однако я получаю столкновения. Вот что у меня есть:
- веб-приложение, работающее в Google Chrome.
- 16 пользователей.
- около 4000 UUIDs были созданы за последние 2 месяца этими пользователями.
- я получил около 20 столкновений - например, новый UUID genereated сегодня был таким же, как и около 2 месяцев назад (другой пользователь).
Так вопросы являются:
- что вызывает проблему?
- как я могу избежать этого?
5 ответов:
Я думаю, что это
Math.random()сломленн на вашей системе по какой-то причине (странно как то звучит). Это первый отчет, который я видел о том, что кто-то получает столкновения.
node-uuidесть тестирование что вы можете использовать для проверки распределения шестнадцатеричных цифр в этом коде. Если это выглядит нормально, то это неMath.random(), поэтому попробуйте заменить реализацию UUID, которую вы используете вuuid()метод там и посмотреть, если вы все еще получаете хорошо результаты.[обновление: только что видел отчет Веселина об ошибке с
Math.random()при запуске. Так как проблема только при запуске, тоnode-uuidтест вряд ли будет полезен. Я прокомментирую более подробно на тему devoluk.com линк.]
действительно есть коллизии, но только под Google Chrome. Проверьте мой опыт по этой теме здесь
http://devoluk.com/google-chrome-math-random-issue.html
кажется, что столкновения происходят только на первых нескольких вызовах математики.случайность. Потому что если вы просто запустите метод createGUID / testGUIDs выше (что, очевидно, было первым, что я попробовал), он просто работает без каких-либо коллизий.
так, чтобы сделать полный тест нужно перезапустите Гугл Хром, генерируют 32 байта, перезагрузите хром, создать, перезагрузить, создать...
просто чтобы другие люди могли знать об этом - я столкнулся с удивительно большим количеством очевидных столкновений, используя технику генерации UUID, упомянутую здесь. Эти столкновения продолжались даже после того, как я переключился на seedrandom для моего генератора случайных чисел. Меня рвет на себе волосы, как вы можете себе представить.
Я в конце концов понял, что проблема была (почти?) исключительно связанные с веб-гусеничных ботов Google. Как только я начал игнорируя запросы с "googlebot" в поле user-agent, коллизии исчезли. Я предполагаю, что они должны кэшировать результаты сценариев JS каким-то полуинтеллектуальным способом, с конечным результатом, что их браузер-паук не может рассчитывать на то, чтобы вести себя так, как это делают обычные браузеры.
просто FYI.
Я хотел опубликовать это как комментарий к вашему вопросу, но, видимо, StackOverflow не позволит мне.
Я только что провел рудиментарный тест из 100 000 итераций в Chrome, используя алгоритм UUID, который вы опубликовали, и не получил никаких столкновений. Вот фрагмент кода:
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);
ответ это первоначально опубликованное решение UUID было обновлено на 2017-06-28:
A хорошая статья от разработчиков Chrome обсуждение состояния математики.случайное качество PRNG в Chrome, Firefox и Safari. tl;dr-по состоянию на конец 2015 года это "довольно хорошее", но не криптографическое качество. Чтобы решить эту проблему, вот обновленная версия вышеуказанного решения, которое использует ES6,
cryptoAPI, и немного JS wizardy я не могу взять кредит для: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());
Comments