2008-09-18 50 views
51

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

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

समाधान मैं धारणात्मक के साथ toyed है कर रहे हैं:

  1. "ताला" ग्राहक के आधार पर फ़ाइलें जो प्रत्येक मशीन द्वारा के लिए जाँच की जाएगी बनाने के लिए हमारी गलती सहिष्णु साझा फाइल सिस्टम का उपयोग करना

  2. हमारे डेटाबेस में एक विशेष तालिका का उपयोग करके, और लॉक रिकॉर्ड के लिए "परीक्षण-और-सेट" करने के लिए पूरी तालिका को लॉक करना।

  3. टेराकोटा, एक खुला स्रोत सर्वर सॉफ्टवेयर जो स्केलिंग करने में सहायता करता है, लेकिन एक हब और स्पोक मॉडल का उपयोग करता का उपयोग करना।

  4. मेरे इन-स्मृति की समकालिक प्रतिकृति के लिए ehcache का उपयोग करना "ताले।"

मैं कल्पना नहीं कर सकता कि मैं अकेला व्यक्ति हूं जिसने कभी इस तरह की समस्या की है। आपने इसे कैसे ठीक किया? क्या आपने घर में कुछ खाना पकाया था या क्या आपके पास पसंदीदा 3-पार्टी उत्पाद है?

+0

परीक्षण-और-सेट की बजाय, यह सुनिश्चित करने की ज़िम्मेदारी क्या हो सकती है कि कोई भी डुप्लिकेट सेवा में स्थानांतरित न हो जो नए ग्राहकों को बनाता है? –

उत्तर

33

आप Hazelcast वितरित ताले का उपयोग करने पर विचार करना चाहेंगे। सुपर लाइट और आसान।

java.util.concurrent.locks.Lock lock = Hazelcast.getLock ("mymonitor"); 
lock.lock(); 
try { 
// do your stuff 
}finally { 
    lock.unlock(); 
} 

Hazelcast - वितरित कतार, मानचित्र, सेट, सूची, लॉक

+0

यह बिल्कुल वही अर्थशास्त्र है जो मैं अपने (असफल) घर से उगाए गए समाधान के साथ उपयोग करने का प्रयास कर रहा था। मैं उत्सुक हूं कि मैं इसे अपने आप क्यों नहीं ढूंढ पाया, लेकिन टिप के लिए धन्यवाद! –

+0

ऐसा लगता है कि एपीआई अब बदल गया है। इसे देखें http://hazelcast.org/docs/3.2/javadoc/com/hazelcast/core/class-use/ILock.html –

-1

वापस दिन में, हम इस संभाल करने के लिए नेटवर्क पर एक विशिष्ट "लॉक सर्वर" का उपयोग करेंगे। Bleh।

आपके डेटाबेस सर्वर में विशेष रूप से इस तरह की चीज करने के लिए संसाधन हो सकते हैं। MS-एसक्यूएल सर्वर आवेदन ताले sp_getapplock/sp_releaseapplock प्रक्रियाओं के माध्यम से प्रयोग करने योग्य है।

0

मैंने दो विधियों के साथ एक साधारण आरएमआई सेवा बनाई: लॉक और रिलीज़। दोनों विधियां एक कुंजी लेती हैं (मेरा डेटा मॉडल यूयूआईडी को पीके के रूप में इस्तेमाल करता है ताकि वह लॉकिंग कुंजी भी हो)।

RMI इस क्योंकि यह केंद्रीकृत है के लिए एक अच्छा उपाय है। आप इसे ईजेबी के साथ नहीं कर सकते (विशेष रूप से क्लस्टर में क्योंकि आप नहीं जानते कि आपकी कॉल किस मशीन पर होगी)। इसके अलावा, यह आसान है।

यह मेरे लिए काम करता है।

1

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

मैं जोड़ता हूं कि किसी भी आधे सभ्य बहु-नोड नेटवर्क आधारित लॉकिंग तंत्र को किसी भी नेटवर्क विफलता की स्थिति में सही तरीके से कार्य करने के लिए उचित परिष्कृत होना होगा।

1

