রেল হল একটি বড় ফ্রেমওয়ার্ক যার মধ্যে নির্দিষ্ট পরিস্থিতির জন্য বিল্ট-ইন অনেক সহজ টুল রয়েছে। এই সিরিজে, আমরা রেলের বৃহৎ কোডবেসে লুকানো কিছু স্বল্প-পরিচিত সরঞ্জামের দিকে নজর দেব৷
এই নিবন্ধে, আমরা increment
ব্যাখ্যা করব এবং decrement
Rails.cache
-এ পদ্ধতি .
The Rails.cache সাহায্যকারী
Rails.cache
আপনার অ্যাপ্লিকেশনে ক্যাশের সাথে ইন্টারঅ্যাক্ট করার প্রবেশ পথ। এটি একটি বিমূর্ততাও, যা হুডের নীচে ব্যবহৃত প্রকৃত ক্যাশে "স্টোর" নির্বিশেষে আপনাকে কল করার জন্য একটি সাধারণ API দেয়। বাক্সের বাইরে, রেলগুলি নিম্নলিখিতগুলিকে সমর্থন করে:
- ফাইলস্টোর
- মেমরিস্টোর
- MemCacheStore
- নালস্টোর
- RedisCacheStore
Rails.cache
পরিদর্শন করা হচ্ছে আপনি কোনটি চালাচ্ছেন তা দেখাবে:
> Rails.cache
=> <#ActiveSupport::Cache::RedisCacheStore options={:namespace=>nil, ...
আমরা সেগুলিকে বিস্তারিতভাবে দেখব না, তবে একটি দ্রুত সারাংশ হিসাবে:
- NullStore কিছু সঞ্চয় করে না; এটি থেকে ফিরে পড়া সবসময়
nil
ফিরে আসবে . এটি একটি নতুন রেল অ্যাপের জন্য ডিফল্ট৷ - ফাইলস্টোর হার্ড ড্রাইভে ফাইল হিসাবে ক্যাশে সংরক্ষণ করে, তাই আপনি আপনার রেল সার্ভার পুনরায় চালু করলেও সেগুলি বজায় থাকে।
- MemoryStore ক্যাশে RAM এ রাখে, তাই আপনি যদি আপনার Rails সার্ভার বন্ধ করেন, আপনি ক্যাশেও মুছে ফেলবেন।
- MemCacheStore এবং RedisCacheStore ক্যাশে বজায় রাখার জন্য বহিরাগত প্রোগ্রাম (যথাক্রমে মেমক্যাচে এবং রেডিস) ব্যবহার করে।
বিভিন্ন কারণে, এখানে প্রথম তিনটি উন্নয়ন/পরীক্ষার জন্য প্রায়শই ব্যবহৃত হয়। উৎপাদনে, আপনি সম্ভবত Redis বা MemCache ব্যবহার করবেন।
কারণ Rails.cache
এই পরিষেবাগুলির মধ্যে পার্থক্যগুলিকে বিমূর্ত করে, কোড পরিবর্তন না করেই বিভিন্ন পরিবেশে বিভিন্ন সংস্করণ চালানো সহজ; উদাহরণস্বরূপ, আপনি NullStore
ব্যবহার করতে পারেন বিকাশে, MemoryStore
পরীক্ষায়, এবং RedisCacheStore
উৎপাদনে।
ক্যাশেড ডেটা
৷
Rails' Rails.cache.read
এর মাধ্যমে , Rails.cache.write
, এবং Rails.cache.fetch
, আমাদের কাছে ক্যাশে থেকে যেকোনো নির্বিচারে তথ্য সংরক্ষণ এবং পুনরুদ্ধার করার একটি সহজ উপায় রয়েছে। একটি পূর্ববর্তী নিবন্ধ আরো বিস্তারিতভাবে এই কভার; এই নিবন্ধের জন্য উল্লেখ করা গুরুত্বপূর্ণ বিষয় হল যে এই পদ্ধতিগুলিতে কোনও অন্তর্নির্মিত থ্রেড-নিরাপত্তা নেই। ধরা যাক চলমান গণনা রাখতে আমরা একাধিক থ্রেড থেকে ক্যাশে করা ডেটা আপডেট করছি; রেস কন্ডিশন এড়ানোর জন্য আমাদের রিড/রাইট অপারেশনটিকে এক ধরনের লকের মধ্যে মোড়ানো দরকার। এই উদাহরণটি বিবেচনা করুন, ধরে নিচ্ছি আমরা একটি Redis ক্যাশে স্টোর ব্যবহার করার জন্য জিনিসগুলি সেট আপ করেছি:
threads = []
# Set initial counter
Rails.cache.write(:test_counter, 0)
4.times do
threads << Thread.new do
100.times do
current_count = Rails.cache.read(:test_counter)
current_count += 1
Rails.cache.write(:test_counter, current_count)
end
end
end
threads.map(&:join)
puts Rails.cache.read(:test_counter)
এখানে আমাদের চারটি থ্রেড রয়েছে, প্রত্যেকটি আমাদের ক্যাশে করা মানকে একশত বার বৃদ্ধি করছে। ফলাফল 400 হওয়া উচিত, কিন্তু বেশিরভাগ সময়, এটি অনেক কম হবে - আমার পরীক্ষায় 269। এখানে যা ঘটছে তা একটি জাতিগত অবস্থা। আমি পূর্ববর্তী নিবন্ধে এগুলিকে আরও বিশদে কভার করেছি, তবে একটি দ্রুত সারাংশ হিসাবে, কারণ থ্রেডগুলি সমস্ত একই "ভাগ করা" ডেটাতে কাজ করে, তারা একে অপরের সাথে সিঙ্ক থেকে বেরিয়ে আসতে পারে। উদাহরণস্বরূপ, একটি থ্রেড মানটি পড়তে পারে, তারপর অন্য একটি থ্রেড গ্রহণ করে এবং মানটিও পড়ে, এটি বৃদ্ধি করে এবং এটি সংরক্ষণ করে। প্রথম থ্রেডটি তার এখন-সেকেলে-তারিখ মান ব্যবহার করে পুনরায় শুরু হয়।
এই সমস্যাটি সমাধান করার সাধারণ উপায় হল কোডটিকে একটি পারস্পরিক একচেটিয়া লক (বা Mutex) দিয়ে ঘিরে রাখা যাতে শুধুমাত্র একটি থ্রেড একবারে লকের মধ্যে কোড চালাতে পারে। আমাদের ক্ষেত্রে, যদিও, Rails.cache-এর এই দৃশ্যটি পরিচালনা করার জন্য কিছু পদ্ধতি রয়েছে।
রেল ক্যাশে বৃদ্ধি এবং হ্রাস
Rails.cache
বস্তুর উভয়ই increment
আছে এবং decrement
আমাদের পাল্টা দৃশ্যের মতো ক্যাশে করা ডেটাতে সরাসরি কাজ করার পদ্ধতি:
threads = []
# Set initial counter
Rails.cache.write(:test_counter, 0, raw: true)
4.times do
threads << Thread.new do
100.times do
Rails.cache.increment(:test_counter)
# repeating the increment just to highlight the thread safety
Rails.cache.decrement(:test_counter)
Rails.cache.increment(:test_counter)
end
end
end
threads.map(&:join)
puts Rails.cache.read(:test_counter, raw: true)
increment
ব্যবহার করতে এবং decrement
, আমাদের ক্যাশে স্টোরকে বলতে হবে এটি একটি 'raw' মান (এর মাধ্যমে raw: true
) পাশাপাশি মানটি পড়ার সময় আপনাকে এটি করতে হবে; অন্যথায়, আপনি একটি ত্রুটি পাবেন। মূলত, আমরা ক্যাশেকে বলছি যে আমরা এই মানটিকে একটি বেয়ার পূর্ণসংখ্যা হিসাবে সংরক্ষণ করতে চাই যাতে আমরা এটিকে বৃদ্ধি/হ্রাস কল করতে পারি, তবে আপনি এখনও expires_in
ব্যবহার করতে পারেন এবং একই সময়ে অন্যান্য ক্যাশে পতাকা।
এখানে মূল বিষয় হল increment
এবং decrement
পারমাণবিক অপারেশন ব্যবহার করুন (অন্তত রেডিস এবং মেমক্যাশের জন্য), যার অর্থ তারা থ্রেড নিরাপদ; পারমাণবিক ক্রিয়াকলাপের সময় থ্রেডের বিরতির কোন উপায় নেই।
এটি লক্ষণীয়, যদিও আমি এখানে আমার উদাহরণে এটি ব্যবহার করিনি, উভয় পদ্ধতিই নতুন মান ফেরত দেয়। অতএব, আপনি যদি নতুন কাউন্টার মানটি শুধুমাত্র আপডেট করার বাইরেও ব্যবহার করতে চান, তাহলে আপনি অতিরিক্ত read
ছাড়াই তা করতে পারেন। কল করুন।
রিয়েল-ওয়ার্ল্ড অ্যাপ্লিকেশন
এর মুখে, এই increment
এবং decrement
পদ্ধতিগুলিকে নিম্ন-স্তরের সাহায্যকারী পদ্ধতির মতো মনে হয়, যে ধরনের আপনি সম্ভবত শুধুমাত্র যদি আপনি একটি ব্যাকগ্রাউন্ড জব প্রসেসিং জেমের মতো কিছু বাস্তবায়ন বা রক্ষণাবেক্ষণ করেন তবেই আপনার যত্ন নিন। একবার আপনি তাদের সম্পর্কে জানলে, আপনি অবাক হতে পারেন যে তারা কোথায় কাজে আসতে পারে।
ডুপ্লিকেট নির্ধারিত ব্যাকগ্রাউন্ড কাজ একই সাথে চলমান এড়াতে আমি এটি একটি উত্পাদন অ্যাপ্লিকেশনে ব্যবহার করেছি। আমাদের ক্ষেত্রে, অনুসন্ধান সূচকগুলি আপডেট করতে, পরিত্যক্ত কার্টগুলি চিহ্নিত করতে এবং আরও অনেক কিছু করার জন্য আমাদের বিভিন্ন নির্ধারিত কাজ রয়েছে৷ সাধারণত, এটি সূক্ষ্ম কাজ করে; ধরা হল যে কিছু কাজ (বিশেষত অনুসন্ধান সূচকগুলি) প্রচুর মেমরি খরচ করে - যথেষ্ট যে, যদি দুটি একসাথে চালানো হয় তবে এটি আমাদের হেরোকু ডায়নোর সীমা অতিক্রম করবে এবং কর্মীকে হত্যা করা হবে। কারণ আমাদের কাছে এই কাজগুলির কয়েকটি রয়েছে, সেগুলিকে পুনরায় চেষ্টা না করা বা অনন্য কাজগুলিকে জোর করে চিহ্নিত করার মতো সহজ নয়; দুটি ভিন্ন (এবং এইভাবে অনন্য) কাজ একই সময়ে চালানোর চেষ্টা করতে পারে এবং কর্মীকে নামিয়ে আনতে পারে।
এটি প্রতিরোধ করার জন্য, আমরা নির্ধারিত কাজের জন্য একটি বেস ক্লাস তৈরি করেছি যা বর্তমানে কতজন চলছে তার কাউন্টার রাখে। যদি গণনা খুব বেশি হয়, কাজটি কেবল নিজেকে পুনরায় সারিবদ্ধ করে এবং অপেক্ষা করে৷
আরেকটি উদাহরণ ছিল আমার একটি পার্শ্ব-প্রকল্পে যেখানে একটি ব্যাকগ্রাউন্ড কাজ (বা একাধিক কাজ) কিছু প্রক্রিয়াকরণ করে যখন ব্যবহারকারীকে অপেক্ষা করতে হয়। এটি ব্যাকগ্রাউন্ড কাজের ব্যবহারকারীর কাছে বর্তমান অগ্রগতি যোগাযোগের সাধারণ সমস্যা নিয়ে আসে। যদিও এটি সমাধান করা যেতে পারে এমন অনেক উপায় আছে, একটি পরীক্ষা হিসাবে, আমি Rails.cache.increment
ব্যবহার করার চেষ্টা করেছি একটি বিশ্বব্যাপী উপলব্ধ কাউন্টার আপডেট করতে। গঠন নিম্নরূপ ছিল:
- প্রথম, আমি
/app/models
-এ একটি নতুন ক্লাস যোগ করেছি কাউন্টার ক্যাশে বাস যে দূরে বিমূর্ত. এটি হল যেখানে মানটির সমস্ত অ্যাক্সেস প্রবাহিত হবে। এর একটি অংশ হল কাজের সাথে সম্পর্কিত অনন্য ক্যাশে কী তৈরি করা। - চাকরিটি তারপর এই মডেলের একটি উদাহরণ তৈরি করে এবং আইটেমগুলি প্রক্রিয়া করার সাথে সাথে এটি আপডেট করে৷
- বর্তমান মান ধরতে একটি সাধারণ JSON এন্ডপয়েন্ট এই মডেলের একটি উদাহরণ তৈরি করে৷
- ইউআই আপডেট করতে ফ্রন্ট-এন্ড প্রতি কয়েক সেকেন্ডে এই এন্ডপয়েন্টে পোল করে। আপনি অবশ্যই অ্যাকশনকেবলের মতো কিছু দিয়ে এটিকে আরও উন্নত করতে পারেন এবং আপডেটগুলি পুশ আউট করতে পারেন৷
উপসংহার
সত্যি বলতে, Rails.cache.increment
আমি প্রায়শই পৌঁছাতে পারি এমন একটি সরঞ্জাম নয়, কারণ এটি প্রায়শই হয় না যে আমি ক্যাশে সংরক্ষিত ডেটা আপডেট করতে চাই (যা প্রকৃতির দ্বারা, কিছুটা অস্থায়ী)। উপরে উল্লিখিত হিসাবে, আমি যে সময়গুলিতে পৌঁছতে পারি তা সাধারণত ব্যাকগ্রাউন্ড কাজের সাথে সম্পর্কিত কারণ চাকরিগুলি ইতিমধ্যেই তাদের ডেটা Redis-এ সংরক্ষণ করছে (অন্তত বেশিরভাগ অ্যাপে আমি কাজ করেছি) এবং এটি সাধারণত অস্থায়ী। এই ধরনের ক্ষেত্রে, স্বল্প-মেয়াদী অধ্যবসায়ের একই স্তরের সাথে একই জায়গায় সম্পর্কিত ডেটা (শতাংশ সম্পূর্ণ, উদাহরণস্বরূপ) সংরক্ষণ করা স্বাভাবিক বলে মনে হয়।
"পিটানো পথের বাইরে" সমস্ত জিনিসের মতো, আপনার কোডবেসে এই জাতীয় জিনিসগুলি প্রবর্তন করার বিষয়ে আপনার সতর্ক হওয়া উচিত। আমি সুপারিশ করব, অন্তত, ভবিষ্যতের বিকাশকারীদের ব্যাখ্যা করার জন্য কিছু মন্তব্য যোগ করার জন্য আপনি কেন এই পদ্ধতিটি ব্যবহার করছেন যেটির সাথে তারা সম্ভবত পরিচিত নয়৷