वितरित क्रम संख्या जनरेशन?


103

मैंने आमतौर पर अतीत में डेटाबेस अनुक्रमों का उपयोग करके अनुक्रम संख्या पीढ़ी को लागू किया है।

उदा। क्रमिक प्रकारों का उपयोग करना http://www.neilconway.org/docs/fterences/

मैं उत्सुक हूं कि बड़े वितरित सिस्टम के लिए अनुक्रम संख्या कैसे उत्पन्न करें जहां कोई डेटाबेस नहीं है। किसी को भी कई ग्राहकों के लिए एक धागा सुरक्षित तरीके से अनुक्रम संख्या पीढ़ी प्राप्त करने के लिए सबसे अच्छा अभ्यास का कोई अनुभव या सुझाव है?


यह प्रश्न पुराना है, लेकिन pls मेरा नया उत्तर देखें stackoverflow.com/questions/2671858/…
जेस्पर एम

आप nextval.org का उपयोग कैसे करते हैं? वेबसाइट थोड़ी अजीब है और मुझे नहीं पता कि इसके बारे में क्या है। क्या यह कुछ यूनिक्स कमांड है? या कुछ क्लाउड सेवा?
डाईगोससव

जवाबों:


116

ठीक है, यह एक बहुत पुराना प्रश्न है, जिसे मैं पहली बार देख रहा हूं।

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

यूनिक आईडी एक और मामला है, विकेंद्रीकृत तरीके से यूनिक आईडी बनाने के कई अच्छे तरीके हैं:

a) आप ट्विटर की स्नोफ्लेक आईडी नेटवर्क सेवा का उपयोग कर सकते हैं । हिमपात का एक खंड है:

  • नेटवर्क सेवा, यानी आप एक अद्वितीय आईडी प्राप्त करने के लिए एक नेटवर्क कॉल करते हैं;
  • जो 64 बिट यूनिक आईडी का उत्पादन करता है जो कि पीढ़ी के समय के अनुसार आदेशित किया जाता है;
  • और सेवा अत्यधिक स्केलेबल है और (संभावित) अत्यधिक उपलब्ध है; प्रत्येक उदाहरण प्रति सेकंड कई हज़ार ID जनरेट कर सकता है, और आप अपने LAN / WAN पर कई इंस्टेंस चला सकते हैं;
  • स्काला में लिखा गया, जेवीएम पर चलता है।

बी) आप यूयूआईडी और स्नोफ्लेक आईडी से कैसे बना है , इस दृष्टिकोण का उपयोग करके, आप स्वयं ग्राहकों पर अद्वितीय आईडी तैयार कर सकते हैं। कई विकल्प हैं, लेकिन कुछ की तर्ज पर:

  • सबसे महत्वपूर्ण 40 या तो बिट्स: एक टाइमस्टैम्प; आईडी का पीढ़ी समय। (हम टाइमस्टैम्प के लिए सबसे महत्वपूर्ण बिट्स का उपयोग कर रहे हैं ताकि आईडी को पीढ़ी के समय के अनुसार क्रमबद्ध बनाया जा सके।)

  • अगले 14 या तो बिट्स: एक प्रति-जनरेटर काउंटर, जो प्रत्येक जेनरेटर प्रत्येक नई आईडी के लिए एक-एक करके बढ़ाता है। यह सुनिश्चित करता है कि एक ही पल में उत्पन्न आईडी (समान टाइमस्टैम्प) ओवरलैप न हों।

  • अंतिम 10 या तो बिट्स: प्रत्येक जनरेटर के लिए एक अद्वितीय मूल्य। इसका उपयोग करते हुए, हमें जनरेटर (जो कि अत्यंत कठिन है) के बीच कोई सिंक्रनाइज़ेशन करने की आवश्यकता नहीं है, क्योंकि सभी जनरेटर इस मान के कारण गैर-अतिव्यापी आईडी का उत्पादन करते हैं।