सुनिश्चित नहीं है कि मैं पूरे संदर्भ को समझता हूं लेकिन ऐसा लगता है कि आपके पास 1 एकल डेटाबेस का बैकिंग है? डेटाबेस लॉकिंग का उपयोग क्यों न करें: यदि ग्राहक बनाना एक एकल INSERT है तो अकेले यह कथन लॉक के रूप में कार्य कर सकता है क्योंकि डेटाबेस एक दूसरे आईएनएसईआरटी को अस्वीकार कर देगा जो आपकी बाधाओं का उल्लंघन करेगा (उदाहरण के लिए ग्राहक का नाम है उदाहरण के लिए अद्वितीय)।

यदि "ग्राहक डालने" ऑपरेशन परमाणु नहीं है और बयानों का एक बैच है तो मैं प्रारंभिक INSERT का परिचय (या उपयोग) करता हूं जो आपके ग्राहक को पहचानने के लिए कुछ सरल मूल रिकॉर्ड बनाता है (आवश्यक अद्वितीय बाधाओं के साथ) और फिर उसी लेनदेन में अन्य सभी आवेषण/अपडेट करें। फिर डेटाबेस स्थिरता का ख्याल रखेगा और किसी भी समवर्ती संशोधन के परिणामस्वरूप उनमें से एक विफल हो जाएगा।

+1

मैं क्षमा चाहता हूं, मुझे पता है कि मेरा "प्रश्न" दुनिया में सबसे स्पष्ट नहीं था - ईएसबी सेवाओं के माध्यम से बातचीत कर रहा है, इसलिए हमारे पास बाधाओं पर कोई नियंत्रण नहीं है। अगर उनके ग्राहक मौजूद हैं तो मुझे सेवाओं के माध्यम से पूछना होगा, और फिर यदि ऐसा नहीं होता है तो एक बनाने का एक अलग अनुरोध करें। –

+1

क्या आप सवाल अपडेट कर सकते हैं? –

4

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

किसी भी मामले में आपको शायद पता है कि टेराकोटा आपको क्लस्टर में समेकन व्यक्त करने की क्षमता देता है, वैसे ही आप पीओजेओ सिंक्रनाइज़/प्रतीक्षा/अधिसूचना का उपयोग करके या किसी भी java.util.concurrent का उपयोग करके एक एकल JVM में करते हैं Primentives जैसे ReentrantReadWriteLock, CyclicBarrier, AtomicLong, FutureTask और इसी तरह।

Terracotta Cookbook में इन प्राइमेटिव्स के उपयोग का प्रदर्शन करने वाली बहुत सी सरल व्यंजन हैं।

एक उदाहरण के रूप में, मैं ReentrantReadWriteLock उदाहरण पोस्ट करेंगे (ध्यान दें कि वहाँ ताला का कोई "टेराकोटा" संस्करण है - तुम सिर्फ सामान्य जावा ReentrantReadWriteLock का उपयोग)

import java.util.concurrent.locks.*; 

public class Main 
{ 
    public static final Main instance = new Main(); 
    private int counter = 0; 
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(true); 

    public void read() 
    { 
     while (true) { 
      rwl.readLock().lock(); 
       try { 
       System.out.println("Counter is " + counter); 
      } finally { 
       rwl.readLock().unlock(); 
      } 
      try { Thread.currentThread().sleep(1000); } catch (InterruptedException ie) { } 
     } 
    } 

    public void write() 
    { 
     while (true) { 
      rwl.writeLock().lock(); 
      try { 
       counter++; 
       System.out.println("Incrementing counter. Counter is " + counter); 
      } finally { 
       rwl.writeLock().unlock(); 
      } 
      try { Thread.currentThread().sleep(3000); } catch (InterruptedException ie) { } 
     } 
    } 

    public static void main(String[] args) 
    { 
     if (args.length > 0) { 
      // args --> Writer 
      instance.write(); 
     } else { 
      // no args --> Reader 
      instance.read(); 
     } 
    } 
} 
+2

आपको 'Thread.current थ्रेड के बजाय' Thread.sleep (...) 'का उपयोग करना चाहिए()। नींद (...) 'क्योंकि यह एक स्थिर विधि है; आपका कोड आपको 'someOtherThread.sleep (...)' करने के लिए प्रेरित कर सकता है जो 'कुछ अन्य थ्रेड' नहीं सोता है। – newacct

13

