जब एक रेल्स एप्लिकेशन एक अनुरोध स्वीकार करता है, तो कंट्रोलर आमतौर पर मॉडल से अनुरोधित डेटा मांगेगा। मॉडल तब इसे डेटाबेस से लाता है और इसे कंट्रोलर को वापस पास करता है। कंट्रोलर अंत में व्यू को रेंडर करता है जो डेटा को मानव-पठनीय प्रारूप में प्रस्तुत करता है।
कुछ स्थितियों में, व्यू को रेंडर करना एक महंगा ऑपरेशन होता है, खासकर यदि व्यू को बहुत सारा डेटा प्रदर्शित करने की आवश्यकता होती है, जैसे स्टोर में उपलब्ध सभी उत्पादों की सूची दिखाते समय, उदाहरण के लिए। ऐसे मामलों में, वापस किए गए व्यू के कुछ हिस्सों को कैश करने से चीजें तेज हो सकती हैं, खासकर जब डेटा बहुत बार नहीं बदलता।
👋 और अगर आपको यह लेख पसंद आया, तो हमने रूबी (ऑन रेल्स) प्रदर्शन के बारे में बहुत कुछ लिखा है, हमारी रूबी प्रदर्शन निगरानी चेकलिस्ट देखें।
स्थानीय स्तर पर कैशिंग का परीक्षण
कैशिंग डिफ़ॉल्ट रूप से विकास में बंद होती है, ताकि आप हमेशा अपने ऐप से ताज़ा प्रतिक्रियाएं प्राप्त कर सकें। स्थानीय स्तर पर कैशिंग का परीक्षण करने के लिए, आपको इसे अपने विकास कॉन्फ़िगरेशन में चालू करना होगा।
रेल्स 5 में, आप कमांड लाइन से अस्थायी रूप से कैशिंग चालू कर सकते हैं। यह मेमोरी स्टोर का उपयोग करेगा, जिसका अर्थ है कि कैश्ड फ्रैगमेंट वेब सर्वर की रूबी प्रोसेस में मेमोरी में रखे जाएंगे।
$ rails dev:cache
Development mode is now being cached.
आप कैशिंग को वापस बंद करने के लिए वही कमांड चला सकते हैं।
फ्रैगमेंट कैशिंग
मान लें कि हमारे पास एक पेज है जो स्टोर में सभी उत्पादों को एक ही पेज पर दिखाता है। ऐसा करने के लिए, हमारे पास एक इंडेक्स व्यू है जो उत्पादों को दिखाता है।
# app/views/products/index.html.erb
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Image url</th>
<th>Price</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @products.each do |product| %>
<%= render product %>
<% end %>
</tbody>
</table>
प्रत्येक उत्पाद के लिए, _product.html.erb पार्शियल रेंडर किया जाता है, जो उत्पाद के विवरण के साथ एक टेबल पंक्ति प्रदर्शित करने का ध्यान रखता है।
# app/views/products/_product.html.erb
<tr>
<td><%= product.title %></td>
<td><%= product.description %></td>
<td><%= product.image_url %></td>
<td><%= product.price %></td>
<td><%= link_to 'Show', product %></td>
<td><%= link_to 'Edit', edit_product_path(product) %></td>
<td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
स्थानीय स्तर पर पेज का अनुरोध करने पर, विकास मोड में, डेटाबेस में 25 उत्पादों के साथ लगभग 300 मिलीसेकंड लगते हैं। उस समय का लगभग पूरा हिस्सा पार्शियल रेंडर करने में खर्च होता है।
सबसे अधिक संभावना है, प्रतिक्रिया उत्पादन में तेज़ होगी, बंडल्ड एसेट्स, कम लॉगिंग और तेज़ वेब सर्वर के कारण। हालांकि विकास में संख्याएं सटीक नहीं हैं, वे दिखाएंगे कि हमारे अनुरोध का कौन सा हिस्सा सबसे धीमा है, ताकि हम इसे तेज़ करने का प्रयास कर सकें।
Started GET "/products" for ::1 at 2018-03-13 12:16:08 +0100
Processing by ProductsController#index as HTML
Rendering products/index.html.erb within layouts/application
Product Load (0.4ms) SELECT "products".* FROM "products"
Rendered products/_product.html.erb (1.4ms)
Rendered products/_product.html.erb (0.4ms)
...
Rendered products/index.html.erb within layouts/application (257.5ms)
Completed 200 OK in 295ms(Views: 290.4ms | ActiveRecord: 0.4ms)
इन सभी पार्शियल को रेंडर करने में समय बचाने के लिए, हम रेल्स के अंतर्निहित फ्रैगमेंट कैशिंग का उपयोग कर सकते हैं, जो रेंडर्ड व्यू के हिस्से को फ्रैगमेंट के रूप में संग्रहीत करता है। बाद के अनुरोधों के लिए, प्री-सेव्ड फ्रैगमेंट का उपयोग इसे फिर से रेंडर करने के बजाय किया जाता है।
एक फ्रैगमेंट को कैश करने के लिए, आप इसे cache हेल्पर का उपयोग करके एक ब्लॉक में रैप करते हैं।
<table> ... <tbody>
<% @products.each do |product| %>
<% cache(product) do %>
<%= render product %>
<% end %>
<% end %>
</tbody>
</table>
यह देखने के लिए कि इन उत्पादों को कैश करने से हमारी प्रतिक्रिया तेज हुई या नहीं, हम पेज का दो बार अनुरोध करेंगे। दूसरा अनुरोध बहुत तेज़ी से निष्पादित होना चाहिए, क्योंकि व्यू में प्रत्येक उत्पाद प्री-रेंडर किया गया है और पहले से ही कैश में संग्रहीत है।
Started GET "/products" for ::1 at 2018-03-13 12:17:29 +0100
Processing by ProductsController#index as HTML
Rendering products/index.html.erb within layouts/application
Product Load (0.4ms) SELECT "products".* FROM "products"
Rendered products/index.html.erb within layouts/application (21.2ms)
Completed 200 OK in 55ms (Views: 50.8ms | ActiveRecord: 0.4ms)
यह काम कर गया! दूसरा अनुरोध पहले की तुलना में पांच गुना से अधिक तेज़ था। ध्यान दें कि लॉग में पार्शियल का कोई रेंडरिंग नहीं दिखाता, क्योंकि वे सीधे कैश से लोड होते हैं।
कैश समाप्त करना
ऊपर दिए गए उदाहरण में cache हेल्पर को कॉल करते समय, हमने product ऑब्जेक्ट को कैश निर्भरता के रूप में पास किया। यह हेल्पर को बताता है कि कैश्ड फ्रैगमेंट की सामग्री उत्पाद ऑब्जेक्ट पर निर्भर करती है।
आंतरिक रूप से, उत्पाद ऑब्जेक्ट में एक #cache_key मेथड होता है, जिसका उपयोग कैश्ड फ्रैगमेंट के लिए कुंजी बनाने के लिए किया जाता है। पूरे फ्रैगमेंट की कुंजी इस तरह दिख सकती है:
views/products/42-20180302103130041320/75dda06d36880e8b0ae6cac0a44fb56d
कैश कुंजी में कुछ भाग होते हैं:
- "views/products" कैश क्लास है।
42उत्पाद की आईडी है20180302103130041320उत्पाद की updated_at तारीख है75dda06d36880e8b0ae6cac0a44fb56dटेम्पलेट ट्री का डाइजेस्ट है
यह कुंजी जब भी उत्पाद अपडेट होता है, या टेम्पलेट में कुछ भी बदलता है, तो बदल जाती है। जब ऐसा होता है, तो यह कैश में मिस का कारण बनता है, जिससे फ्रैगमेंट फिर से रेंडर होता है और एक नया फ्रैगमेंट सेव होता है। यह सुनिश्चित करता है कि फ्रैगमेंट ताज़ा रहे, भले ही इसके घटक बदल जाएं।
फ्रैगमेंट कैशिंग से आगे
हालांकि इस उदाहरण में चर्चा किए गए कैश्ड फ्रैगमेंट एक छोटी गति वृद्धि देते हैं, कैशिंग में इससे कहीं अधिक है जितना हमने आज चर्चा की। रशियन डॉल कैशिंग जैसी रणनीतियों या डेटाबेस क्वेरी परिणामों को कैश करने जैसे निम्न-स्तरीय तरीकों का उपयोग करके बड़ी गति वृद्धि प्राप्त की जा सकती है।
बेशक, हम ऐपसिग्नल अकादमी के बाद के एपिसोड में इन पर जाएंगे। कुछ विशिष्ट जो आप सीखना चाहते हैं? कृपया @AppSignal पर हमें बताने में संकोच न करें। बेशक, हम जानना चाहेंगे कि आपको यह लेख कैसा लगा, या यदि आप किसी अन्य विषय के बारे में अधिक जानना चाहते हैं।