ग) आप ग्राहकों पर सिर्फ एक टाइमस्टैम्प और यादृच्छिक मूल्य का उपयोग करके आईडी बना सकते हैं यह सभी जनरेटर को जानने की आवश्यकता से बचता है, और प्रत्येक जनरेटर को एक अद्वितीय मूल्य प्रदान करता है। दूसरी तरफ, ऐसी आईडी की विश्व स्तर पर अद्वितीय होने की गारंटी नहीं है , वे केवल अद्वितीय होने की बहुत अधिक संभावना रखते हैं। (टकराने के लिए, एक या एक से अधिक जनरेटर को एक ही समय में एक ही यादृच्छिक मान बनाना होगा।) लाइनों के साथ कुछ:

  • सबसे महत्वपूर्ण 32 बिट्स: टाइमस्टैम्प, आईडी का पीढ़ी समय।
  • कम से कम महत्वपूर्ण 32 बिट्स: 32-बिट यादृच्छिकता, प्रत्येक आईडी के लिए नए सिरे से उत्पन्न।

घ) आसान तरीका है, UUIDs / GUID का उपयोग करें


कैसेंड्रा काउंटरों का समर्थन करता है ( cassandra.apache.org/doc/cql3/CQL.html#counters ), हालांकि कुछ सीमाएँ हैं।
पीयूष कंसल

अनुक्रम संख्या बिटमैप सूचकांक के लिए स्थिति निर्धारित करना आसान है, लेकिन अद्वितीय आईडी कभी-कभी बहुत लंबा (64 बिट या 128 बिट), बिटमैप सूचकांक स्थिति में अद्वितीय आईडी मैपिंग कैसे कर सकता है? धन्यवाद।
ब्रुकेन

2
वास्तव में पसंद किया गया विकल्प # बी ..... यह उच्च स्तर के लिए अनुमति दे सकता है और अधिक संगामिति के मुद्दे का कारण नहीं बन सकता है
प्यूनेट

2
twitter/snowflakeअब नहीं रखा गया है
नवीन

यदि आप विकल्प बी का अपाचे 2 लाइसेंस्ड कार्यान्वयन चाहते हैं, तो bitbucket.org/pythagorasio/common-lbooks/src/master/ पर देखें। आप इसे maven io.pythagoras.commonmon से भी प्राप्त कर सकते हैं: वितरित-अनुक्रम-आईडी-जनरेटर: 1.0 .0
22 अगस्त को वीपीगॉट

16

अब और विकल्प हैं।

यद्यपि यह प्रश्न "पुराना" है, मैं यहां गया, इसलिए मुझे लगता है कि मेरे (अब तक) ज्ञात विकल्पों को छोड़ना उपयोगी हो सकता है:

  • आप हेज़ेलकास्ट की कोशिश कर सकते हैं । 1.9 रिलीज में इसमें java.util.concurrent.AtomicLong का डिस्ट्रिब्यूटेड इम्प्लीमेंटेशन शामिल है
  • आप ज़ूकीपर का भी उपयोग कर सकते हैं । यह अनुक्रम नोड बनाने के लिए तरीके प्रदान करता है (znode नाम से जोड़ा जाता है, हालांकि मैं नोड्स के संस्करण संख्याओं का उपयोग करना पसंद करता हूं)। इस एक के साथ सावधान रहें: यदि आप अपने अनुक्रम में छूटी हुई संख्या नहीं चाहते हैं, तो यह वह नहीं हो सकता जो आप चाहते हैं।

चियर्स


3
ज़ुकीपर मेरे पास गए विकल्प थे, मेलिंग सूची पर इसका एक अच्छा विवरण और राइटअप है
जॉन

जॉन, उस धागे की ओर इशारा करने के लिए धन्यवाद, यह ठीक उसी प्रकार का समाधान है जो मैं सोच रहा था। BTW, क्या आपने MAX_INT सीमा को पार करने के लिए कोड बनाया था?
पाओलो

15

आपके पास प्रत्येक नोड में एक अद्वितीय आईडी हो सकती है (जो आपके पास वैसे भी हो सकती है) और फिर अनुक्रम संख्या में उसे प्रस्तुत करें।

उदाहरण के लिए, नोड 1 अनुक्रम 001-00001 001-00002 001-00003 आदि उत्पन्न करता है और नोड 5 005-00001 005-00002 उत्पन्न करता है।

अद्वितीय :-)

