Computer >> कंप्यूटर >  >> प्रोग्रामिंग >> Ruby

रेल छिपे हुए रत्न:सक्रिय समर्थन कैश वृद्धि और कमी

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

इस लेख में, हम increment . के बारे में बताएंगे और decrement Rails.cache . में विधियां ।

रेल.कैश हेल्पर

Rails.cache आपके आवेदन में कैश के साथ बातचीत करने का प्रवेश मार्ग है। यह एक अमूर्तता भी है, जो आपको हुड के तहत उपयोग किए जा रहे वास्तविक कैश "स्टोर" की परवाह किए बिना कॉल करने के लिए एक सामान्य एपीआई देता है। लीक से हटकर, रेल निम्नलिखित का समर्थन करती है:

  • फाइलस्टोर
  • मेमोरीस्टोर
  • मेम कैशेस्टोर
  • नलस्टोर
  • RedisCacheStore

Rails.cache का निरीक्षण करना दिखाएगा कि आप किसे चला रहे हैं:

> Rails.cache
=> <#ActiveSupport::Cache::RedisCacheStore options={:namespace=>nil, ...

हम उन सभी को विस्तार से नहीं देखेंगे, लेकिन एक त्वरित सारांश के रूप में:

  • NullStore कुछ भी स्टोर नहीं करता है; इससे वापस पढ़ना हमेशा nil लौटाएगा . यह एक नए रेल ऐप के लिए डिफ़ॉल्ट है।
  • फाइलस्टोर कैश को हार्ड ड्राइव पर फाइलों के रूप में संग्रहीत करता है, इसलिए यदि आप अपने रेल सर्वर को पुनरारंभ करते हैं तो भी वे बने रहते हैं।
  • मेमोरीस्टोर कैश को रैम में रखता है, इसलिए यदि आप अपना रेल सर्वर बंद कर देते हैं, तो आप कैश को भी मिटा देंगे।
  • MemCacheStore और RedisCacheStore कैश को बनाए रखने के लिए बाहरी प्रोग्राम (क्रमशः MemCache और Redis) का उपयोग करते हैं।

विभिन्न कारणों से, यहां पहले तीन का उपयोग अक्सर विकास/परीक्षण के लिए किया जाता है। उत्पादन में, आप संभवतः Redis या MemCache का उपयोग करेंगे।

क्योंकि Rails.cache इन सेवाओं के बीच अंतर को दूर करता है, कोड को बदले बिना विभिन्न वातावरणों में विभिन्न संस्करणों को चलाना आसान है; उदाहरण के लिए, आप NullStore . का उपयोग कर सकते हैं विकास में, MemoryStore परीक्षण में, और RedisCacheStore उत्पादन में।

संचित डेटा

रेल के माध्यम से Rails.cache.read , Rails.cache.write , और Rails.cache.fetch , हमारे पास कैश से किसी भी मनमाने डेटा को संग्रहीत और पुनर्प्राप्त करने का एक आसान तरीका है। पहले के एक लेख में इन्हें और अधिक विस्तार से कवर किया गया था; इस लेख के लिए ध्यान देने योग्य महत्वपूर्ण बात यह है कि इन विधियों पर कोई अंतर्निहित थ्रेड-सुरक्षा नहीं है। मान लें कि हम चल रहे काउंट को बनाए रखने के लिए कैश्ड डेटा को कई थ्रेड्स से अपडेट कर रहे हैं; दौड़ की स्थिति से बचने के लिए हमें किसी प्रकार के लॉक में पढ़ने/लिखने के संचालन को लपेटने की आवश्यकता होगी। इस उदाहरण पर विचार करें, मान लें कि हमने रेडिस कैश स्टोर का उपयोग करने के लिए चीजों को सेट अप किया है:

threads = []
# Set initial counter
Rails.cache.write(:test_counter, 0)

4.times do
  threads << Thread.new do
    100.times do 
      current_count = Rails.cache.read(:test_counter)
      current_count += 1
      Rails.cache.write(:test_counter, current_count)
    end
  end
end

threads.map(&:join)

puts Rails.cache.read(:test_counter)

