जावास्क्रिप्ट में UUIDs बनाते समय टकराव?


94

यह इस प्रश्न से संबंधित है । मैं जावास्क्रिप्ट में UUID उत्पन्न करने के लिए इस उत्तर से नीचे दिए गए कोड का उपयोग कर रहा हूं :

'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 उपयोगकर्ता।
  • इन उपयोगकर्ताओं द्वारा पिछले 2 महीनों में लगभग 4000 यूयूआईडी उत्पन्न किए गए हैं।
  • मुझे लगभग 20 टक्कर मिलीं - उदाहरण के तौर पर आज उत्पन्न नई यूयूआईडी लगभग 2 महीने पहले (अलग-अलग उपयोगकर्ता) जैसी थी।

इस मुद्दे के कारण क्या है और मैं इससे कैसे बच सकता हूं?


2
वर्तमान समय (मिलीसेकंड में) के साथ एक अच्छा यादृच्छिक संख्या मिलाएं। ठीक उसी समय टकराने वाली यादृच्छिक संख्या की संभावनाएं वास्तव में, वास्तव में, वास्तव में कम हैं।
jfriend00

7
@ jfriend00 अगर आपको ऐसा करने की आवश्यकता है, तो यह "अच्छा यादृच्छिक संख्या" नहीं है, एक सभ्य छद्म यादृच्छिक संख्या भी नहीं है।
Attila O.

2
(r&0x3|0x8)भाग का क्या अर्थ / मूल्यांकन है?
क्रिस्टियन

क्या एक Date.now () .String () इसे लागू करने के बारे में?
विटिमस

4
UUIDs से असंबंधित आपकी वास्तुकला में एक बड़ी समस्या है - क्लाइंट जानबूझकर टकराने वाली आईडी उत्पन्न कर सकता है। केवल एक प्रणाली पर भरोसा करें, जिस पर आप भरोसा करते हैं। हालांकि, वर्कअराउंड के रूप में, user_id के साथ क्लाइंट-जनरेटेड आईडी को प्रीपेन्ड करें, ताकि प्रतिकूल / दोषपूर्ण क्लाइंट केवल खुद से टकरा सकें (और सर्वर साइड पर इसे संभाल सकें)।
Dzmitry Lazerka

जवाबों:


35

मेरा सबसे अच्छा अनुमान है कि Math.random()किसी कारण से आपके सिस्टम पर टूट गया है (लगता है जैसे कि विचित्र)। यह पहली रिपोर्ट है जो मैंने किसी से टकराव होते हुए देखी है।

node-uuidएक परीक्षण दोहन है जिसका उपयोग आप उस कोड में हेक्स अंकों के वितरण का परीक्षण करने के लिए कर सकते हैं। अगर यह ठीक लग रहा है, तो यह नहीं है Math.random(), इसलिए फिर UUID कार्यान्वयन को प्रतिस्थापित करने का प्रयास करें जो आप uuid()वहां विधि में उपयोग कर रहे हैं और देखें कि क्या आपके पास अभी भी अच्छे परिणाम हैं।

[अद्यतन: बस स्टार्टअप पर बग के साथ वेसलिन की रिपोर्ट देखी Math.random()। चूंकि समस्या केवल स्टार्टअप पर है, node-uuidपरीक्षण उपयोगी होने की संभावना नहीं है। मैं devoluk.com लिंक पर अधिक विस्तार से टिप्पणी करूंगा।]


1
धन्यवाद, मैं अब uuid.js के साथ जा रहा हूं, क्योंकि यह उपलब्ध होने पर ब्राउज़र के मजबूत क्रिप्टो का उपयोग करता है। देखेंगे कि क्या कोई टक्कर है।
Muxa

क्या आप उस uuid.js कोड का लिंक प्रदान कर सकते हैं जिसका आप उल्लेख कर रहे हैं? (क्षमा करें, यह निश्चित नहीं है कि आपका कौन सा अर्थ है।)
ब्रूफ़