वैकल्पिक रूप से यदि आप किसी प्रकार की केंद्रीकृत प्रणाली चाहते हैं, तो आप अपने अनुक्रम सर्वर को ब्लॉक में देने पर विचार कर सकते हैं। यह ओवरहेड को काफी कम कर देता है। उदाहरण के लिए, प्रत्येक आईडी के लिए केंद्रीय सर्वर से एक नई आईडी का अनुरोध करने के बजाय जिसे सौंपा जाना चाहिए, आप केंद्रीय सर्वर से 10,000 के ब्लॉक में आईडी का अनुरोध करते हैं और उसके बाद केवल एक अन्य नेटवर्क अनुरोध करना होगा जब आप बाहर निकलते हैं।


1
मैं बैच आईडी पीढ़ी के बारे में अपनी बात पसंद करता हूं, लेकिन यह किसी भी वास्तविक समय की गणना की संभावना को सीमित करता है।
इशान

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

11

यह रेडिसन के साथ किया जा सकता है । यह वितरित और स्केलेबल संस्करण को लागू करता है AtomicLong। यहाँ उदाहरण है:

Config config = new Config();
config.addAddress("some.server.com:8291");

Redisson redisson = Redisson.create(config);
RAtomicLong atomicLong = redisson.getAtomicLong("anyAtomicLong");
atomicLong.incrementAndGet();

8

यदि यह वास्तव में विश्व स्तर पर अनुक्रमिक होना चाहिए, और केवल अद्वितीय नहीं है, तो मैं इन नंबरों के वितरण के लिए एक एकल, सरल सेवा बनाने पर विचार करूंगा।

वितरित सिस्टम बहुत सारी छोटी-छोटी सेवाओं के परस्पर क्रिया पर निर्भर हैं, और इस सरल प्रकार के कार्य के लिए, क्या आपको वास्तव में ज़रूरत है या आप वास्तव में किसी अन्य जटिल, वितरित समाधान से लाभान्वित होंगे?


3
... और क्या होता है जब उस सेवा को चलाने वाला सर्वर नीचे चला जाता है?
नवीन

एक चेतावनी है कि किसी को एक और एक शुरू करने के लिए कहता है? कभी-कभी यह ठीक होगा। मुझे लगता है कि उत्तर "चीजों को परिप्रेक्ष्य में रखने" की कोशिश कर रहा है। सही वितरित समाधान की अपनी कमियां हैं और कभी-कभी सरलता बेहतर होती है।
निक फेरियर

6

कुछ रणनीतियाँ हैं; लेकिन कोई भी नहीं जो मुझे पता है कि वास्तव में वितरित किया जा सकता है और एक वास्तविक अनुक्रम दे सकता है।

  1. एक केंद्रीय संख्या जनरेटर है। यह एक बड़ा डेटाबेस होना जरूरी नहीं है। memcachedएक तेज़ परमाणु काउंटर है, अधिकांश मामलों में यह आपके पूरे क्लस्टर के लिए पर्याप्त तेज़ है।
  2. प्रत्येक नोड के लिए एक पूर्णांक सीमा को अलग करें (जैसे स्टीवन श्लैंक्टर का उत्तर )
  3. यादृच्छिक संख्या या UUID का उपयोग करें
  4. नोड आईडी के साथ डेटा के कुछ टुकड़े का उपयोग करें, और यह सब हैश (या यह hmac )