यहां हमारे पास चार धागे हैं, प्रत्येक एक हमारे कैश्ड मान को सौ गुना बढ़ा रहा है। परिणाम 400 होना चाहिए, लेकिन ज्यादातर समय, यह बहुत कम होगा - मेरे टेस्ट रन पर 269। यहाँ जो हो रहा है वह एक दौड़ की स्थिति है। मैंने पिछले लेख में इन्हें और अधिक विस्तार से कवर किया था, लेकिन एक त्वरित सारांश के रूप में, क्योंकि सभी थ्रेड्स एक ही "साझा" डेटा पर काम कर रहे हैं, वे एक दूसरे के साथ सिंक से बाहर हो सकते हैं। उदाहरण के लिए, एक थ्रेड मान को पढ़ सकता है, फिर दूसरा थ्रेड मान लेता है और मान को भी पढ़ता है, इसे बढ़ाता है, और इसे संग्रहीत करता है। पहला थ्रेड फिर से शुरू हो जाता है, इसके पुराने मान का उपयोग करते हुए।

इस समस्या को हल करने का सामान्य तरीका कोड को पारस्परिक रूप से अनन्य लॉक (या म्यूटेक्स) के साथ घेरना है ताकि एक समय में केवल एक थ्रेड लॉक के भीतर कोड निष्पादित कर सके। हमारे मामले में, हालांकि, इस परिदृश्य को संभालने के लिए Rails.cache के पास कुछ तरीके हैं।

रेल कैश इंक्रीमेंट और डिक्रीमेंट

Rails.cache ऑब्जेक्ट में increment both दोनों हैं और decrement हमारे काउंटर परिदृश्य जैसे कैश्ड डेटा पर सीधे कार्य करने के तरीके:

  threads = []
  # Set initial counter
  Rails.cache.write(:test_counter, 0, raw: true)

  4.times do
    threads << Thread.new do
      100.times do 
        Rails.cache.increment(:test_counter)
        # repeating the increment just to highlight the thread safety
        Rails.cache.decrement(:test_counter)
        Rails.cache.increment(:test_counter)
      end
    end
  end

  threads.map(&:join)

  puts Rails.cache.read(:test_counter, raw: true)

increment का उपयोग करने के लिए और decrement , हमें कैश स्टोर को बताना होगा कि यह एक 'कच्चा' मान है (raw: true . के माध्यम से) ) मूल्य को वापस पढ़ते समय भी आपको ऐसा करना होगा; अन्यथा, आपको एक त्रुटि मिलेगी। मूल रूप से, हम कैश को बता रहे हैं कि हम चाहते हैं कि यह मान एक नंगे पूर्णांक के रूप में संग्रहीत हो ताकि हम उस पर वृद्धि/कमी कह सकें, लेकिन आप अभी भी expires_in का उपयोग कर सकते हैं और अन्य कैश फ़्लैग एक ही समय में।

यहाँ कुंजी यह है कि increment और decrement परमाणु संचालन (कम से कम Redis और MemCache के लिए) का उपयोग करें, जिसका अर्थ है कि वे थ्रेड सुरक्षित हैं; परमाणु संचालन के दौरान धागे के रुकने का कोई तरीका नहीं है।

यह ध्यान देने योग्य है, हालाँकि मैंने यहाँ अपने उदाहरण में इसका उपयोग नहीं किया है, कि दोनों विधियाँ भी नया मान लौटाती हैं। इसलिए, यदि आपको नए काउंटर वैल्यू को केवल अपडेट करने के अलावा उपयोग करने की आवश्यकता है, तो आप अतिरिक्त read के बिना भी ऐसा कर सकते हैं। कॉल करें।

रियल-वर्ल्ड ऐप्लिकेशन

इसके चेहरे पर, ये increment और decrement विधियां निम्न-स्तरीय सहायक विधियों की तरह प्रतीत होती हैं, जिस तरह से आप शायद केवल तभी परवाह करते हैं जब आप पृष्ठभूमि नौकरी प्रसंस्करण मणि की तरह कुछ कार्यान्वित या बनाए रखते हैं। हालाँकि, एक बार जब आप उनके बारे में जान जाते हैं, तो आपको आश्चर्य हो सकता है कि वे कहाँ काम आ सकते हैं।

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