10
अब तक कोई टक्कर नहीं थी :)
Muxa

वैसे भी, अगर यह क्रोम है और केवल शुरुआत करते समय, आपका ऐप उत्पन्न हो सकता है और उपरोक्त फ़ंक्शन का उपयोग करते हुए, दस
गिड को त्याग सकता है

समस्या सीमित एन्ट्रापी के साथ है जो आपको Math.random () से मिलती है। कुछ ब्राउज़रों के लिए एन्ट्रापी सभी 41 बिट्स के समान कम है। Math.random () कॉलिंग कई बार एन्ट्रापी नहीं बढ़ाएगा। यदि आप वास्तव में अद्वितीय v4 UUID चाहते हैं, तो आपको एक क्रिप्टोग्राफिक रूप से मजबूत RNG का उपयोग करने की आवश्यकता है जो उत्पन्न प्रति UUID में कम से कम 122bit एन्ट्रापी का उत्पादन करती है।
म्लेच्छ

36

वास्तव में टकराव होते हैं लेकिन केवल Google Chrome के अंतर्गत। इस विषय पर मेरे अनुभव की जाँच करें

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

(लिंक 2019 तक टूट गया। पुरालेख लिंक: https://web.archive.org/web/20190121220947/http://devoluk.com/google-chrome-math-random-issue.html ।)

टकराव की तरह लगता है केवल Math.random की पहली कुछ कॉल पर होते हैं। यदि आप सिर्फ createGUID / testGUIDs विधि चलाते हैं, तो इसका कारण यह है (जो स्पष्ट रूप से मैंने पहली कोशिश की थी) यह बस बिना किसी टक्कर के काम करता है।

इसलिए Google Chrome को पुनरारंभ करने के लिए एक पूर्ण परीक्षा देने की आवश्यकता है, 32 बाइट उत्पन्न करें, Chrome को पुनरारंभ करें, जनरेट करें, पुनः आरंभ करें, जनरेट करें ...


2
यह बहुत चिंताजनक है - क्या किसी ने बग रिपोर्ट उठाई है?
UpTheCreek

1
विशेष रूप से जावास्क्रिप्ट में बेहतर यादृच्छिक संख्या जनरेटर के लिंक की तरह: baagoe.com/en/RandomMusings/javascript
Leopd

दुख की बात है कि लिंक अब टूट गया है :(
गस


7
अगर इस बग को संबोधित किया गया है तो क्या कोई पुष्टि कर सकता है?
Xdrone

20

बस इतना है कि अन्य लोगों को इसके बारे में पता चल सकता है - मैं यहां वर्णित UUID पीढ़ी तकनीक का उपयोग करके आश्चर्यजनक रूप से बड़ी संख्या में स्पष्ट टकरावों में भाग रहा था। मेरे यादृच्छिक संख्या जनरेटर के लिए बीजक के स्विच करने के बाद भी ये टकराव जारी रहे। इससे मुझे अपने बालों को तोड़ना पड़ा, जैसा कि आप कल्पना कर सकते हैं।

मैंने अंततः पता लगाया कि समस्या (लगभग?) विशेष रूप से Google के वेब क्रॉलर बॉट्स से जुड़ी थी। जैसे ही मैंने उपयोगकर्ता-एजेंट फ़ील्ड में "googlebot" के अनुरोधों को अनदेखा करना शुरू किया, टकराव गायब हो गए। मैं अनुमान लगा रहा हूं कि उन्हें जेएस लिपियों के परिणामों को कुछ अर्ध-बुद्धिमान तरीके से कैश करना होगा, जिसके अंतिम परिणाम के रूप में उनके स्पाइडरिंग ब्राउज़र को उस तरह से व्यवहार करने के लिए नहीं गिना जा सकता है जो सामान्य ब्राउज़र करते हैं।

सिर्फ एक FYI करें।


2
हमारे मेट्रिक्स सिस्टम के साथ एक ही मुद्दे में भाग गया। ब्राउज़र में सेशन आईडी जनरेट करने के लिए 'नोड-यूआईडी' मॉड्यूल का उपयोग करके हजारों यूयूआईडी टकराव देख रहा था। यह सभी के साथ googlebot था। धन्यवाद!
डोमकॉक

4

मैं इसे आपके प्रश्न के लिए एक टिप्पणी के रूप में पोस्ट करना चाहता था, लेकिन जाहिर तौर पर StackOverflow मुझे नहीं होने देगा।

मैंने अभी आपके द्वारा पोस्ट किए गए UUID एल्गोरिथ्म का उपयोग करके Chrome में 100,000 पुनरावृत्तियों का अल्पविकसित परीक्षण चलाया और कोई टक्कर नहीं मिली। यहाँ एक कोड स्निपेट है:

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

क्या आप सुनिश्चित हैं कि यहाँ कुछ और नहीं चल रहा है?


4
हां, मैंने कुछ स्थानीय परीक्षण भी चलाए और कोई टक्कर नहीं हुई। यूयूआईडी के बीच टकराव होता है जो विभिन्न उपयोगकर्ता की मशीनों पर उत्पन्न होते हैं। मुझे विभिन्न मशीनों पर कुछ डेटा उत्पन्न करने और टकरावों की जांच करने की आवश्यकता हो सकती है।
Muxa

2
इसके अलावा, मैंने देखा है कि टकराव UUIDs के बीच 3-4 सप्ताह के बीच उत्पन्न होते हैं।
Muxa

बहुत अजीब। आप किस प्लेटफॉर्म पर चल रहे हैं?
user533676

1
ऐसा लगता है कि V8 के Math.random () में इतनी बुनियादी कमी है, लेकिन ऐसा लगता है कि क्रोमियम 11 ने विंडो के साथ मजबूत यादृच्छिक संख्या उत्पादन के लिए समर्थन जोड़ा है। यदि आप इसके बजाय प्रयास करना चाहते हैं। Blog.chromium.org/2011/06/… देखें ।
user533676

विंडोज 7 और विंडोज एक्सपी के संयोजन पर चल रहा है।
Muxa

3

मूल रूप से इस UUID समाधान को पोस्ट करने वाले उत्तर को 2017-06-28 को अपडेट किया गया था:

Chrome डेवलपर्स का एक अच्छा लेख Chrome, Firefox, और Safari में Math.random PRNG गुणवत्ता की स्थिति पर चर्चा करता है। tl; dr - 2015 के अंत तक यह "बहुत अच्छा" है, लेकिन क्रिप्टोग्राफ़िक गुणवत्ता नहीं है। उस समस्या को हल करने के लिए, यहाँ उपरोक्त समाधान का एक अद्यतन संस्करण है जो ES6, cryptoAPI, और JS JSy का उपयोग करता है जिनका मैं क्रेडिट नहीं ले सकता :

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());


0

यहां जवाब "क्या समस्या पैदा कर रहा है?" (क्रोम Math.random बीज मुद्दा) लेकिन नहीं "मैं इसे कैसे बचा सकता है?"।

यदि आप अभी भी इस समस्या से बचने के लिए देख रहे हैं, तो मैंने इस उत्तर को कुछ समय पहले ही लिखा था कि इस सटीक समस्या के बारे में जानने के लिए ब्रूफा के कार्य को संशोधित किया जाए। यह टाइमस्टैम्प के एक हेक्स भाग द्वारा पहले 13 हेक्स संख्याओं को ऑफसेट करके काम करता है, जिसका अर्थ है कि भले ही Math.random एक ही बीज पर है, यह तब भी एक अलग UUID उत्पन्न करेगा जब तक कि सटीक एक ही मिलीसेकंड पर उत्पन्न न हो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.