व्यक्तिगत रूप से, मैं UUIDs के लिए दुबला हो जाऊंगा, या अगर मुझे ज्यादातर-सन्निहित स्थान चाहिए तो मेमेकैस्ट किया जाएगा।


5

UUID जनरेटर (थ्रेड सेफ) का उपयोग क्यों नहीं किया जाता है?

मुझे शायद इस पर विस्तार करना चाहिए।

UUIDs को विश्व स्तर पर अद्वितीय होने की गारंटी दी जाती है (यदि आप यादृच्छिक संख्याओं के आधार पर लोगों से बचते हैं, जहां विशिष्टता सिर्फ अत्यधिक संभावना है)।

आपकी "वितरित" आवश्यकता को पूरा किया जाता है, भले ही आप प्रत्येक यूयूआईडी की वैश्विक विशिष्टता द्वारा कितने यूयूआईडी जनरेटर का उपयोग करें।

आपकी "थ्रेड सेफ" आवश्यकता को "थ्रेड सेफ" यूयूआईडी जनरेटर चुनकर पूरा किया जा सकता है।

आपकी "अनुक्रम संख्या" की आवश्यकता को प्रत्येक UUID की वैश्विक विशिष्टता से पूरा किया जाना माना जाता है।

ध्यान दें कि कई डेटाबेस अनुक्रम संख्या कार्यान्वयन (जैसे ओरेकल) या तो नीरस वृद्धि की गारंटी नहीं देते हैं, या (यहां तक ​​कि) बढ़ते क्रम संख्या (प्रति "कनेक्शन" आधार पर)। ऐसा इसलिए है क्योंकि अनुक्रम संख्या का एक निरंतर बैच प्रति कनेक्शन के आधार पर "कैशेड" ब्लॉक में आवंटित किया जाता है। यह वैश्विक विशिष्टता की गारंटी देता है और पर्याप्त गति बनाए रखता है। लेकिन अनुक्रम संख्या वास्तव में आवंटित (समय के साथ) जब कई कनेक्शनों द्वारा आवंटित किए जा रहे हैं तो उन्हें उछाला जा सकता है!


1
जबकि यूयूआईडी काम करते हैं, उनके साथ समस्या यह है कि आपको सावधान रहना होगा कि आप उन्हें कैसे संग्रहीत करते हैं यदि आपको अंततः उत्पन्न की गई कुंजी को अनुक्रमित करने की आवश्यकता है। वे आमतौर पर एक नीरस रूप से बढ़े हुए अनुक्रम की तुलना में बहुत अधिक स्थान लेते हैं। MySQL के साथ उन्हें संग्रहीत करने के बारे में चर्चा के लिए percona.com/blog/2014/12/19/store-uuid-optimized-way देखें ।
पावेल

2

वितरित आईडी पीढ़ी को रेडिस और लुआ के साथ संग्रहीत किया जा सकता है। Github में उपलब्ध कार्यान्वयन । यह एक वितरित और k- छांटने वाली अनूठी आईडी बनाता है।


2

मुझे पता है कि यह एक पुराना सवाल है लेकिन हम भी उसी जरूरत का सामना कर रहे थे और उस समाधान को खोजने में असमर्थ थे जो हमारी जरूरत को पूरा करता है। हमारी आवश्यकता आईडी का एक अनूठा अनुक्रम (0,1,2,3 ... n) प्राप्त करना था और इसलिए बर्फ के टुकड़े ने मदद नहीं की। हमने रेडिस का उपयोग करके आईडी बनाने के लिए अपना सिस्टम बनाया। Redis सिंगल थ्रेडेड है इसलिए इसकी सूची / कतार तंत्र हमें हमेशा एक समय में 1 पॉप देगा।