इसे रोकने के लिए, हमने अनुसूचित नौकरियों के लिए एक आधार वर्ग बनाया है जो इस बात का काउंटर रखता है कि कितने वर्तमान में चल रहे हैं। यदि गिनती बहुत अधिक है, तो कार्य बस फिर से कतारबद्ध हो जाता है और प्रतीक्षा करता है।

एक अन्य उदाहरण मेरा एक साइड-प्रोजेक्ट था जहां उपयोगकर्ता को प्रतीक्षा करने के दौरान पृष्ठभूमि नौकरी (या एकाधिक नौकरियां) कुछ प्रसंस्करण करती है। यह पृष्ठभूमि कार्य के उपयोगकर्ता को वर्तमान प्रगति को संप्रेषित करने के सामान्य मुद्दे को सामने लाता है। हालांकि इसे कई तरीकों से हल किया जा सकता है, एक प्रयोग के रूप में, मैंने Rails.cache.increment का उपयोग करने का प्रयास किया। विश्व स्तर पर उपलब्ध काउंटर को अद्यतन करने के लिए। संरचना इस प्रकार थी:

  1. सबसे पहले, मैंने /app/models में एक नया वर्ग जोड़ा है इस तथ्य को दूर करने के लिए कि काउंटर कैश में रहता था। यह वह जगह है जहां मूल्य तक सभी पहुंच प्रवाहित होगी। इसका एक हिस्सा कार्य से संबंधित अद्वितीय कैश कुंजी उत्पन्न कर रहा है।
  2. कार्य तब इस मॉडल का एक उदाहरण बनाता है और आइटम संसाधित होते ही इसे अपडेट कर देता है।
  3. एक साधारण JSON एंडपॉइंट वर्तमान मान को हथियाने के लिए इस मॉडल का एक उदाहरण बनाता है।
  4. यूआई को अपडेट करने के लिए फ्रंट-एंड इस एंडपॉइंट को हर कुछ सेकंड में पोल ​​करता है। बेशक, आप एक्शनकेबल जैसी किसी चीज़ के साथ इस प्रशंसक को बना सकते हैं और अपडेट को पुश आउट कर सकते हैं।

निष्कर्ष

ईमानदारी से, Rails.cache.increment ऐसा उपकरण नहीं है जिसके लिए मैं अक्सर पहुंचूंगा, क्योंकि ऐसा अक्सर नहीं होता है कि मैं कैश में संग्रहीत डेटा को अपडेट करना चाहता हूं (जो स्वभाव से, कुछ हद तक अस्थायी है)। जैसा कि ऊपर उल्लेख किया गया है, मैं जिस समय तक पहुंचता हूं वह आम तौर पर पृष्ठभूमि की नौकरियों से संबंधित होता है क्योंकि नौकरियां पहले से ही रेडिस में अपना डेटा संग्रहीत कर रही हैं (कम से कम अधिकांश ऐप में मैंने काम किया है) और आम तौर पर अस्थायी भी हैं। ऐसे मामलों में, संबंधित डेटा (उदाहरण के लिए पूर्ण प्रतिशत) को समान स्तर की अल्पकालिक दृढ़ता के साथ एक ही स्थान पर संग्रहीत करना स्वाभाविक लगता है।

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


  1. रेल रत्नों को कैसे संभालती है?

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

  1. रेल और कैरियरवेव के साथ अपलोड करना

    यह अपलोडिंग विद रेल्स श्रृंखला का एक और लेख है। आज हम कैरियरवेव से मिलने जा रहे हैं - रेल के लिए सबसे लोकप्रिय फ़ाइल अपलोडिंग समाधानों में से एक। मुझे कैरियरवेव पसंद है क्योंकि इसे शुरू करना आसान है, इसमें बहुत सारी विशेषताएं हैं, और यह समुदाय के सदस्यों द्वारा लिखे गए दर्जनों कैसे करें लेख प्रदान क

  1. Windows 11 युक्तियाँ और छिपे हुए रत्न जिन्हें आपको जानना चाहिए

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