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

जटिल डेटा मॉडल को कैश करने का एक तेज़ तरीका

जब आपका डेटा मॉडल जटिल हो जाता है, और आपके एपीआई उस दु:खद 1 सेकंड प्रतिक्रिया समय पर हिट करते हैं, तो आमतौर पर एक आसान समाधान होता है::includes . जब आप अपने मॉडल की संबद्धता को प्रीलोड करते हैं, तो आप उतनी SQL कॉल नहीं करेंगे। और इससे आपका बहुत सारा समय बच सकता है।

लेकिन फिर आपकी साइट धीमी हो जाती है, और आप कैशिंग प्रतिक्रियाओं के बारे में सोचते हैं। और अब आपको समस्या है। क्योंकि अगर आप कैशे से प्रतिक्रिया प्राप्त करना चाहते हैं:

results = {lawyer_1: 1, lawyer_2: 2, lawyer_3: 3}
cached_objects = Rails.cache.fetch_multi(results.keys) do |key|
  Lawyer.find(results[key]).as_json
end

अब आप अपना सारा :includes . खो चुके हैं . क्या आपके पास दोनों हो सकते हैं? आप अपने कैश्ड ऑब्जेक्ट के लिए तेज़ प्रतिक्रिया कैसे प्राप्त करते हैं, और फिर भी उन ऑब्जेक्ट्स को जल्दी से लोड कैसे करते हैं जो कैश में नहीं हैं?

करने के लिए बहुत कुछ है, इसलिए इसके बारे में सोचना कठिन है। जब आप समस्या को छोटे-छोटे टुकड़ों में बांटते हैं, और एक आसान अगले चरण के साथ आते हैं तो यह आसान हो जाता है।

तो आप सबसे पहले क्या कर सकते हैं? कुछ भी करने के लिए, आपको यह जानना होगा कि आपके कैश में कौन सी वस्तुएं हैं, और आपको अभी भी किन वस्तुओं को खोजने की आवश्यकता है।

कैश्ड को कैश न किए गए से अलग करें

तो, मान लें कि आपके पास कैश कुंजियों का एक गुच्छा है:

cache_keys = [:key_1, :key_2, :key_3]

आप कैसे बता सकते हैं कि इनमें से कौन-सा कैश में है?

ActiveSupport::Cache read_multi . नामक एक आसान तरीका है :

# When only lawyer_1 is cached

cache_keys = [:lawyer_1, :lawyer_2, :lawyer_3]
Rails.cache.read_multi(cache_keys) # => {:lawyer_1 => {"id": 1, "name": "Bob the Lawyer"} }

read_multi {key: value} . का हैश लौटाता है कैश में मिली प्रत्येक कुंजी के लिए। लेकिन आप उन सभी कुंजियों को कैसे खोजेंगे जो नहीं हैं कैश में? आप इसे सीधे तरीके से कर सकते हैं:सभी कैश कुंजियों के माध्यम से लूप करें और पता करें कि कौन सी हैश में नहीं हैं read_multi रिटर्न:

cache_keys = [:lawyer_1, :lawyer_2, :lawyer_3]
uncached_keys = []

cached_keys_with_values = Rails.cache.read_multi(cache_keys)

cache_keys.each do |key|
  uncached_keys << key unless cached_keys_with_values.has_key?(key)
end

तो, अब आपके पास क्या है?

  • सभी कैश कुंजियों की एक सरणी जिसके लिए आप ऑब्जेक्ट चाहते थे।
  • {key: value} . का हैश कैश में मिली प्रत्येक वस्तु के लिए जोड़े।
  • उन कुंजियों की सूची जो कैश में नहीं थीं।

और आपको आगे क्या चाहिए?

  • मान उन चाबियों के लिए जो कैश में नहीं थीं। अधिमानतः सभी को एक साथ लाया गया।

यह आपका अगला कदम है।

अनकैश्ड मान प्रीलोड करें