हम क्या करते हैं, हम आईडी का एक बफर बनाते हैं, प्रारंभ में, कतार में 0 से 20 आईडी होंगे जो अनुरोध किए जाने पर भेजे जाने के लिए तैयार हैं। एकाधिक ग्राहक एक आईडी का अनुरोध कर सकते हैं और रेडिस एक बार में 1 आईडी पॉप करेगा, बाएं से प्रत्येक पॉप के बाद, हम बफ़र + करंट को दाईं ओर सम्मिलित करते हैं, जो बफर सूची को चालू रखता है। यहां क्रियान्वयन


0

मैंने एक साधारण सेवा लिखी है जो अर्ध-अद्वितीय गैर-क्रमिक 64 बिट लंबी संख्या उत्पन्न कर सकती है। यह अतिरेक और स्केलेबिलिटी के लिए कई मशीनों पर तैनात किया जा सकता है। यह मैसेजिंग के लिए ZeroMQ का उपयोग करता है। यह कैसे काम करता है इसके बारे में अधिक जानकारी के लिए जीथब पृष्ठ देखें: zUID


0

एक डेटाबेस का उपयोग करके आप एक कोर के साथ प्रति सेकंड 1.000 + वेतन वृद्धि तक पहुंच सकते हैं। यह बहुत आसान है। आप उस संख्या को उत्पन्न करने के लिए बैकेंड के रूप में अपने स्वयं के डेटाबेस का उपयोग कर सकते हैं (जैसा कि इसका अपना कुल होना चाहिए, डीडीडी शब्दों में)।

मेरे पास ऐसी ही समस्या थी। मेरे पास कई विभाजन थे और मैं प्रत्येक के लिए एक ऑफसेट काउंटर प्राप्त करना चाहता था। मैंने कुछ इस तरह से लागू किया:

CREATE DATABASE example;
USE example;
CREATE TABLE offsets (partition INTEGER, offset LONG, PRIMARY KEY (partition));
INSERT offsets VALUES (1,0);

फिर निम्नलिखित कथन को क्रियान्वित किया:

SELECT @offset := offset from offsets WHERE partition=1 FOR UPDATE;
UPDATE offsets set offset=@offset+1 WHERE partition=1;

यदि आपका आवेदन आपको अनुमति देता है, तो आप एक बार में एक ब्लॉक आवंटित कर सकते हैं (यह मेरा मामला था)।

SELECT @offset := offset from offsets WHERE partition=1 FOR UPDATE;
UPDATE offsets set offset=@offset+100 WHERE partition=1;

यदि आपको आगे थ्रूपुट की आवश्यकता है, तो आप अग्रिम में आबंटित नहीं कर सकते हैं, तो आप वास्तविक समय प्रसंस्करण के लिए फ्लिंक का उपयोग करके अपनी स्वयं की सेवा को लागू कर सकते हैं। मैं प्रति विभाजन लगभग 100K वेतन वृद्धि प्राप्त करने में सक्षम था।

आशा करता हूँ की ये काम करेगा!


0

यह समस्या समान है: इस्की दुनिया में, जहां ग्राहक की ओर से चल रहे सर्जक द्वारा प्रत्येक लून / वॉल्यूम को विशिष्ट रूप से पहचाना जाना चाहिए। Iscsi मानक कहता है कि पहले कुछ बिट्स को संग्रहण प्रदाता / निर्माता जानकारी का प्रतिनिधित्व करना होगा, और बाकी की मोनोटोनिक रूप से बढ़ रही है।

इसी तरह, कोई नोड्स की वितरित प्रणाली में नोड्स के प्रतिनिधित्व के लिए प्रारंभिक बिट्स का उपयोग कर सकता है और बाकी नीरस रूप से बढ़ सकता है।


1
कृपया कुछ और विवरण जोड़ें
वेद प्रकाश

0

एक समाधान जो सभ्य है, वह लंबे समय तक आधारित पीढ़ी का उपयोग करना है। यह एक वितरित डेटाबेस के समर्थन के साथ किया जा सकता है।

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