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

रेल में कैशिंग देखें के बारे में आप जो कुछ भी जानना चाहते हैं वह सब कुछ

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

रेल डेवलपर्स के लिए, कैशिंग के सामान्य रूपों में संस्मरण, निम्न-स्तरीय कैशिंग (दोनों इस कैशिंग श्रृंखला के पिछले भागों में शामिल हैं), और कैशिंग देखें, जिसे हम यहां कवर करेंगे।

Ruby on Rails Renders Views

सबसे पहले, आइए कुछ भ्रमित करने वाली शब्दावली को कवर करें। रेल समुदाय जिसे "विचार" कहते हैं, वे फ़ाइलें हैं जो आपके app/views . के अंदर रहती हैं निर्देशिका। आमतौर पर, ये .html.erb हैं फ़ाइलें, हालांकि अन्य विकल्प भी हैं (यानी, सादा .html , .js.erb , या फ़ाइलें जो अन्य प्रीप्रोसेसरों का उपयोग करती हैं, जैसे कि स्लिम और हैमल)। कई अन्य वेब ढांचे में, इन फ़ाइलों को "टेम्पलेट्स" कहा जाता है, जो मुझे लगता है कि उनके उपयोग का बेहतर वर्णन करता है।

जब कोई रेल एप्लिकेशन GET प्राप्त करता है अनुरोध, इसे एक विशेष नियंत्रक कार्रवाई के लिए भेजा जाता है, उदाहरण के लिए, UsersController#index . कार्रवाई तब डेटाबेस से किसी भी आवश्यक जानकारी को इकट्ठा करने और दृश्य/टेम्पलेट फ़ाइल को प्रस्तुत करने में उपयोग के लिए इसे पारित करने के लिए ज़िम्मेदार है। इस समय, हम "व्यू लेयर" में प्रवेश कर रहे हैं।

आमतौर पर, आपका दृश्य (या टेम्पलेट) हार्ड-कोडेड HTML मार्कअप और डायनेमिक रूबी कोड का मिश्रण होगा:

#app/views/users/index.html.erb

<div class='user-list'>
  <% @users.each do |user| %>
    <div class='user-name'><%= user.name %></div>
  <% end %>
</div>

फ़ाइल में रूबी कोड को दृश्य प्रस्तुत करने के लिए निष्पादित करने की आवश्यकता है (erb . के लिए) यह <% %> . में कुछ भी है टैग)। पृष्ठ को 100 बार ताज़ा करें, और @users.each... 100 बार निष्पादित किया जाएगा। शामिल किसी भी आंशिक के लिए भी यही सच है; प्रोसेसर को आंशिक html.erb load लोड करने की आवश्यकता है फ़ाइल, उसके अंदर सभी रूबी कोड निष्पादित करें, और परिणामों को एक HTML फ़ाइल में संयोजित करें ताकि वे अनुरोधकर्ता को वापस भेज सकें।

स्लो व्यू के कारण क्या हैं

आपने शायद ध्यान दिया होगा कि जब आप विकास के दौरान किसी पृष्ठ को देखते हैं, तो रेल बहुत सारी लॉग जानकारी को प्रिंट करता है, जो कुछ इस तरह दिखती है:

Processing by PagesController#home as HTML
  Rendering layouts/application.html.erb
  Rendering pages/home.html.erb within layouts/application
  Rendered pages/home.html.erb within layouts/application (Duration: 4.0ms | Allocations: 1169)
  Rendered layouts/application.html.erb (Duration: 35.9ms | Allocations: 8587)
Completed 200 OK in 68ms (Views: 40.0ms | ActiveRecord: 15.7ms | Allocations: 14307)

इस स्तर पर अंतिम पंक्ति हमारे लिए सबसे उपयोगी है। बाएं से दाएं समय का अनुसरण करके, हम देखते हैं कि ब्राउज़र को प्रतिक्रिया देने के लिए रेल द्वारा लिया गया कुल समय 68ms था, जिसमें से 40ms erb को प्रस्तुत करने में खर्च किया गया था। फ़ाइलें और 15.7ms ActiveRecord प्रश्नों को संसाधित करने पर।

