दूसरे दिन HB टीम चैट कर रही थी और बेन, हमारे देव-ऑप्स मास्टर, ने उल्लेख किया कि वह चाहता है कि उसने एक विशेष प्रणाली के लिए UUID के बजाय ULIDs का उपयोग किया होता।
किसी भी अनुभवी इंजीनियर की तरह, मेरी प्रतिक्रिया कुछ गैर-प्रतिबद्ध बड़बड़ाना था फिर गूगल पर चुपके से यह पता लगाने के लिए कि आखिर ULID क्या है।
दो घंटे बाद मैं हजार-यार्ड स्टेयर और इस अहसास के साथ उभरा कि यूनिक आइडेंटिफायर्स की दुनिया मेरी कल्पना से कहीं अधिक बड़ी और अद्भुत है।
ULIDs के साथ शुरू करने से पहले, आइए मूल बातों पर वापस जाएं और चर्चा करें कि UUID क्या हैं:
"रेगुलर" IDs के साथ क्या समस्या है?
डेटाबेस का उपयोग करने वाले अधिकांश वेब एप्लिकेशन डिफ़ॉल्ट रूप से संख्यात्मक IDs का उपयोग करते हैं जो स्वचालित रूप से बढ़ते हैं। उदाहरण के लिए, Rails में आप ऐसा व्यवहार देख सकते हैं:
p1 = Person.create!
p1.id # => 1
p2 = Person.create!
p2.id # => 2
डेटाबेस एक काउंटर संग्रहीत करके अनुक्रमिक IDs उत्पन्न कर सकता है जो रिकॉर्ड निर्माण पर बढ़ता है।
यह पैटर्न डेटाबेस के बाहर भी देखा जा सकता है। कभी-कभी हमें मैन्युअल रूप से IDs असाइन करने की आवश्यकता होती है, और हम एक कस्टम काउंटर को स्टोर कर सकते हैं - कहते हैं - एक Redis इंस्टेंस में।
अनुक्रमिक IDs कम-वॉल्यूम उपयोग-मामलों के लिए लागू करना आसान है, लेकिन जैसे-जैसे वॉल्यूम बढ़ता है वे अधिक समस्याग्रस्त हो जाते हैं:
- रिकॉर्ड्स को समवर्ती रूप से बनाना असंभव है क्योंकि प्रत्येक इंसर्ट को अपना ID प्राप्त करने के लिए लाइन में इंतजार करना पड़ता है।
- अनुक्रमिक ID का अनुरोध करने के लिए नेटवर्क राउंड ट्रिप की आवश्यकता हो सकती है और धीमे प्रदर्शन का परिणाम हो सकता है।
- अनुक्रमिक IDs प्रदान करने वाले डेटा स्टोर्स को स्केल आउट करना मुश्किल है। आपको अलग-अलग सर्वरों पर काउंटर्स के आउट ऑफ सिंक होने की चिंता करनी होगी।
- काउंटर वाला नोड विफलता का एकल बिंदु बन जाना आसान है।
अनुक्रमिक IDs डेटा भी लीक करते हैं, जो कुछ मामलों में समस्या हो सकती है:
- आप आसानी से उन संसाधनों के IDs का अनुमान लगा सकते हैं जो आपके नहीं हो सकते।
- यदि आप एक यूज़र बनाते हैं और उसकी ID 20 है, तो आप जानते हैं कि सेवा के 20 यूज़र्स हैं।
UUIDs वेब-स्केल हैं
UUIDs अनुक्रमिक IDs से थोड़े अलग दिखते हैं। वे 128-बिट संख्याएं हैं, आमतौर पर 32 हेक्साडेसिमल अंकों के रूप में व्यक्त की जाती हैं:
123e4567-e89b-12d3-a456-426655440000
UUIDs RFC 4122 में परिभाषित विशिष्ट एल्गोरिदम का उपयोग करके बनाए जाते हैं। वे अनुक्रमिक IDs के साथ होने वाली कई समस्याओं को हल करने का प्रयास करते हैं:
- आप किसी भी संख्या में नोड्स पर UUIDs उत्पन्न कर सकते हैं बिना किसी शेयर्ड स्टेट या नोड्स के बीच समन्वय के।
- वे अनुक्रमिक IDs की तुलना में थोड़े कम अनुमान योग्य हैं (बाद में इस पर अधिक)
- वे आपके डेटासेट के आकार का खुलासा नहीं करते।
पकड़ यह है कि दो नोड्स द्वारा स्वतंत्र रूप से वही ID उत्पन्न करने की एक छोटी सी संभावना है। इस घटना को "टकराव" कहा जाता है।
UUID के कई स्वाद
RFC 4122 में UUID एल्गोरिदम के पांच प्रकार परिभाषित हैं। वे दो श्रेणियों में आते हैं:
- समय और यादृच्छिकता-आधारित एल्गोरिदम वे हैं जिन पर हम चर्चा कर रहे हैं। वे हर रन के लिए एक नया UUID परिणाम देते हैं।
- टाइप 4: एक रैंडमली-जनरेटेड ID। शायद नए कोड के लिए हमारा सबसे अच्छा विकल्प।
- टाइप 1: ID में होस्ट का MAC एड्रेस और वर्तमान टाइमस्टैम्प होता है। ये डिप्रिकेटेड हैं क्योंकि वे अनुमान लगाने में बहुत आसान हैं।
- टाइप 2: ये असामान्य प्रतीत होते हैं। वे RPC के एक पुराने रूप के लिए उद्देश्य-निर्मित प्रतीत होते हैं।
- नाम-आधारित एल्गोरिदम थोड़े अलग हैं। वे दिए गए इनपुट के सेट के लिए हमेशा वही UUID उत्पन्न करते हैं।
- टाइप 5: UUID उत्पन्न करने के लिए SHA-1 हैश का उपयोग करता है। अनुशंसित।
- टाइप 3: MD5 हैश का उपयोग करता है और डिप्रिकेटेड है क्योंकि MD5 बहुत असुरक्षित है।
Ruby में, आप uuidtools जेम के माध्यम से UUIDs उत्पन्न कर सकते हैं। यह रहस्यमयी टाइप 2 को छोड़कर हर टाइप का समर्थन करता है;
# uuidtools readme से कोड चुराया गया। :)
require "uuidtools"
# टाइप 1
UUIDTools::UUID.timestamp_create
# => #<UUID:0x2adfdc UUID:64a5189c-25b3-11da-a97b-00c04fd430c8>
# टाइप 4
UUIDTools::UUID.random_create
# => #<UUID:0x19013a UUID:984265dc-4200-4f02-ae70-fe4f48964159>
# टाइप 3
UUIDTools::UUID.md5_create(UUIDTools::UUID_DNS_NAMESPACE, "www.widgets.com")
# => #<UUID:0x287576 UUID:3d813cbb-47fb-32ba-91df-831e1593ac29>
# टाइप 5
UUIDTools::UUID.sha1_create(UUIDTools::UUID_DNS_NAMESPACE, "www.widgets.com")
# => #<UUID:0x2a0116 UUID:21f7f8de-8051-5b89-8680-0195ef798b6a>
ULIDs की ओर बढ़ना
नोट: इस ब्लॉग पोस्ट के मूल संस्करण में मैं ULID स्पेक से लिंक करना भूल गया था। यहां यह है। यह Ruby और अन्य भाषाओं में कार्यान्वयन के लिंक प्रदान करता है।
ULIDs यूनिक आइडेंटिफायर्स पर एक उपयोगी नया दृष्टिकोण है। सबसे स्पष्ट अंतर यह है कि वे थोड़े अलग दिखते हैं:
01ARZ3NDEKTSV4RRFFQ69G5FAV
वे दो बेस32-एन्कोडेड संख्याओं से बने होते हैं; एक यूनिक्स टाइमस्टैम्प उसके बाद एक रैंडम नंबर। यहाँ संरचना है, जैसा कि विनिर्देश में परिभाषित किया गया है:
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
टाइमस्टैम्प रैंडमनेस
48बिट्स 80बिट्स
यह संरचना आकर्षक है! यदि आप याद करते हैं, तो UUIDs या तो टाइमस्टैम्प या यादृच्छिकता पर भरोसा करते हैं, लेकिन ULIDs दोनों टाइमस्टैम्प और यादृच्छिकता का उपयोग करते हैं।
परिणामस्वरूप, ULIDs के कुछ दिलचस्प गुण हैं:
- वे लेक्सिकोग्राफिकली (यानी, वर्णानुक्रम में) सॉर्टेबल हैं।
- टाइमस्टैम्प मिलीसेकंड तक सटीक है
- वे UUIDs से सुंदर हैं :)
ये कुछ शानदार संभावनाएं खोलते हैं:
- यदि आप अपने डेटाबेस को तारीख के अनुसार पार्टीशन कर रहे हैं, तो आप सही पार्टीशन का चयन करने के लिए ULID में एम्बेडेड टाइमस्टैम्प का उपयोग कर सकते हैं।
- यदि मिलीसेकंड सटीकता स्वीकार्य है तो आप अलग created_at कॉलम के बजाय ULID द्वारा सॉर्ट कर सकते हैं।
कुछ संभावित नकारात्मक पहलू भी हैं:
- यदि आपके एप्लिकेशन के लिए टाइमस्टैम्प को उजागर करना एक बुरा विचार है, तो ULIDs सबसे अच्छा विकल्प नहीं हो सकते हैं।
ULID द्वारा सॉर्टदृष्टिकोण काम नहीं कर सकता है यदि आपको सब-मिलीसेकंड सटीकता की आवश्यकता है।- इंटरनेट के अनुसार, कुछ ULID कार्यान्वयन बुलेटप्रूफ नहीं हैं।
निष्कर्ष
UUIDs मानक हैं और बने रहेंगे। वे हमेशा से रहे हैं, और हर कल्पनीय भाषा में लाइब्रेरी उपलब्ध हैं। हालांकि, नए दृष्टिकोण विचार करने योग्य हैं, विशेष रूप से जब हम एक ऐसी दुनिया में प्रवेश करते हैं जो तेजी से डिस्ट्रिब्यूटेड सिस्टम द्वारा चलाई जाती है। नए यूनिक-ID दृष्टिकोण उन समस्याओं को हल करने में हमारी मदद कर सकते हैं जो RFC4122 के प्रकाशन के समय प्रचलित नहीं थीं।