हम टेराकोटा उपयोग करते हैं, तो मैं चाहते हैं इसके लिए वोट दें।

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

लेकिन मैंने जकीपर के बारे में भी सुना है, जो याहू से बाहर आया था, और हैडोप छाता के नीचे जा रहा है। यदि आप कुछ नई तकनीक की कोशिश कर रहे साहसी हैं, तो वास्तव में बहुत सारे वादे हैं क्योंकि यह बहुत दुबला और मतलब है, जो समन्वय पर ध्यान केंद्रित करते हैं। मुझे दृष्टि और वादा पसंद है, हालांकि यह अभी भी बहुत हरा हो सकता है।

+1

मैं यह देखने में असफल रहा कि क्यों Hazelcase पी 2 पी का उपयोग करता है यह बड़े पैमाने पर उपयोग के लिए अविश्वसनीय बना देगा। पी 2 पी लॉकिंग की स्केलेबिलिटी के बारे में चिंता का जिक्र करने के लिए – Dunaril

+0

+1। @ डुनरिल इस बारे में सोचें कि लॉक जारी किए जाने के बारे में कितने नोड्स को अधिसूचित किया जाना चाहिए। बेवकूफ मामले में यह एक एन वर्ग की समस्या है (cluster_size^2): प्रत्येक नोड को हर दूसरे नोड पर जारी ताले के बारे में अधिसूचित करने की आवश्यकता है। अभ्यास में शेरिंग या कोरम इन समस्याओं में कमी कर सकते हैं, लेकिन फिर भी यह एक कठिन समस्या है और पुस्तकालय विज्ञापन "प्लग और प्ले" प्रयोज्यता इसे हल करने की संभावना नहीं है! पी 2 पी लॉकिंग में उलटा स्केलेबिलिटी है: प्रदर्शन * गिरावट * अतिरिक्त नोड्स जोड़े गए हैं। – npgall

2

मैं लॉग रखने के लिए एक बहुत तेज, वितरित रैम भंडारण के रूप में memcached का उपयोग करने पर सलाह के लिए जा रहा था; लेकिन ऐसा लगता है कि ईएच कैश एक समान परियोजना है लेकिन अधिक जावा केंद्रित है।

किसी भी तरह से जाने का तरीका है, जब तक आप परमाणु अद्यतनों का उपयोग करना सुनिश्चित करते हैं (memcached उन्हें समर्थन करता है, EHCache के बारे में नहीं जानते)। यह अब तक का सबसे स्केलेबल समाधान है।

संबंधित डेटापॉइंट के रूप में, Google बिगटेबल के बीच कई प्रणालियों की जड़ के रूप में एक तेज़, रैम-आधारित वितरित लॉक स्टोरेज 'चबबी' का उपयोग करता है।

0

यदि आप अपना लोड संतुलन सेट अप कर सकते हैं ताकि एक ग्राहक के लिए अनुरोध हमेशा एक ही सर्वर पर मैप हो जाएं तो आप स्थानीय सिंक्रनाइज़ेशन के माध्यम से इसे संभाल सकते हैं। उदाहरण के लिए, 10 नोड्स का उपयोग करने के लिए अपने ग्राहक आईडी मोड 10 को लें।

भले ही आप सामान्य मामले में ऐसा नहीं करना चाहते हैं, तो भी आपके नोड इस विशिष्ट प्रकार के अनुरोध के लिए एक दूसरे के लिए प्रॉक्सी कर सकते हैं।

मान लें कि आपके उपयोगकर्ता पर्याप्त हैं (यानी यदि आपके पास उनमें से एक टन है) तो आप गर्म स्पॉट को पॉप अप करने की अपेक्षा नहीं करते हैं जहां एक नोड अधिभारित हो जाता है, यह अभी भी बहुत अच्छी तरह से स्केल होना चाहिए।

-5