हालांकि यह एक मामूली उदाहरण है, यह यह भी दिखाता है कि हम व्यू लेयर को कैशिंग क्यों करना चाहते हैं। यहां तक ​​​​कि अगर हम जादुई रूप से ActiveRecord प्रश्नों को तुरंत कर सकते हैं, तो हम erb को प्रस्तुत करने के लिए दोगुने से अधिक समय खर्च कर रहे हैं ।

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

एक ईमेल इनबॉक्स की कल्पना करें, जहां हमारे पास एक आंशिक हो सकता है जो एक व्यक्तिगत पंक्ति को संभालता है:

# app/views/emails/_email.html.erb

<li class="email-line">
  <div class="email-sender">
    <%= email.from_address %>
  </div>
  <div class="email-subject">
    <%= email.subject %>
  </div>
</div>

और, हमारे मुख्य इनबॉक्स पृष्ठ में, हम प्रत्येक ईमेल के लिए आंशिक प्रस्तुत करते हैं:

# app/views/emails/index.html.erb

...
<% @emails.each do |email| %>
  <%= render email %>
<% end %>

यदि हमारे इनबॉक्स में 100 संदेश हैं, तो हम _email.html.erb . प्रदान कर रहे हैं 100 बार आंशिक। हमारे छोटे से उदाहरण के साथ, यह ज्यादा चिंता का विषय नहीं है। मेरी मशीन पर, आंशिक केवल पूरे सूचकांक को प्रस्तुत करने के लिए 15ms लेता है। बेशक, वास्तविक दुनिया के उदाहरण अधिक जटिल होंगे और उनमें अन्य आंशिक भी शामिल हो सकते हैं; रेंडर समय को बढ़ाना मुश्किल नहीं है। भले ही हमारे _email . को रेंडर करने में केवल 1-2ms लगते हैं आंशिक, पूरे संग्रह को करने में 100-200ms का समय लगेगा।

सौभाग्य से, इस समस्या को हल करने के लिए आसानी से कैशिंग जोड़ने में हमारी मदद करने के लिए रेल में कुछ अंतर्निहित कार्यक्षमता है, चाहे हम केवल __email को कैश करना चाहें। आंशिक, index पृष्ठ, या दोनों।

व्यू कैशिंग क्या है

रूबी ऑन रेल्स में कैशिंग देखें एचटीएमएल ले रहा है कि एक दृश्य इसे बाद में उत्पन्न और संग्रहीत करता है। हालाँकि रेल के पास इन्हें फाइल सिस्टम में लिखने या उन्हें मेमोरी में रखने के लिए समर्थन है, उत्पादन के उपयोग के लिए, आप लगभग निश्चित रूप से एक स्टैंडअलोन कैशिंग सर्वर चाहते हैं, जैसे कि मेमकैच्ड या रेडिस। रेल का memory_store विकास के लिए उपयोगी है लेकिन प्रक्रियाओं में साझा नहीं किया जा सकता है (उदाहरण के लिए, एकाधिक सर्वर/डायनो या फोर्किंग सर्वर, जैसे यूनिकॉर्न)। इसी तरह, file_store सर्वर के लिए स्थानीय है। इसलिए, इसे कई बक्सों में साझा नहीं किया जा सकता है, और यह समय-सीमा समाप्त प्रविष्टियों को स्वचालित रूप से नहीं हटाएगा, इसलिए आपको समय-समय पर Rails.cache.clear पर कॉल करने की आवश्यकता होगी। अपने सर्वर की डिस्क को फुल होने से रोकने के लिए।

कैशिंग स्टोर को सक्षम करना आपकी पर्यावरण कॉन्फ़िगरेशन फ़ाइल में किया जा सकता है (उदा., config/environments/production.rb ):

  # memory store is handy for testing
  # during development but not advisable
  # for production
  config.cache_store = :memory_store

