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

रेल्स कलेक्शन कैशिंग में महारत: प्रदर्शन बढ़ाएं और रेंडरिंग ऑप्टिमाइज़ करें

हमने पहले ऐपसिग्नल अकादमी पर रेल्स में फ्रैगमेंट कैशिंग को देखा है। यह छोटे टुकड़ों को कैश करके व्यूज के प्रदर्शन में काफी सुधार करता है। पार्शियल्स को कैश करते समय, हमारे पास उन्हें अपने व्यूज में कहीं और कम लागत पर पुन: उपयोग करने का अतिरिक्त लाभ होता है।

यह छोटे कलेक्शन्स के लिए अच्छा काम करता है, लेकिन बड़े कलेक्शन्स पर समस्याएं तेजी से उत्पन्न होती हैं। इस लेख में, हम देखेंगे कि रेल्स कलेक्शन कैशिंग कैसे काम करती है और कैसे हम इसका उपयोग बड़े कलेक्शन के रेंडरिंग को तेज करने के लिए कर सकते हैं।

👋 और यदि आप इस लेख को पसंद करते हैं, तो हमने रूबी (ऑन रेल्स) प्रदर्शन के बारे में बहुत कुछ लिखा है, हमारे रूबी प्रदर्शन मॉनिटरिंग चेकलिस्ट को देखें।

कलेक्शन रेंडर करना

आइए एक छोटे कंट्रोलर से शुरू करें जो हमारे ब्लॉग के इंडेक्स पेज के लिए अंतिम 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 मिलीसेकंड खर्च होने के साथ, आप देख सकते हैं कि रेंडर समय काफी बढ़ गया है। ऐसा इसलिए है क्योंकि हर पोस्ट के लिए एक नई फाइल (पार्शियल) को लोड, कंपाइल और रेंडर करने की आवश्यकता होती है। आइए संक्षेप में देखें कि हम फ्रैगमेंट कैशिंग के साथ रेंडर समय को कैसे सुधार सकते हैं।

फ्रैगमेंट कैशिंग

फ्रैगमेंट कैशिंग लेख में वर्णित अनुसार, हम व्यू में render कॉल के चारों ओर cache हेल्पर का उपयोग करेंगे। इस तरह, हम हर पोस्ट के लिए पार्शियल के रेंडरिंग को कैश करेंगे।

<!-- 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 मिलीसेकंड। फिर भी, यह हमारे मूल कोड के मुकाबले अभी भी बहुत धीमा है - यह लगभग दोगुना धीमा है।

नोट: यदि आप अपने लॉग्स में "Read/Write fragment" लाइनें नहीं देख रहे हैं, तो अपने डेवलपमेंट एनवायरनमेंट में फ्रैगमेंट कैश लॉगिंग को सक्षम करना सुनिश्चित करें, जो रेल्स 5.1 और ऊपर पर डिफ़ॉल्ट रूप से false पर सेट है:

# 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 पर हमें बताने में संकोच न करें! यदि आपके पास लेख के संबंध में कोई टिप्पणी है या यदि आपके पास कोई विषय है जिसे आप कवर करना चाहेंगे, तो कृपया हमसे संपर्क करें।

  1. Hotwire के साथ Rails ऐप्स को तेज़ करें: JavaScript के बिना सर्वर-साइड रेंडरिंग Hotwire के साथ Rails ऐप्स को तेज़ करें: JavaScript के बिना सर्वर-साइड रेंडरिंग

    यदि आप पेज परिवर्तनों और फॉर्म सबमिशन को तेज़ करने और जटिल पेज को बिना कोई JavaScript कोड लिखे घटकों में विभाजित करने का तरीका ढूंढ रहे हैं, तो यह पोस्ट आपको Hotwire के साथ Rails को अगले स्तर पर ले जाने में मदद करेगी। यह लेख आपको सर्वर-साइड रेंडरिंग के लिए एक टूल का उपयोग करना सिखाएगा। Hotwire क्या

  1. AWS Lambda पर रूबी ऑन Rails डिप्लॉय करना: चरण-दर-चरण मार्गदर्शिका AWS Lambda पर रूबी ऑन Rails डिप्लॉय करना: चरण-दर-चरण मार्गदर्शिका

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

  1. Angular को Rails 5 के साथ इंटीग्रेट करना: एक सहज फुल-स्टैक दृष्टिकोण Angular को Rails 5 के साथ इंटीग्रेट करना: एक सहज फुल-स्टैक दृष्टिकोण

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