हम एक ओपन सोर्स, वितरित सिंक्रनाइज़ेशन फ्रेमवर्क विकसित कर रहे हैं, वर्तमान में वितरित रेनेंट्रंट लॉक और वितरित रेन्टेंट्रेट रीडवाइट लॉक लागू किया गया है, लेकिन अभी भी परीक्षण और रिफैक्टरिंग चरण में हैं। हमारे आर्किटेक्चर लॉक कुंजियों में बाल्टी में विचलित होते हैं और प्रत्येक नोड बाल्टी की कुछ संख्या के लिए resonsible है। सफल लॉक अनुरोधों के लिए प्रभावी रूप से, केवल एक नेटवर्क अनुरोध है। हम स्थानीय लॉक स्टेटस के रूप में AbstractQueuedSynchronizer क्लास का भी उपयोग कर रहे हैं, इसलिए सभी असफल लॉक अनुरोध स्थानीय रूप से संभाले जाते हैं, इससे नेटवर्क ट्रैफिक कम हो जाता है। हम समूह संचार और सीरियलाइजेशन के लिए हेसियन के लिए जेग्रुप (http://jgroups.org) का उपयोग कर रहे हैं। विवरण के लिए

, कृपया http://code.google.com/p/vitrit/ देखें।

कृपया मुझे अपनी मूल्यवान प्रतिक्रिया भेजें।

कामरान

+4

आपके क्लाइंट को इस सर्वर से यूआरएल/पी/विट्रिट/प्राप्त करने की अनुमति नहीं है – stepancheg

0

तुम भी Cacheonix वितरित ताले के लिए सोच सकते हैं।

ReadWriteLock rwLock = Cacheonix.getInstance().getCluster().getReadWriteLock(); 
Lock lock = rwLock.getWriteLock(); 
try { 
    ... 
} finally { 
    lock.unlock(); 
} 

पूर्ण प्रकटीकरण: कुछ और यहाँ उल्लेख Cacheonix ताला वृद्धि के साथ ReadWrite ताले का समर्थन जब जरूरत लिखने के लिए पढ़ा से विपरीत मैं एक Cacheonix डेवलपर हूँ।

3

मैं Redisson का उपयोग करने की सलाह देता हूं। यह java.util.Lock सहित 30 वितरित डेटा संरचनाओं और सेवाओं को लागू करता है।प्रयोग उदाहरण:

JdbcSemaphore semaphore = new JdbcSemaphore(ds, semName, maxReservations); 
boolean acq = semaphore.acquire(acquire, 1, TimeUnit.MINUTES); 
if (acq) { 
// do stuff 
semaphore.release(); 
} else { 
    throw new TimeoutException(); 
} 

यह spf4j पुस्तकालय का हिस्सा है:

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

Lock lock = redisson.getLock("anyLock"); 
lock.lock(); 
try { 
    ... 
} finally { 
    lock.unlock(); 
} 

redisson.shutdown(); 
+0

मैं रेडिस को लॉकिंग सेवा के रूप में उपयोग नहीं करता, कोई रास्ता नहीं: http://aphyr.com/posts/283-call-me-maybe -redis –

+0

@mbonaci लॉक ऑब्जेक्ट समवर्ती परीक्षण है और इसे हर बार पास करता है। एंटीरेज़ से इस http://antirez.com/news/55 अद्यतन का एक एंटीरज़ उत्तर यहां दिया गया है: इस बीच रेडिस सेंटीनेल वास्तुकला और कार्यान्वयन में काफी बदलाव आया, इसके अलावा रेडिस की एक विशेषता को लिखना बंद करना लिखता है यदि पर्याप्त जुड़े गुलाम नहीं हैं जोड़ा गया था, इसलिए मूल रूप से सेंटिनल का उपयोग करके एक बेहतर प्रकार की स्थिरता गारंटी तक पहुंचना संभव है। –

+0

मुझे पता है, और यहां एफ़िर की पुनरीक्षण redis और उन ([और अधिक हालिया] (http://antirez.com/news/66)) antirez की टिप्पणियां/whimps: http://aphyr.com/posts/307-call- मुझे शायद-redis-redux। Redis, जब सेंटिनल के साथ जोड़ा, कैशिंग के लिए केवल अच्छा है। सत्र भंडारण सर्वोत्तम (गैर-महत्वपूर्ण वातावरण में)। जब तक इसके मॉडल की समीक्षा नहीं की जाती है, वह है। –

0

के बाद से आप पहले से ही एक और बुनियादी टुकड़ा जोड़ने से पहले एक डेटाबेस से कनेक्ट कर रहे हैं, JdbcSemaphore पर एक नज़र डालें, तो यह प्रयोग आसान है ।

संबंधित मुद्दे