डिफ़ॉल्ट स्थापना में, आपका development.rb आपकी मशीन पर कैशिंग की आसान टॉगलिंग की अनुमति देने के लिए आपके पास पहले से ही कुछ कॉन्फ़िगरेशन होगा। बस rails dev:cache चलाएं कैशिंग चालू और बंद टॉगल करने के लिए।

रेल में एक दृश्य को कैश करना भ्रामक रूप से सरल है, इसलिए प्रदर्शन अंतर को स्पष्ट करने के लिए, मैं केवल sleep(5) का उपयोग करूंगा कृत्रिम विलंब पैदा करने के लिए:

<% cache do %>
  <div>
    <p>Hi <%= @user.name %>
    <% sleep(5) %>
  </div>
<% end %>

इस दृश्य को पहली बार रेंडर करने में अपेक्षानुसार 5 सेकंड का समय लगता है। हालांकि, इसे दूसरी बार लोड करने में केवल कुछ मिलीसेकंड लगते हैं क्योंकि cache do के अंदर सब कुछ है ब्लॉक को कैशे से प्राप्त किया जाता है।

उदाहरण के द्वारा कैशिंग देखें जोड़ना

आइए एक छोटा सा उदाहरण देखें और कैशिंग के लिए हमारे विकल्पों को देखें। हम मान लेंगे कि यह दृश्य वास्तव में कुछ प्रदर्शन समस्याओं का कारण बन रहा है:

# app/views/user/show.html.erb
<div>
  Hi <%= @user.name %>!
<div>

<div>
  Here's your list of posts,
  you've written
  <%= @user.posts.count %> so far
  <% @user.posts.each do |post|
    <div><%= post.body %></div>
  <% end %>
</div>

<% sleep(5) #artificial delay %>

यह हमें हमारे कृत्रिम 5-सेकंड की देरी के साथ काम करने के लिए एक बुनियादी कंकाल देता है। सबसे पहले, हम संपूर्ण show.html.erb . को लपेट सकते हैं फ़ाइल को cache do . में फ़ाइल करें ब्लॉक, जैसा कि पहले बताया गया है। अब, कैश के गर्म होने के बाद, हमें अच्छा, तेज़ रेंडरिंग समय मिलता है। हालाँकि, इस योजना के साथ समस्याएँ दिखने में देर नहीं लगती।

सबसे पहले, यदि उपयोगकर्ता अपना नाम बदलते हैं तो क्या होगा? हमने रेल को यह नहीं बताया है कि हमारे कैश्ड पेज को कब समाप्त करना है, इसलिए उपयोगकर्ता को कभी भी एक अद्यतन संस्करण नहीं दिखाई दे सकता है। एक आसान उपाय केवल @user . पास करना है cache . पर आपत्ति करें विधि:

<% cache(@user) do %>
<div>
  Hi <%= @user.name %>!
</div>
...
<% sleep(5) #artificial delay %>
<% end %>

निम्न-स्तरीय कैशिंग पर इस श्रृंखला के पिछले लेख में कैश कुंजियों का विवरण शामिल किया गया था, इसलिए मैं इसे यहां फिर से शामिल नहीं करूंगा। अभी के लिए, यह जानना काफी है कि अगर हम cache() . पर एक मॉडल पास करते हैं , यह उस मॉडल के updated_at . का उपयोग करेगा कैश में देखने के लिए एक कुंजी उत्पन्न करने के लिए विशेषता। दूसरे शब्दों में, जब भी @user अपडेट किया गया है, यह कैश्ड पेज समाप्त हो जाएगा, और रेल एचटीएमएल को फिर से प्रस्तुत करेंगे।

जब उपयोगकर्ता अपना नाम बदलते हैं, तो हमने उस मामले का ध्यान रखा है, लेकिन उनकी पोस्ट का क्या? किसी मौजूदा पोस्ट को बदलने या नई पोस्ट बनाने से updated_at में कोई बदलाव नहीं आएगा User . का टाइमस्टैम्प , इसलिए हमारा संचित पृष्ठ समाप्त नहीं होगा। इसके अतिरिक्त, यदि उपयोगकर्ता अपना नाम बदलते हैं, तो हम सभी को फिर से प्रस्तुत करेंगे भले ही उनके पदों में कोई परिवर्तन न हुआ हो। इन दोनों समस्याओं को हल करने के लिए; हम "रूसी गुड़िया कैशिंग" (यानी कैश के भीतर कैश) का उपयोग कर सकते हैं:

<% cache(@user) do %>
  <div>
    Hi <%= @user.name %>!
  <div>

  <div>
    Here's your list of posts,
    you've written
    <%= @user.posts.count %> so far<br>
    <% @user.posts.each do |post| %>
      <% cache(post) do %>
        <div><%= post.body %></div>
      <% end %>
    <% end %>
  </div>

  <% sleep(5) #artificial delay %>
<% end %>

अब हम प्रत्येक व्यक्तिगत रूप से प्रस्तुत post . को कैशिंग कर रहे हैं (वास्तविक दुनिया में, यह शायद आंशिक होगा)। इसलिए, भले ही @user अपडेट किया गया है, हमें पोस्ट को फिर से प्रस्तुत करने की आवश्यकता नहीं है; हम केवल कैश्ड मान का उपयोग कर सकते हैं। हालाँकि, हमारे पास अभी भी एक और मुद्दा है। अगर कोई post बदल दिया गया है, हम अभी भी अपडेट प्रस्तुत नहीं करेंगे क्योंकि @user.update_at नहीं बदला है, इसलिए cache(@user) do निष्पादित नहीं होगा।

इस समस्या को ठीक करने के लिए, हमें touch: true add जोड़ना होगा हमारे post . पर मॉडल:

class Post < ApplicationRecord
  belongs_to :user, touch: true
end

touch: true adding जोड़कर यहाँ, हम ActiveRecord को बता रहे हैं कि हर बार एक पोस्ट अपडेट की गई है, हम चाहते हैं कि updated_at उस उपयोगकर्ता का टाइमस्टैम्प भी अपडेट किया जाना चाहिए जिसका वह "संबंधित" है।

मुझे यह भी जोड़ना चाहिए कि रेल आंशिक के संग्रह को प्रस्तुत करने के लिए एक विशिष्ट सहायक प्रदान करता है, यह कितना आम है:

  <%= render partial: 'posts/post',
       collection: @posts, cached: true %>

जो कार्यात्मक रूप से निम्नलिखित के बराबर है:

<% @posts.each do |post| %>
  <% cache(post) do %>
    <%= render post %>
  <% end %>
<% end %>

न केवल render partial: ... cached: true कम वर्बोज़ बनाते हैं, यह आपको कुछ अतिरिक्त दक्षता भी देता है क्योंकि रेल संग्रह में प्रत्येक आइटम के लिए आपके कैश स्टोर को हिट करने के बजाय कैश स्टोर (यानी, एक ही राउंड-ट्रिप में कई कुंजी/मूल्य जोड़े पढ़ना) के लिए एक मल्टीगेट जारी कर सकते हैं।

गतिशील पृष्ठ सामग्री

कुछ पृष्ठों में कुछ मात्रा में 'गतिशील' सामग्री शामिल होना आम बात है जो अपने आस-पास के शेष पृष्ठ की तुलना में बहुत तेज़ दर से बदलती है। यह होम पेज या डैशबोर्ड पर विशेष रूप से सच है, जहां आपके पास गतिविधि/समाचार फ़ीड हो सकते हैं। इन्हें हमारे कैश्ड पेज में शामिल करने का मतलब यह हो सकता है कि हमारे कैशे को बार-बार अमान्य करने की आवश्यकता है, जो पहले स्थान पर कैशिंग से मिलने वाले लाभ को सीमित करता है।

एक साधारण उदाहरण के रूप में, आइए वर्तमान दिन को हमारे विचार में जोड़ें:

<% cache(@user) do %>
  <div>
    Hi <%= @user.name %>,
    hope you're having a great
    <%= Date.today.strftime("%A") %>!
  <div>

  ...
<% end %>