जल्द ही, आपको कैश कुंजी का उपयोग करके एक वस्तु ढूंढनी होगी। चीजों को आसान बनाने के लिए, आप कोड को कुछ इस तरह बदल सकते हैं:

cache_identifiers = {lawyer_1: 1, lawyer_2: 2, lawyer_3: 3}
cache_keys = cache_identifiers.keys
uncached_keys = []

cached_keys_with_values = Rails.cache.read_multi(cache_keys)

cache_keys.each do |key|
  uncached_keys << key unless cached_keys_with_values.has_key?(key)
end

तो cache_identifiers अब कैश कुंजी का ट्रैक रखता है और लाने के लिए ऑब्जेक्ट आईडी।

अब, आपकी कैश न की गई कुंजियों के साथ:

uncached_keys # => [:lawyer_2, :lawyer_3]

और आपके cache_identifiers हैश:

cache_identifiers # => {lawyer_1: 1, lawyer_2: 2, lawyer_3: 3}

आप उन सभी वस्तुओं को एक साथ ला सकते हैं, प्रीलोड कर सकते हैं और क्रमबद्ध कर सकते हैं:

uncached_ids = uncached_keys.map { |key| cache_identifiers[key] }
uncached_lawyers = Lawyer.where(id: uncached_ids)
                         .includes([:address, :practice_areas, :awards, ...])
                         .map(&:as_json))

तो अब आपके पास क्या है?

  • उन सभी कैश कुंजियों की एक सरणी जिनके साथ आप ऑब्जेक्ट शुरू करना चाहते थे।
  • {key: value} . का हैश कैश में मिली प्रत्येक वस्तु के लिए जोड़े।
  • उन कुंजियों की सूची जो कैश में नहीं थीं।
  • वे सभी मान जो संचय में नहीं पाए गए।

और आपको आगे क्या चाहिए?

  • आपके द्वारा अभी प्राप्त किए गए सभी मानों को कैश करने के लिए, ताकि आपको अगली बार इस पूरी प्रक्रिया से न गुजरना पड़े।
  • आपके सभी ऑब्जेक्ट की अंतिम सूची, चाहे वे कैश से आए हों या नहीं।

कैश न किए गए मानों को संचित करें

आपके पास दो सूचियाँ हैं:एक अनकैश्ड कुंजियों की सूची और दूसरी अनकैश्ड मानों की। लेकिन उन्हें कैश करना आसान होगा यदि आपके पास एक . होता [key, value] . की सूची जोड़े, ताकि आपका value इसकी key . के ठीक बगल में है . यह मेरी पसंदीदा विधियों में से एक का उपयोग करने का एक बहाना है, zip :

[1, 2, 3].zip(["a", "b", "c"]) # => [[1, "a"], [2, "b"], [3, "c"]]

zip के साथ , आप अपने प्राप्त मूल्यों को आसानी से कैश कर सकते हैं:

uncached_keys.zip(uncached_lawyers).each do |key, value|
  Rails.cache.write(key, value)
end

अब आपके पास क्या है?

  • उन सभी कैश कुंजियों की एक सरणी जिनके साथ आप ऑब्जेक्ट शुरू करना चाहते थे।
  • {key: value} . का हैश कैश में मिली प्रत्येक वस्तु के लिए जोड़े।
  • पूर्व में कैश नहीं किए गए मानों की सूची जिन्हें आपने अभी-अभी कैश किया है।

और आपको अब भी क्या चाहिए?

  • आपके सभी ऑब्जेक्ट की एक बड़ी सूची, चाहे वे कैश से आए हों या नहीं।

सभी को एक साथ लाएं

अब, आपके पास कैश कुंजियों की एक आदेशित सूची है:

cache_keys = cache_identifiers.keys

आपके द्वारा कैश से प्राप्त की गई वस्तुओं की सूची:

cached_keys_with_values = Rails.cache.read_multi(cache_keys)

और उन वस्तुओं की सूची जिन्हें आपने अभी डेटाबेस से पकड़ा है:

uncached_ids = uncached_keys.map { |key| cache_identifiers[key] }
uncached_lawyers = Lawyer.where(id: uncached_ids)
                         .includes([:address, :practice_areas, :awards, ...])
                         .map(&:as_json))

अब आपको सब कुछ एक साथ रखने के लिए बस एक आखिरी लूप चाहिए:

results = []
cache_keys.each do |key|
  results << cache_keys_with_values[key] || uncached_lawyers.shift
end

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

उसके बाद, आपका काम हो गया!

यहाँ पूरी चीज़ कैसी दिखती है:

cache_identifiers = {lawyer_1: 1, lawyer_2: 2, lawyer_3: 3}
cache_keys = cache_identifiers.keys
uncached_keys = []

# Fetch the cached values from the cache
cached_keys_with_values = Rails.cache.read_multi(cache_keys)

# Create the list of keys that weren't in the cache
cache_keys.each do |key|
  uncached_keys << key unless cached_keys_with_values.has_key?(key)
end

# Fetch all the uncached values, in bulk
uncached_ids = uncached_keys.map { |key| cache_identifiers[key] }
uncached_lawyers = Lawyer.where(id: uncached_ids)
                         .includes([:address, :practice_areas, :awards, ...])
                         .map(&:as_json))

# Write the uncached values back to the cache
uncached_keys.zip(uncached_lawyers).each do |key, value|
  Rails.cache.write(key, value)
end

# Create our final result set from the cached and uncached values
results = []
cache_keys.each do |key|
  results << cache_keys_with_values[key] || uncached_lawyers.shift
end
results

क्या यह लायक था? शायद। यह बहुत सारे कोड है। लेकिन यदि आप बहुत सारे संघों के साथ ऑब्जेक्ट कैशिंग कर रहे हैं, तो यह आपको दर्जनों या सैकड़ों SQL कॉल सहेज सकता है। और यह आपके API प्रतिसादों में से एक टन का समय निकाल सकता है।

Avvo में, यह पैटर्न अविश्वसनीय रूप से उपयोगी रहा है:हमारे बहुत से JSON API कैश्ड प्रतिक्रियाओं को अविश्वसनीय रूप से तेज़ी से वापस करने के लिए इसका उपयोग करते हैं।

पैटर्न इतना उपयोगी रहा है कि मैंने इसे जोड़ने के लिए एक रत्न लिखा, जिसे बल्क_कैश_फेचर कहा जाता है। इसलिए यदि आप कभी खुद को बड़े, जटिल डेटा मॉडल को कैश करने का प्रयास करते हुए पाते हैं, तो इसे आज़माएं!


  1. कैश संगतता बनाए रखने के तीन तरीके

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

  1. Windows 10 पर Chrome में कुकी और कैशे साफ़ करने का सबसे तेज़ तरीका

    जब आप वेबसाइट पर जाते हैं, तो यह आपकी साइट वरीयताएँ या प्रोफ़ाइल जानकारी जैसी ब्राउज़िंग जानकारी संग्रहीत करने के लिए कुकीज़ बनाएगी, और आपके ब्राउज़र का कैश, जो वेब पेज, इमेज, सीएसएस, ऑडियो, वीडियो और अन्य डाउनलोड की गई सामग्री को स्टोर करता है, पेजों को तेजी से लोड करने में मदद कर सकता है, आपके लिए

  1. स्टेग्नोग्राफ़ी:मैलवेयर फैलाने का एक नया तरीका

    जबकि हम शून्य-दिन के खतरों, लोकप्रिय कारनामों, घातक COVID-19 वायरस से लड़ने के लिए तैयार हो रहे हैं। हैकर्स आपकी मशीनों पर मैलवेयर को पास करने के लिए नई तकनीक विकसित कर रहे हैं। एक अवधारणा 1499 में शुरू की गई थी लेकिन प्राचीन काल से मौजूद थी, नया हथियार है। इसे स्टेग्नोग्राफ़ी कहा जाता है, इस नई तकन