ActiveRecord रूबी ऑन रेल्स की सबसे जादुई विशेषता है। हमें आमतौर पर इसके आंतरिक कामकाज के बारे में चिंता करने की ज़रूरत नहीं है, लेकिन जब हम ऐसा करते हैं, तो यहां बताया गया है कि ऐपसिग्नल हमें यह जानने में मदद कर सकता है कि हुड के नीचे क्या हो रहा है।
ActiveRecord क्या है?
ActiveRecord के बारे में बात करने के लिए, हमें पहले फ्रेमवर्क के बारे में सोचना होगा, विशेष रूप से MVC फ्रेमवर्क के बारे में। एमवीसी मॉडल-व्यू-कंट्रोलर के लिए खड़ा है, और यह ग्राफिकल और वेब अनुप्रयोगों के लिए एक लोकप्रिय सॉफ्टवेयर डिज़ाइन पैटर्न है।
MVC फ्रेमवर्क निम्न से बना होता है:
- मॉडल :व्यापार तर्क और डेटा दृढ़ता को संभालता है।
- देखें :प्रेजेंटेशन लेयर को ड्राइव करता है और यूजर इंटरफेस को ड्रा करता है।
- नियंत्रक :सब कुछ एक साथ जोड़ता है।
ActiveRecord मॉडल . है रेल ढांचे में रूबी में घटक। यह कोड और डेटा के बीच एक अमूर्त परत का परिचय देता है, इसलिए हमें स्वयं SQL कोड लिखने की आवश्यकता नहीं है। प्रत्येक मॉडल को एक तालिका में मैप किया जाता है और सीआरयूडी संचालन करने के लिए विभिन्न विधियां प्रदान करता है (बनाएं, पढ़ें, अपडेट करें और हटाएं)।
AppSignal के साथ ActiveRecord की निगरानी करना
एब्स्ट्रैक्शन जादुई लगते हैं - वे हमें उन विवरणों को अनदेखा करने में मदद करते हैं जिन्हें हमें जानने की आवश्यकता नहीं है और हाथ में कार्य पर ध्यान केंद्रित करते हैं। लेकिन जब चीजें अपेक्षित रूप से काम नहीं करती हैं, तो वे जो जटिलता जोड़ते हैं, वह मूल कारण को निर्धारित करना कठिन बना सकती है। AppSignal हमें रेल में वास्तव में क्या हो रहा है, इसका विस्तृत विवरण दे सकता है।
प्रतिक्रिया समय ग्राफ
आइए पहले समस्या पर एक नज़र डालें। प्रदर्शन समस्याओं का निवारण एक पुनरावृत्तीय प्रक्रिया है। एक बार जब आप अपने रेल एप्लिकेशन को AppSignal पर रिपोर्ट कर लेते हैं, तो घटनाओं . पर जाएं> प्रदर्शन ।
प्रतिक्रिया समय ग्राफ प्रत्येक नाम स्थान के लिए प्रतिक्रिया समय प्रतिशतक दिखाएगा। ActiveRecord ईवेंट स्वचालित रूप से नेमस्पेस को उस अनुरोध या पृष्ठभूमि कार्य को असाइन किया जाता है जिसमें क्वेरी निष्पादित की जाती हैं।
इसके बाद, इवेंट ग्रुप ग्राफ़ देखें। यह दर्शाता है कि श्रेणी के अनुसार कितना समय लगता है। active_record
. द्वारा देखें कि कितना सापेक्ष समय व्यतीत होता है . अपने सभी नामस्थानों में उपयोग की जाँच करें।
ग्राफ़ हमें तुरंत बताएगा कि हमें अपने कोड-अनुकूलन प्रयासों पर ध्यान केंद्रित करना चाहिए।
जब आप प्रदर्शन ग्राफ़ डैशबोर्ड में हों, तो यह सुनिश्चित करने के लिए प्रतिक्रिया समय और थ्रूपुट की जांच करें कि आपके आवेदन पर कोई सामान्य से अधिक गतिविधि तो नहीं है।
धीमी क्वेरी डैशबोर्ड
अब जबकि हमने पहचान लिया है कि समस्या डेटा-बाउंड है, आइए देखें कि क्या हम मूल कारण निर्धारित करने के लिए ज़ूम इन कर सकते हैं।
खोलें सुधारें> धीमी क्वेरी डैशबोर्ड। यह पृष्ठ समग्र समय पर प्रभाव के आधार पर क्रमबद्ध SQL प्रश्नों की सूची दिखाता है। सभी ActiveRecord-उत्पत्ति क्वेरी को sql.active_record
. के रूप में दिखाया जाता है इवेंट.
इसके विवरण देखने के लिए सबसे ऊपरी क्वेरी पर क्लिक करने का प्रयास करें। डैशबोर्ड औसत अवधि और क्वेरी टेक्स्ट दिखाता है।
नीचे स्क्रॉल करने से आपको पिछले कुछ घंटों में क्वेरी का प्रतिक्रिया समय और आरंभिक कार्रवाई दिखाई देगी।
आप पा सकते हैं कि कुछ कार्रवाइयों में एक संबद्ध घटना है। इसका मतलब यह है कि जब क्वेरी चल रही थी तब ऐपसिग्नल ने एक प्रदर्शन घटना बनाई, लेकिन इसका मतलब यह नहीं है कि ActiveRecord इसका कारण है।
प्रदर्शन मापन डैशबोर्ड
प्रदर्शन माप की घटनाएं तब खुलती हैं जब AppSignal एक नया समापन बिंदु या पृष्ठभूमि कार्य रिकॉर्ड करता है।
घटनाएँ प्रदर्शन . पर स्थित हैं> समस्या सूची डैशबोर्ड।
घटना पृष्ठ प्रत्येक MVC घटकों के लिए बीता हुआ समय और आवंटन की संख्या दिखाता है। ActiveRecord समस्याएं active_record
. में लंबी अवधि प्रदर्शित करेंगी श्रेणी।
इवेंट टाइमलाइन दिखाती है कि इवेंट समय के साथ कैसे आगे बढ़ा।
ActiveRecord समस्याओं का पता लगाना
इस अनुभाग में, हम देखेंगे कि कैसे AppSignal कुछ सामान्य ActiveError समस्याओं की पहचान करने में हमारी सहायता कर सकता है।
प्रासंगिक स्तंभों का चयन करना
डेटाबेस ज्ञान कहता है कि हमें नौकरी के लिए आवश्यक कॉलम हमेशा प्राप्त करना चाहिए। उदाहरण के लिए, SELECT * FROM people
. के बजाय हमें SELECT first_name, surname, birthdate FROM people
. यह सब ठीक है और अच्छा है, लेकिन हम इसे रेल पर कैसे करते हैं?
डिफ़ॉल्ट रूप से, ActiveRecord सभी स्तंभों को पुनः प्राप्त करता है।
Person.all.each {
# process data
}
सौभाग्य से, हमारे पास select
है आवश्यक कॉलम चुनने और चुनने की विधि:
Person.select(:name, :address, :birthdate).each {
# process data
}
ऐसा लग सकता है कि मैं छोटी-छोटी बातों को लेकर जुनूनी हूं। लेकिन विस्तृत तालिकाओं पर, सभी स्तंभों का चयन करना व्यर्थ है। आप देखेंगे कि जब ऐसा होता है, तो ActiveRecord मेमोरी का बड़ा हिस्सा आवंटित करता है:
N+1 समस्याएं
एन + 1 समस्या तब होती है जब एप्लिकेशन को डेटाबेस से रिकॉर्ड का एक सेट मिलता है और इसके माध्यम से लूप होता है। यह एप्लिकेशन को एन + 1 प्रश्नों को निष्पादित करने का कारण बनता है, जहां एन शुरू में प्राप्त पंक्तियों की संख्या है। जैसा कि आप कल्पना कर सकते हैं, तालिका बढ़ने पर यह पैटर्न खराब होता है। यह इतनी हानिकारक समस्या है कि AppSignal विशेष रूप से आपको इसके बारे में चेतावनी देता है:
N+1 समस्याएं आमतौर पर संबद्ध मॉडलों के साथ दिखाई देती हैं। कल्पना कीजिए कि हमारे पास एक व्यक्ति मॉडल है:
class Person < ApplicationRecord
has_many :addresses
end
प्रत्येक व्यक्ति के कई पते हो सकते हैं:
class Address < ApplicationRecord
belongs_to :person
end
डेटा पुनर्प्राप्त करने का सबसे सीधा तरीका N+1 समस्या की ओर ले जाता है:
class RelatedTablesController < ApplicationController
def index
Person.all.each do |person|
person.addresses.each do |address|
address.address
end
end
end
end
आप AppSignal में देख सकते हैं कि एप्लिकेशन SELECT
. पर चल रहा है प्रति व्यक्ति:
इस विशेष मामले के लिए फिक्स सरल है:उपयोग शामिल है, जो आवश्यक कॉलम के लिए क्वेरी को अनुकूलित करने के लिए ActiveRecord को बताता है:
class RelatedTablesController < ApplicationController
def index
Person.all.includes(:addresses).each do |person|
person.addresses.each do |address|
address.address
end
end
end
end
अब हमारे पास N+1 के बजाय दो प्रश्न हैं:
Processing by RelatedTablesController#index as HTML
(0.2ms) SELECT sqlite_version(*)
↳ app/controllers/related_tables_controller.rb:12:in `index'
Person Load (334.6ms) SELECT "people".* FROM "people"
↳ app/controllers/related_tables_controller.rb:12:in `index'
Address Load (144.4ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."person_id" IN (1, 2, 3, . . .)
प्रति तालिका कम से कम आवश्यक क्वेरी निष्पादित करें
यह कभी-कभी N+1 समस्या से भ्रमित होता है, लेकिन यह थोड़ा अलग है। जब हम किसी तालिका को क्वेरी करते हैं, तो हमें वह सभी डेटा पुनर्प्राप्त करना चाहिए जो हमें लगता है कि हमें पढ़ने के संचालन को कम करने की आवश्यकता होगी। हालाँकि, बहुत सारे निर्दोष दिखने वाले कोड हैं जो अनावश्यक प्रश्नों को ट्रिगर करते हैं। उदाहरण के लिए, देखें कैसे count
हमेशा एक SELECT COUNT(*)
में परिणत होता है निम्नलिखित दृश्य में क्वेरी:
<ul>
<% @people.each do |person| %>
<li><%= person.name %></li>
<% end %>
</ul>
<h2>Number of Persons: <%= @people.count %></h2>
अब ActiveRecord दो प्रश्न करता है:
Rendering duplicated_table_query/index.html.erb within layouts/application
(69.1ms) SELECT COUNT(*) FROM "people" WHERE "people"."name" = ? [["name", "John Waters"]]
↳ app/views/duplicated_table_query/index.html.erb:3
Person Load (14.6ms) SELECT "people".* FROM "people" WHERE "people"."name" = ? [["name", "John Waters"]]
↳ app/views/duplicated_table_query/index.html.erb:6
AppSignal में, आप जो लक्षण देखेंगे, वह यह है कि दो active_record
. हैं एक ही टेबल पर इवेंट:
वास्तविकता यह है कि हमें दो प्रश्नों की आवश्यकता नहीं है; हमारे पास पहले से ही वह सभी डेटा है जो हमें मेमोरी में चाहिए। इस मामले में, समाधान count
. को स्वैप करना है size
. के साथ :
<ul>
<% @people.each do |person| %>
<li><%= person.name %></li>
<% end %>
</ul>
<h2>Number of Persons: <%= @people.size %></h2>
अब हमारे पास एक ही SELECT
है , जैसा होना चाहिए:
Rendering duplicated_table_query/index.html.erb within layouts/application
Person Load (63.2ms) SELECT "people".* FROM "people" WHERE "people"."name" = ? [["name", "Abdul Strosin"]]
↳ app/views/duplicated_table_query/index.html.erb:5
एक अन्य समाधान मेमोरी में डेटा को कैश करने के लिए प्रीलोड का उपयोग करना है।
रेल में समेकित डेटा की गणना करना
डेटा के एक सेट के आधार पर मूल्य की गणना करने के लिए एकत्रीकरण का उपयोग किया जाता है। डेटाबेस बड़े डेटासेट के साथ काम करने में बहुत अच्छे होते हैं। यह वही है जो वे करते हैं और जिसके लिए हम उनका उपयोग करते हैं। दूसरी ओर, रेल को एग्रीगेट करने का पैमाना नहीं है क्योंकि इसके लिए डेटाबेस से सभी रिकॉर्ड प्राप्त करने, उन्हें मेमोरी में रखने और फिर उच्च-स्तरीय कोड का उपयोग करके गणना करने की आवश्यकता होती है।
जब भी हम रूबी फ़ंक्शन जैसे max
. का सहारा लेते हैं, हम रेल में एकत्रीकरण कर रहे हैं , min
, या sum
ActiveRecord तत्वों या अन्य गणनाओं पर।
class AggregatedColumnsController < ApplicationController
def index
@mean = Number.pluck(:number).sum()
end
end
सौभाग्य से, ActiveRecord मॉडल में विशिष्ट विधियाँ शामिल होती हैं जो डेटाबेस में एकत्रीकरण कार्यों को मैप करती हैं। उदाहरण के लिए, निम्न क्वेरी मैप SELECT SUM(number) FROM ...
, जो पिछले उदाहरण की तुलना में चलाने में बहुत तेज़ और सस्ता है:
# controller
class AggregatedColumnsController < ApplicationController
def index
@mean = Number.sum(:number)
end
end
Processing by AggregatedColumnsController#index as */*
(2.4ms) SELECT SUM("numbers"."number") FROM "numbers"
यदि आपको अधिक जटिल या संयुक्त एकत्रीकरण कार्यों की आवश्यकता है, तो आपको थोड़ा कच्चा SQL कोड शामिल करने की आवश्यकता हो सकती है:
sql = "SELECT AVG(number), STDDEV(number), VAR(number) FROM ..."
@results = ActiveRecord::Base.connection.execute(sql)
बड़े लेन-देन का प्रबंधन
SQL लेनदेन सुसंगत और परमाणु अद्यतन सुनिश्चित करते हैं। जब हम परिवर्तन करने के लिए लेन-देन का उपयोग करते हैं, तो या तो प्रत्येक पंक्ति को सफलतापूर्वक अपडेट किया जाता है, या पूरी चीज़ को वापस ले लिया जाता है। किसी भी स्थिति में, डेटाबेस हमेशा एक सुसंगत स्थिति में रहता है।
हम ActiveRecord::Base.transaction
के साथ एकल लेनदेन में परिवर्तनों के एक बैच को बंडल कर सकते हैं ।
class BigTransactionController < ApplicationController
def index
ActiveRecord::Base.transaction do
(1..1000).each do
Person.create(name: 'Les Claypool')
end
end
end
end
बड़े लेनदेन का उपयोग करने के लिए बहुत सारे वैध मामले हैं। हालाँकि, ये डेटाबेस को धीमा करने के जोखिम में चलते हैं। इसके अलावा, कुछ थ्रेशोल्ड से अधिक के लेन-देन के परिणामस्वरूप डेटाबेस उन्हें अस्वीकार कर देगा।
लेन-देन के बहुत बड़े होने का पहला संकेत commit transaction
. पर बहुत समय व्यतीत करना है इवेंट:
डेटाबेस पर ही कॉन्फ़िगरेशन समस्याओं को छोड़कर, समाधान लेन-देन को छोटे टुकड़ों में तोड़ना है।
डेटाबेस की निगरानी
कभी-कभी हम कोड को खोजने के बाद भी उसमें कुछ भी गलत नहीं पाते हैं। फिर, डेटाबेस में ही कोई समस्या हो सकती है। डेटाबेस इंजन जटिल हैं, और कई चीजें गलत हो सकती हैं:कम मेमोरी, डिफ़ॉल्ट सेटिंग्स, लापता इंडेक्स, असुविधाजनक रूप से शेड्यूल किए गए बैकअप कार्य। जब तक हमें डेटाबेस चलाने वाली मशीन के बारे में जानकारी नहीं मिलती, तब तक तस्वीर पूरी नहीं हो सकती।
यदि हम अपना स्वयं का डेटाबेस चला रहे हैं, तो हम होस्ट मेट्रिक्स को कैप्चर करने के लिए स्टैंडअलोन एजेंट स्थापित कर सकते हैं। स्टैंडअलोन एजेंट का उपयोग करने के तरीके के बारे में अधिक जानने के लिए, पढ़ें:StatsD और AppSignal के स्टैंडअलोन एजेंट के साथ किसी भी सिस्टम की निगरानी करना।
निम्नलिखित संकेत दिखा सकते हैं कि डेटाबेस के साथ कुछ चल रहा है। निरीक्षण . पर जाएं> होस्ट मीट्रिक अपने सर्वर में संसाधन उपयोग देखने के लिए डैशबोर्ड:
- उच्च स्मृति उपयोग :डेटाबेस को सही ढंग से चलाने के लिए - अधिकांश अन्य प्रणालियों की तुलना में बहुत अधिक मेमोरी की आवश्यकता होती है। जैसे-जैसे डेटासेट बढ़ता है, मेमोरी की ज़रूरतें आम तौर पर बढ़ती जाती हैं। हमें समय-समय पर या तो अधिक मेमोरी जोड़ने या डेटासेट को विभिन्न मशीनों में विभाजित करने की आवश्यकता होगी।
- उपयोग बदलें :आदर्श रूप से, डेटाबेस मशीनों को स्वैप मेमोरी की बिल्कुल भी आवश्यकता नहीं होनी चाहिए। स्वैपिंग डेटाबेस प्रदर्शन को मारता है। इसकी उपस्थिति का अर्थ है कि अधिक गहन कॉन्फ़िगरेशन या स्मृति समस्या है।
- उच्च I/O उपयोग :डिस्क गतिविधि में शिखर रखरखाव कार्यों के कारण हो सकता है जैसे डेटाबेस को पुन:अनुक्रमणित करना या बैकअप लेना। व्यस्त समय के दौरान इन कार्यों को करने से निश्चित रूप से प्रदर्शन प्रभावित होगा।
👋 यदि आप इस लेख को पसंद करते हैं, तो हमने रूबी (ऑन रेल्स) के प्रदर्शन के बारे में और भी बहुत कुछ लिखा है, हमारी रूबी प्रदर्शन निगरानी चेकलिस्ट देखें।
निष्कर्ष
प्रदर्शन के मुद्दों का निदान करना कभी आसान काम नहीं होता है। आज, हमने सीखा है कि समस्या के स्रोत का शीघ्रता से पता लगाने के लिए Appsignal का उपयोग कैसे किया जाता है।
आइए रेल पर ऐपसिग्नल और रूबी के बारे में सीखते रहें:
- ActiveRecord प्रदर्शन:N+1 क्वेरी एंटीपैटर्न
- रेल तेज़ है:अपने दृश्य प्रदर्शन को अनुकूलित करें
- रूबी ऑन रेल्स पैटर्न और एंटी-पैटर्न का परिचय
पी.एस. यदि आप रूबी मैजिक की पोस्ट प्रेस से छूटते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूजलेटर की सदस्यता लें और एक भी पोस्ट मिस न करें!