हमने पहले AppSignal Academy पर रेल में फ्रैगमेंट कैशिंग को देखा है। यह दृश्यों के छोटे टुकड़ों को कैश करके उनके प्रदर्शन में बहुत सुधार करता है। आंशिक को कैशिंग करते समय, हमें कम लागत पर अपने विचारों में उन्हें कहीं और पुन:उपयोग करने में सक्षम होने का अतिरिक्त लाभ होता है।
यह छोटे संग्रहों के लिए अच्छा काम करता है, लेकिन बड़े संग्रहों पर समस्याएँ शीघ्र ही उत्पन्न हो जाती हैं। इस लेख में, हम देखेंगे कि रेल संग्रह कैशिंग कैसे काम करता है और बड़े संग्रह के प्रतिपादन को गति देने के लिए हम इसका उपयोग कैसे कर सकते हैं।
<ब्लॉकक्वॉट>👋 और यदि आप इस लेख को पसंद करते हैं, तो हमने रूबी (ऑन रेल्स) के प्रदर्शन के बारे में और भी बहुत कुछ लिखा है, हमारी रूबी प्रदर्शन निगरानी चेकलिस्ट देखें।
संग्रह प्रस्तुत करना
आइए एक छोटे नियंत्रक से शुरू करें जो हमारे ब्लॉग के अनुक्रमणिका पृष्ठ के लिए पिछले 100 पोस्ट लोड करता है।
class PostsController < ApplicationController
def index
@posts = Post.all.order(:created_at => :desc).limit(100)
end
end
इन पोस्ट को दृश्य में प्रस्तुत करने के लिए, हम @posts
. पर लूप करते हैं आवृत्ति चर।
<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
<div class="posts">
<% @posts.each do |post| %>
<div class="post">
<h2><%= post.title %></h2>
<small><%= post.author %></small>
<div class="body">
<%= post.body %>
</div>
</div>
<% end %>
</div>
इस पृष्ठ का अनुरोध करने पर, हम देखते हैं कि पोस्ट डेटाबेस से प्राप्त की जा रही हैं और दृश्य प्रस्तुत किया जा रहा है। दृश्य परत में केवल 32 मिलीसेकंड खर्च करने के साथ, यह पृष्ठ बहुत तेज़ है।
Started GET "/posts"
Processing by PostsController#index as HTML
Rendering posts/index.html.erb within layouts/application
Post Load (1.5ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ? [["LIMIT", 100]]
↳ app/views/posts/index.html.erb:4
Rendered posts/index.html.erb within layouts/application (19.4ms)
Completed 200 OK in 37ms (Views: 32.4ms | ActiveRecord: 2.7ms)
एक संग्रह को आंशिक रूप से प्रस्तुत करना
इसके बाद, हम post
. का उपयोग करना चाहते हैं किसी अन्य दृश्य में तत्व, इसलिए हम पोस्ट HTML को आंशिक में ले जाते हैं।
<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
<div class="posts">
<% @posts.each do |post| %>
<%= render post %>
<% end %>
</div>
<!-- app/views/posts/_post.html.erb -->
<div class="post">
<h2><%= post.title %></h2>
<small><%= post.author %></small>
<div class="body">
<%= post.body %>
</div>
</div>
Started GET "/posts"
Processing by PostsController#index as HTML
Rendering posts/index.html.erb within layouts/application
Post Load (1.2ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ? [["LIMIT", 100]]
↳ app/views/posts/index.html.erb:4
...
Rendered posts/_post.html.erb (0.1ms)
Rendered posts/_post.html.erb (0.1ms)
Rendered posts/index.html.erb within layouts/application (205.4ms)
Completed 200 OK in 217ms (Views: 213.8ms | ActiveRecord: 1.7ms)
दृश्य परत पर खर्च किए गए 213 मिलीसेकंड के साथ, आप देख सकते हैं कि रेंडर करने का समय काफी बढ़ गया है। ऐसा इसलिए है क्योंकि प्रत्येक पोस्ट के लिए एक नई फ़ाइल (आंशिक) को लोड, संकलित और प्रस्तुत करने की आवश्यकता होती है। आइए संक्षेप में देखें कि हम फ़्रैगमेंट कैशिंग के साथ रेंडर समय को कैसे बेहतर बना सकते हैं।
फ्रैगमेंट कैशिंग
जैसा कि फ्रैगमेंट कैशिंग लेख में वर्णित है, हम cache
. का उपयोग करेंगे render
. के आसपास के दृश्य में सहायक बुलाना। इस तरह, हम प्रत्येक पोस्ट के लिए आंशिक के रेंडरिंग को कैश करेंगे।
<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
<div class="posts">
<% @posts.each do |post| %>
<%= cache post do %>
<%= render post %>
<% end %>
<% end %>
</div>
Started GET "/posts"
Processing by PostsController#index as HTML
Rendering posts/index_with_partial_caching.html.erb within layouts/application
Post Load (1.4ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ? [["LIMIT", 100]]
↳ app/views/posts/index.html.erb:4
...
Read fragment views/posts/index.1ms)
Rendered posts/_post.html.erb (0.1ms)
Write fragment views/posts/index.1ms)
Read fragment views/posts/index.5ms)
Rendered posts/_post.html.erb (0.1ms)
Write fragment views/posts/index.1ms)
Rendered posts/index.html.erb within layouts/application (274.5ms)
Completed 200 OK in 286ms (Views: 281.4ms | ActiveRecord: 2.4ms)
पहला अनुरोध इतना तेज़ नहीं होगा, क्योंकि इसे अभी भी हर आंशिक को पहली बार प्रस्तुत करने और इसे कैशे स्टोर में संग्रहीत करने की आवश्यकता है।
Started GET "/posts"
Processing by PostsController#index as HTML
Rendering posts/index.html.erb within layouts/application
Post Load (2.2ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ? [["LIMIT", 100]]
↳ app/views/posts/index.html.erb:4
...
Read fragment views/posts/index.1ms)
Read fragment views/posts/index.1ms)
Rendered posts/index.html.erb within layouts/application (63.8ms)
Completed 200 OK in 78ms (Views: 75.5ms | ActiveRecord: 2.2ms)
बाद के अनुरोधों में, हम देखते हैं कि दृश्य में बिताया गया समय काफी कम है - 286 मिलीसेकंड से 78 मिलीसेकंड तक। फिर भी, यह अभी भी हमारे मूल कोड की तुलना में बहुत धीमा है - यह लगभग दोगुना धीमा है।
नोट:यदि आप अपने लॉग्स में "रीड/राइट फ्रैगमेंट" लाइन नहीं देख रहे हैं, तो अपने डेवलपमेंट एनवायरनमेंट में फ्रैगमेंट कैश लॉगिंग को सक्षम करना सुनिश्चित करें, जो कि false
पर सेट है। रेल 5.1 और इसके बाद के संस्करण पर डिफ़ॉल्ट रूप से:
# config/environments/development.rb
config.action_controller.enable_fragment_cache_logging = true
संग्रह कैशिंग
रेल 5 में, संग्रह कैशिंग को तेज करने के लिए बहुत काम किया गया था। इन सुधारों का लाभ उठाने के लिए, हमें अपना व्यू कोड बदलना होगा। cache
को कॉल करने के बजाय अपने आप को सहायक, हम रेल को एक ही समय में एक संपूर्ण संग्रह प्रस्तुत करने और उसे कैश करने के लिए कह सकते हैं।
<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
<div class="posts">
<%= render partial: :post, collection: @posts, cached: true %>
</div>
नोट करें render @collection, cached: true
इस कैशिंग गति सुधार के लिए शॉर्टहैंड काम नहीं करेगा।
Started GET "/posts"
Processing by PostsController#index as HTML
Rendering posts/index.html.erb within layouts/application
Post Load (1.4ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ? [["LIMIT", 100]]
↳ app/views/posts/index.html.erb:4
Rendered collection of posts/_post.html.erb [0 / 100 cache hits] (28.2ms)
Rendered posts/index.html.erb within layouts/application (46.6ms)
Completed 200 OK in 64ms (Views: 59.9ms | ActiveRecord: 2.0ms)
पहले अनुरोध पर, हम पहले से ही दृश्य परत पर खर्च किए गए समय में एक बड़ा सुधार देख सकते हैं। ऐसा इसलिए है क्योंकि रेल अब पहले से तैयारी करते हैं, आंशिक रूप से पूरे संग्रह के लिए इस्तेमाल किया जा रहा है, न कि प्रत्येक पोस्ट के लिए अलग से।
Started GET "/posts"
Processing by PostsController#index as HTML
Rendering posts/index.html.erb within layouts/application
Post Load (1.3ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ? [["LIMIT", 100]]
↳ app/views/posts/index.html.erb:4
Rendered collection of posts/_post.html.erb [100 / 100 cache hits] (19.2ms)
Rendered posts/index.html.erb within layouts/application (26.5ms)
Completed 200 OK in 37ms (Views: 35.7ms | ActiveRecord: 1.3ms)
बाद के अनुरोधों में, हम और भी अधिक सुधार देखते हैं - 64 मिलीसेकंड से लेकर लगभग 35 मिलीसेकंड तक। पूरे संग्रह के लिए एक बड़ा गति सुधार यहां संग्रह के लिए रेल अनुकूलन द्वारा किया गया है। प्रत्येक आंशिक के लिए कैश की उपलब्धता की जाँच करने के बजाय, रेल एक ही समय में संग्रह की सभी कैश कुंजियों की जाँच करता है, जिससे कैशे स्टोर को क्वेरी करने में समय की बचत होती है।
इस कैशिंग सहायक का एक अतिरिक्त लाभ संग्रह का सारांशित लॉगिंग है। पहले अनुरोध में, कोई भी कैश कुंजी नहीं मिली [0 / 100 cache hits]
, लेकिन दूसरे अनुरोध में, वे सभी पाए गए [100 / 100 cache hits]
।
डेटाबेस में कुछ ऑब्जेक्ट्स को अपडेट करने के बाद, हम यह भी देख सकते हैं कि कितनी कुंजियाँ पुरानी थीं।
Rendered collection of posts/_post.html.erb [88 / 100 cache hits] (13.4ms)
इस अनुकूलित संग्रह प्रतिपादन और कैशिंग के साथ हासिल करने के लिए बहुत गति सुधार है। बड़े संग्रह प्रस्तुत करते समय और भी बड़ा अंतर बनाया जाएगा। जब तक आपको अपने संग्रह के लिए अनुकूलित दृश्यों की आवश्यकता न हो, यह अनुकूलित रणनीति आपके रेल ऐप्स के लिए जाने का तरीका है। ऐपसिग्नल में, हम इस तरह से हजारों रिकॉर्ड प्रस्तुत करने वाले हमारे एक व्यवस्थापक दृश्य को तेज करने में कामयाब रहे।
रेल में संग्रह कैशिंग के बारे में कोई प्रश्न हैं? कृपया हमें @AppSignal पर बताने में संकोच न करें! यदि आपके पास लेख के संबंध में कोई टिप्पणी है या यदि आपके पास कोई विषय है जिसे आप हमें कवर करना चाहते हैं, तो कृपया हमसे संपर्क करें।