हम हर दिन कैश को अमान्य कर सकते हैं, लेकिन स्पष्ट कारणों से यह बहुत व्यावहारिक नहीं है। एक विकल्प प्लेसहोल्डर मान का उपयोग करना है (या यहां तक ​​कि केवल एक खाली <span> ) और इसे जावास्क्रिप्ट के साथ पॉप्युलेट करें। इस तरह के दृष्टिकोण को अक्सर "जावास्क्रिप्ट स्प्रिंकल्स" कहा जाता है और यह बेसकैंप द्वारा काफी हद तक पसंद किया जाने वाला दृष्टिकोण है, जहां बहुत सारे रेल का कोर कोड विकसित किया जाता है। परिणाम कुछ इस तरह होगा:

<% cache(@user) do %>
  <div>
    Hi <%= @user.name %>,
    hope you're having a great
    <span id='greeting-day-name'>Day</span>!
  <div>

  ...
<% end %>

<script>
 // assuming you're using vanilla JS with turbolinks
 document.addEventListener(
   "turbolinks:load", function() {
   weekdays = new Array('Sunday', 'Monday',
     'Tuesday', 'Wednesday', 'Thursday',
     'Friday', 'Saturday');
     today = weekdays[new Date().getDay()];
   document.getElementById("greeting-day-name").textContent=today;
 });
</script>

एक अन्य तरीका दृश्य के केवल कुछ हिस्सों को कैश करना है। हमारे उदाहरण में, ग्रीटिंग पृष्ठ के शीर्ष पर है, इसलिए यह केवल कैश करने के लिए काफी छोटा है जो निम्नानुसार है:

<div>
  Hi <%= @user.name %>,
  hope you're having a great
  <%= Date.today.strftime("%A") %>!
<div>

<% cache(@user) do %>
  ...
<% end %>

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

चेतावनी के शब्द

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

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

निम्न-स्तरीय कैशिंग के साथ, सबसे अच्छी सलाह यह है कि आप इसका उपयोग कहां और कब करते हैं, इसके बारे में रणनीतिक होना चाहिए। प्रदर्शन के स्वीकार्य स्तर को प्राप्त करने के लिए जितना हो सके कम से कम स्थानों पर कैशिंग का उपयोग करें।

रेल' कैशिंग डिफ़ॉल्ट रूप से

कैशिंग पर इस श्रृंखला में अब तक हमने चीजों को मैन्युअल रूप से कैशिंग करने के तरीकों को कवर किया है, लेकिन बिना किसी मैन्युअल कॉन्फ़िगरेशन के भी, ActiveRecord पहले से ही कुछ कैशिंग अंडर-द-हुड प्रश्नों को तेज करने के लिए करता है (या उन्हें पूरी तरह से छोड़ देता है)। कैशिंग पर इस श्रृंखला के अगले लेख में हम देखेंगे कि ActiveRecord हमारे लिए क्या कैशिंग कर रहा है, और कैसे, थोड़े से काम के साथ, हम इसे "काउंटर कैश" रख सकते हैं ताकि thing.children.size अद्यतित गणना प्राप्त करने के लिए डेटाबेस को बिल्कुल हिट करने की आवश्यकता नहीं है।


  1. सैमसंग गैलेक्सी S9:इसके बारे में आपको जो कुछ भी जानना चाहिए

    लंबा इंतजार आखिरकार खत्म! सैमसंग के फ्लैगशिप फोन S9 और S9+ का हाल ही में MWC (मोबाइल वर्ल्ड कॉन्फ्रेंस) 2018 में अनावरण किया गया था। बार्सिलोना में आयोजित मोबाइल वर्ल्ड कॉन्फ्रेंस 2018 में गैलेक्सी सीरीज़ के सैमसंग के सबसे बड़े और नवीनतम फोन की रिलीज़ देखी गई। सैमसंग के इस फ्लैगशिप फोन में इसके पि

  1. ब्लूटूथ 5

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

  1. पीबीएम फ़ाइल के बारे में वह सब कुछ जो आपको जानना चाहिए?

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