কম্পিউটার

রেল অ্যাপ্লিকেশনে রুবিতে HTTP ক্যাশিং

ক্যাশে বর্ণনা করার একটি সাধারণ উপায় হল কিছু ডেটা সংরক্ষণ করা যাতে আমরা দ্রুত এটিকে পরে পুনরুদ্ধার করতে পারি। কখনও কখনও, এর অর্থ গণনা করা ডেটা সংরক্ষণ করা যাতে এটি পুনরায় গণনা করার প্রয়োজন না হয়, তবে এটি আবার আনার প্রয়োজন এড়াতে স্থানীয়ভাবে ডেটা সংরক্ষণের কথাও উল্লেখ করতে পারে। আপনার কম্পিউটার ক্রমাগত এটি করে, কারণ আপনার অপারেটিং সিস্টেম ঘন ঘন অ্যাক্সেস করা ডেটা RAM-তে রাখার চেষ্টা করে যাতে এটি আবার হার্ড ড্রাইভ বা SSD থেকে আনতে না হয়।

একইভাবে, আপনার ব্রাউজার এটি ইতিমধ্যে ডাউনলোড করা সংস্থানগুলি পুনরায় ব্যবহার করার চেষ্টা করে৷ প্রথমবার একটি নতুন ওয়েবসাইট দেখার সময় আপনি সম্ভবত এটি নিজেই দেখেছেন৷ প্রাথমিক লোড বেশি সময় নেয় কারণ আপনার ব্রাউজারকে সবকিছু টানতে হবে সমস্ত ছবি, জাভাস্ক্রিপ্ট এবং স্টাইলশীট সহ এটির প্রয়োজন। একটি মজার তথ্য হল যে আপনি যখন নতুনভাবে CNN হোমপেজ ডাউনলোড করেন, তখন আপনার ব্রাউজারটি 1993 সালের মূল ডুম গেমের চেয়ে বেশি ডেটা নিয়ে আসে। কৌতূহলীদের জন্য, এই ব্লগ পোস্টটি লেখার সময়, CNN আমার মেশিনে মাত্র 3MB ডাউনলোড করে, যা থেকে সংকুচিত হয় ~15MB, এবং এটি একটি অ্যাড ব্লকার সক্ষম করে, যখন মূল ডুম ইনস্টলার ছিল ~2.2MB।

ব্রাউজার এই ডেটা ক্যাশে করার জন্য, সার্ভারের সাথে কিছু সমন্বয় থাকা দরকার। ব্রাউজারকে জানতে হবে এটি কী ক্যাশে করতে পারে এবং কতক্ষণের জন্য; অন্যথায়, সার্ভারে একটি নতুন সংস্করণ উপলব্ধ থাকলে এটি আপনাকে পুরানো সামগ্রী দেখাতে পারে। এই নিবন্ধে, আমরা দেখব কিভাবে এই ক্লায়েন্ট-সার্ভার ক্যাশিং সমন্বয় করা হয় এবং রেলগুলি এটিকে পরিবর্তন করার জন্য কী প্রদান করে৷

যদিও রুবি অন রেলগুলি কীভাবে এটি পরিচালনা করে তার উপর ফোকাস করা হয়, প্রকৃত প্রক্রিয়াটি HTTP স্পেসিফিকেশনের অংশ। অন্য কথায়, আমরা এখানে যে ক্যাশিংয়ের কথা বলছি তা ইন্টারনেটের পরিকাঠামোর মধ্যে বেক করা হয়েছে, যা এটিকে আধুনিক ওয়েবসাইট এবং ফ্রেমওয়ার্কগুলি কীভাবে তৈরি করা হয় তার ভিত্তি করে তোলে। বিভিন্ন ফ্রেমওয়ার্ক, যেমন রেল, একক-পৃষ্ঠা অ্যাপ্লিকেশন (এসপিএ) এবং এমনকি স্ট্যাটিক সাইটগুলি, কর্মক্ষমতা উন্নত করতে সাহায্য করতে এই প্রক্রিয়াগুলি ব্যবহার করতে পারে৷

HTTP অনুরোধ-প্রতিক্রিয়া

আপনি সম্ভবত অনুরোধ-প্রতিক্রিয়া জীবনচক্রের সাথে পরিচিত, অন্তত একটি উচ্চ স্তরে:আপনি একটি ওয়েবসাইটে একটি লিঙ্কে ক্লিক করেন, আপনার ব্রাউজার সেই সামগ্রীর জন্য সার্ভারে একটি অনুরোধ পাঠায় এবং সার্ভার সেই সামগ্রীটি ফেরত পাঠায় (উল্লেখ্য যে আমি আমি ইচ্ছাকৃতভাবে এখানে অনেক জটিলতার উপর আলোকপাত করছি)।

এই পিছনে এবং সামনে লেনদেনে পাঠানো হচ্ছে প্রকৃত তথ্য মধ্যে একটু খনন করা যাক. প্রতিটি HTTP বার্তার একটি শিরোনাম এবং একটি বডি রয়েছে (<head> এর সাথে বিভ্রান্ত হবেন না এবং <body> এইচটিএমএল ট্যাগ)। অনুরোধ শিরোনাম সার্ভারকে বলে যে আপনি কোন পথটি অ্যাক্সেস করার চেষ্টা করছেন এবং কোন HTTP পদ্ধতিটি ব্যবহার করবেন (যেমন, GET/PUT/PATCH/POST)। প্রয়োজনে, আপনি হয় আপনার ব্রাউজারের ডেভেলপার টুল বা কমান্ড-লাইন টুল, যেমন curl ব্যবহার করে এই শিরোনামগুলি খনন করতে পারেন। :

# curl -v honeybadger.io
...
> GET / HTTP/1.1
> Host: honeybadger.io
> User-Agent: curl/7.64.1
> Accept: */*

আউটপুট এই প্রথম অংশ অনুরোধ শিরোনাম হয়. আমরা একটি GET জারি করছি honeybadger.io-এ . এর পরে সার্ভার যা ফেরত পাঠিয়েছে ("প্রতিক্রিয়া শিরোনাম"):

>
< HTTP/1.1 301 Moved Permanently
< Cache-Control: public, max-age=0, must-revalidate
< Content-Length: 39
< Content-Security-Policy: frame-ancestors 'none'
...
< Content-Type: text/plain

প্রতিক্রিয়াটিতে HTTP কোড অন্তর্ভুক্ত রয়েছে (যেমন, 200 সাফল্যের জন্য অথবা 404 খুঁজে পাওয়া যায়নি জন্য)। এই উদাহরণে, এটি একটি স্থায়ী পুনঃনির্দেশ (301) কারণ কার্ল http-এর সাথে যোগাযোগ করার চেষ্টা করছে URL, যা নিরাপদ https-এ পুনঃনির্দেশ করে URL. প্রতিক্রিয়া শিরোনামটিতে সামগ্রীর ধরনও রয়েছে, যা হল text/plain এখানে, কিন্তু কিছু অন্যান্য সাধারণ বিকল্প হল text/html , text/css , text/javascript , এবং application/json .

প্রতিক্রিয়া বডি হেডার অনুসরণ করে। আমাদের ক্ষেত্রে, বডি ফাঁকা কারণ একটি 301 পুনঃনির্দেশ একটি শরীরের প্রয়োজন নেই. যদি আমরা curl -v https://www.honeybadger.io দিয়ে আবার চেষ্টা করি , আপনি এখানে হোমপেজের বিষয়বস্তু দেখতে পাবেন, যেমন আপনি একটি ব্রাউজারে উৎস দেখছেন।

আপনি যদি এটি নিজে পরীক্ষা করতে চান তবে এখানে দুটি টিপস রয়েছে:

  1. শুধুমাত্র কার্ল সহ প্রতিক্রিয়া শিরোনাম দেখানোর জন্য (যেমন, কোন অনুরোধ শিরোনাম বা প্রতিক্রিয়া বডি নেই), -I ব্যবহার করুন বিকল্প, যেমন curl -I localhost:3000 .
  2. ডিফল্টরূপে, রেল একটি উন্নয়ন পরিবেশে ক্যাশে করে না; আপনাকে rails dev:cache চালানোর প্রয়োজন হতে পারে প্রথম।

ক্যাশে-কন্ট্রোল HTTP হেডার

আমরা যে প্রধান শিরোনামটির বিষয়ে যত্নশীল, যতদূর ক্যাশিং যায়, তা হল Cache-Control হেডার এটি নির্ধারণ করতে সাহায্য করে কোন মেশিনগুলি আমাদের Rails সার্ভার থেকে একটি প্রতিক্রিয়া ক্যাশে করতে পারে এবং কখন সেই ক্যাশ করা ডেটার মেয়াদ শেষ হয়৷ Cache-Control-এর মধ্যে শিরোনাম, বেশ কয়েকটি ক্ষেত্র রয়েছে, যার বেশিরভাগই ঐচ্ছিক। আমরা এখানে সবচেয়ে প্রাসঙ্গিক কিছু এন্ট্রির মধ্য দিয়ে যাব, কিন্তু আরও তথ্যের জন্য, আপনি w3.org-এ অফিসিয়াল HTTP স্পেক চেক করতে পারেন।

এখানে একটি মৌলিক আউট-অফ-দ্য-বক্স রেল প্রতিক্রিয়া শিরোনাম থেকে একটি নমুনা রয়েছে:

< Content-Type: text/html; charset=utf-8
< Etag: W/"b41ce6c6d4bde17fd61a09e36b1e52ad"
< Cache-Control: max-age=0, private, must-revalidate

সর্বোচ্চ বয়স

max-age ক্ষেত্র হল একটি পূর্ণসংখ্যা যেখানে প্রতিক্রিয়াটি বৈধ সেকেন্ডের সংখ্যা রয়েছে। ডিফল্টরূপে, একটি দৃশ্যের জন্য একটি Rails প্রতিক্রিয়া 0 এ সেট থাকবে (অর্থাৎ, প্রতিক্রিয়া অবিলম্বে শেষ হয়ে যায়, এবং ব্রাউজার সর্বদা একটি নতুন সংস্করণ পাওয়া উচিত)।

সর্বজনীন/ব্যক্তিগত

public সহ অথবা private হেডার সেটে কোন সার্ভারকে প্রতিক্রিয়া ক্যাশে করার অনুমতি দেওয়া হয়। যদি হেডারে private অন্তর্ভুক্ত থাকে , এটি শুধুমাত্র অনুরোধকারী ক্লায়েন্ট (যেমন, ব্রাউজার) দ্বারা ক্যাশে করা হবে, সেখানে পৌঁছানোর জন্য অন্য কোনো সার্ভার নয়, যেমন সামগ্রী বিতরণ নেটওয়ার্ক (CDN) বা প্রক্সি। যদি হেডারে public অন্তর্ভুক্ত থাকে , তারপর এই মধ্যস্থতাকারী সার্ভারগুলিকে প্রতিক্রিয়া ক্যাশে করার অনুমতি দেওয়া হয়। রেল প্রতিটি হেডারকে private এ সেট করে ডিফল্টরূপে।

অবশ্যই পুনঃপ্রমাণিত করুন

রেলগুলি must-revalidate সেট করে ডিফল্টরূপে ক্ষেত্র। এর মানে হল যে ক্লায়েন্টকে অবশ্যই সার্ভারের সাথে যোগাযোগ করতে হবে তা নিশ্চিত করতে যে এটির ক্যাশে করা সংস্করণটি ব্যবহার করার আগে এখনও বৈধ। ক্যাশে করা সংস্করণটি বৈধ কিনা তা নির্ধারণ করতে, ক্লায়েন্ট এবং সার্ভার ETags ব্যবহার করে৷

ETags

ETags হল একটি ঐচ্ছিক HTTP হেডার যা সার্ভার দ্বারা যোগ করা হয় যখন এটি ক্লায়েন্টকে একটি প্রতিক্রিয়া পাঠায়। সাধারণত, এটি প্রতিক্রিয়া নিজেই চেকসাম কিছু সাজানোর. যখন ক্লায়েন্টকে (অর্থাৎ, আপনার ব্রাউজার) আবার এই সংস্থানটির জন্য অনুরোধ করতে হবে, তখন এটি If-None-Match-এ প্রাপ্ত Etagটি (অনুমান করে এটির একটি পূর্ববর্তী প্রতিক্রিয়া ক্যাশ করা আছে) অন্তর্ভুক্ত করে। HTTP হেডার। সার্ভার তখন একটি 304 দিয়ে প্রতিক্রিয়া জানাতে পারে HTTP কোড ("সংশোধিত নয়") এবং একটি খালি বডি। এর মানে সার্ভারের সংস্করণটি পরিবর্তিত হয়নি, তাই ক্লায়েন্টের ক্যাশে করা সংস্করণ ব্যবহার করা উচিত।

দুই ধরনের ETags আছে:শক্তিশালী এবং দুর্বল (একটি দুর্বল ট্যাগ W/ দিয়ে চিহ্নিত করা হয় উপসর্গ)। তারা একইভাবে আচরণ করে, কিন্তু একটি শক্তিশালী ETag মানে সম্পদের দুটি কপি (সার্ভারে সংস্করণ এবং স্থানীয় ক্যাশে) 100% বাইট-ফর-বাইট অভিন্ন। দুর্বল ETags, যাইহোক, নির্দেশ করে যে দুটি কপি বাইট-ফর-বাইট অভিন্ন নাও হতে পারে, তবে ক্যাশে করা সংস্করণটি এখনও ব্যবহার করা যেতে পারে। এর একটি সাধারণ উদাহরণ হল Rails' csrf_meta_tags সাহায্যকারী, যা একটি টোকেন তৈরি করে যা ক্রমাগত পরিবর্তিত হয়; এইভাবে, আপনার অ্যাপ্লিকেশানে একটি স্ট্যাটিক পৃষ্ঠা থাকলেও, ক্রস-সাইট-রিকোয়েস্ট-ফোরজি (CSRF) টোকেনের কারণে এটি রিফ্রেশ করার সময় এটি বাইট-ফর-বাইট অভিন্ন হবে না। রেলগুলি ডিফল্টরূপে দুর্বল ETags ব্যবহার করে৷

রেলের মধ্যে ETags

রেলগুলি দৃশ্যগুলিতে স্বয়ংক্রিয়ভাবে ETags পরিচালনা করে৷ এটি বহির্গামী শিরোনামগুলিতে ETag অন্তর্ভুক্ত করে এবং ইনকামিং ETag শিরোনাম এবং রিটার্ন 304 চেক করার জন্য মিডলওয়্যার রয়েছে (সংশোধিত নয়) কোড যখন উপযুক্ত। উল্লেখযোগ্যভাবে, যাইহোক, যেহেতু রেলগুলি গতিশীলভাবে ভিউ তৈরি করে, সেই ভিউটির জন্য ETag বের করার আগে এটিকে এখনও সমস্ত রেন্ডারিং কাজ করতে হবে। এর মানে হল এমনকি যদি ETags মিলে যায়, আপনি শুধুমাত্র নেটওয়ার্ক জুড়ে ডেটা পাঠাতে যে সময় এবং ব্যান্ডউইথ লাগে তা সাশ্রয় করছেন, ভিউ ক্যাশিংয়ের মতো কিছুর বিপরীতে, যেখানে ক্যাশে ভার্সন থাকলে আপনি রেন্ডারিং ধাপটি সম্পূর্ণভাবে এড়িয়ে যেতে পারেন। যাইহোক, রেল জেনারেট করা ETag টি টুইক করার কয়েকটি উপায় প্রদান করে।

বাসি?

ETag পরিবর্তন থেকে চির-পরিবর্তনশীল CSRF টোকেনকে কাটিয়ে ওঠার একটি উপায় হল stale? ActionController-এ সাহায্যকারী . এটি আপনাকে সরাসরি ETag (হয় শক্তিশালী বা দুর্বল) সেট করতে দেয়। যাইহোক, আপনি এটিকে সহজভাবে একটি বস্তু পাস করতে পারেন, যেমন একটি ActiveRecord মডেল, এবং এটি বস্তুর updated_at এর উপর ভিত্তি করে ETag গণনা করবে টাইমস্ট্যাম্প বা সর্বাধিক updated_at ব্যবহার করুন যদি আপনি একটি সংগ্রহ পাস করেন:

class UsersController < ApplicationController
  def index
    @users = User.includes(:posts).all

    render :index if stale?(@users)
  end
end

কার্ল দিয়ে পৃষ্ঠায় আঘাত করে, আমরা ফলাফল দেখতে পারি:

# curl -I localhost:3000 -- first page load
ETag: W/"af9ae8f2d66b9b6c4d0513f185638f1a"
# curl -I localhost:3000 -- reload (change due to CSRF token)
ETag: W/"f06158417f290334f47ea2124e08d89d"

-- Add stale? to controller code

# curl -I localhost:3000 -- reload
ETag: W/"04b9b99835c359f36551720d8e3ca6fe" -- now using `@users` to generate ETag
# curl -I localhost:3000 -- reload
ETag: W/"04b9b99835c359f36551720d8e3ca6fe" -- no change

এটি আমাদেরকে আরও নিয়ন্ত্রণ দেয় যখন ক্লায়েন্টকে আবার সম্পূর্ণ পেলোড ডাউনলোড করতে হবে, কিন্তু তারপরও এটিকে সার্ভারের সাথে প্রতিবার চেক করতে হবে। এটির ক্যাশে এখনও বৈধ কিনা তা নির্ধারণ করতে। আমরা যদি চেকটি সম্পূর্ণভাবে এড়িয়ে যেতে চাই? এখানেই max-age হেডারে ফিল্ড আসে।

এক্সপায়ার_ইন এবং http_cache_forever

Rails আমাদের ActionController-এ কয়েকটি সহায়ক পদ্ধতি দেয় max-age সামঞ্জস্য করতে ক্ষেত্র:expires_in এবং http_cache_forever . তারা উভয়েই তাদের নামের উপর ভিত্তি করে আপনি যেভাবে আশা করবেন তা কাজ করে:

class UsersController < ApplicationController
  def index
    @users = User.includes(:posts).all

    expires_in 10.minutes
  end
end
# curl -I localhost:3000
Cache-Control: max-age=600, private

রেল max-age সেট করেছে 600 পর্যন্ত (সেকেন্ডে 10 মিনিট) এবং must-revalidate সরানো হয়েছে ক্ষেত্র এছাড়াও আপনি private পরিবর্তন করতে পারেন একটি public: true পাস করে ক্ষেত্র নামযুক্ত যুক্তি।

http_cache_forever বেশিরভাগই expires_in এর চারপাশে একটি মোড়ক যা max-age সেট করে 100 বছর পর্যন্ত এবং একটি ব্লক লাগে:

class UsersController < ApplicationController
  def index
    @users = User.includes(:posts).all

    http_cache_forever(public: true) do
      render :index
    end
  end
end
# curl -I localhost:3000
Cache-Control: max-age=3155695200, public

এই ধরনের অত্যন্ত-দীর্ঘ-মেয়াদী-ক্যাশিংয়ের কারণেই রেলস সম্পদগুলির সাথে একটি "আঙুলের ছাপ" যুক্ত থাকে, যা ফাইলের বিষয়বস্তুর একটি হ্যাশ এবং ফাইলের নাম তৈরি করে, যেমন packs/js/application-4028feaf5babc1c1617b.js . শেষে "আঙুলের ছাপ" ফাইলের নামের সাথে ফাইলের বিষয়বস্তুকে কার্যকরভাবে লিঙ্ক করে। বিষয়বস্তু কখনও পরিবর্তন হলে, ফাইলের নাম পরিবর্তন হবে. এর মানে ব্রাউজার নিরাপদে এই ফাইলটি চিরকালের জন্য ক্যাশে করতে পারে৷ কারণ যদি এটি কখনও পরিবর্তন হয়, এমনকি একটি ছোট উপায়েও, আঙুলের ছাপ পরিবর্তন হবে; যতদূর ব্রাউজার উদ্বিগ্ন, এটি একটি সম্পূর্ণ আলাদা ফাইল যা ডাউনলোড করা প্রয়োজন।

প্রভাবের ক্ষেত্র

এখন যেহেতু আমরা কিছু ক্যাশিং বিকল্পগুলি কভার করেছি, আমার পরামর্শটি কিছুটা অদ্ভুত বলে মনে হতে পারে, তবে আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি এই নিবন্ধের যেকোনো পদ্ধতি ব্যবহার করা এড়াতে চেষ্টা করুন! ETags এবং HTTP ক্যাশিং সম্পর্কে জানা ভাল, এবং Rails আমাদের নির্দিষ্ট সমস্যার সমাধানের জন্য কিছু নির্দিষ্ট সরঞ্জাম দেয়। সতর্কতা, যদিও, এবং এটি একটি বড় বিষয়, এই সমস্ত ক্যাশিং আপনার অ্যাপ্লিকেশনের বাইরে ঘটে এবং তাই এটি মূলত আপনার নিয়ন্ত্রণের বাইরে। আপনি যদি রেলে ভিউ ক্যাশিং বা নিম্ন-স্তরের ক্যাশিং ব্যবহার করেন, যেমনটি এই সিরিজের আগের অংশগুলিতে কভার করা হয়েছে, এবং অবৈধতার সমস্যাগুলির সম্মুখীন হন, আপনার কাছে বিকল্প রয়েছে; আপনি touch করতে পারেন মডেল, পুশ আপডেট করা কোড, অথবা এমনকি Rails.cache এ পৌঁছান সরাসরি কনসোল থেকে যদি আপনাকে করতে হয় তবে HTTP ক্যাশিংয়ের সাথে নয়। ব্যক্তিগতভাবে, আমি বরং Rails.cache.clear চালাতে চাই ব্যবহারকারীরা তাদের ব্রাউজার ক্যাশে সাফ না করা পর্যন্ত ব্যবহারকারীদের জন্য একটি সমস্যার সম্মুখীন হওয়ার চেয়ে উত্পাদনে (আপনার গ্রাহক পরিষেবা দল আপনাকে এটির জন্য ভালবাসবে)।

উপসংহার

এটি রেলে ক্যাশিং সিরিজের সমাপ্তি; আশা করি, এটি দরকারী এবং তথ্যপূর্ণ ছিল। ক্যাশে করার জন্য আমার পরামর্শ নিম্নরূপ হতে চলেছে:যতটা সম্ভব কম করুন, কিন্তু যতটা করতে হবে। আপনি যদি কর্মক্ষমতা সমস্যা অনুভব করেন, প্রায়শই আঘাতপ্রাপ্ত পদ্ধতিগুলি সন্ধান করে শুরু করুন; সম্ভবত, তারা memoized করা যেতে পারে. অনুরোধ জুড়ে অবিরত মান প্রয়োজন? হতে পারে যে ভারী-ব্যবহৃত পদ্ধতি কিছু নিম্ন-স্তরের ক্যাশিং ব্যবহার করতে পারে। অথবা, সম্ভবত, এটি কোনো বিশেষ পদ্ধতি নয়; এটি কেবল সেই সমস্ত নেস্টেড আংশিকগুলির মধ্য দিয়ে ক্রাঞ্চ করছে, যা জিনিসগুলিকে ধীর করে দিচ্ছে; এই ক্ষেত্রে, সম্ভবত ভিউ লেভেল ক্যাশিং সাহায্য করতে পারে। রেলগুলি আমাদের এই প্রতিটি সমস্যাকে লক্ষ্য করার জন্য "ধারালো ছুরি" দেয় এবং কখন সেগুলি ব্যবহার করতে হবে তা আমাদের জানতে হবে৷


  1. রেল নিরাপত্তা হুমকি:প্রমাণীকরণ

  2. রুবি ডেভেলপারদের জন্য ডেটা স্ট্রাকচারের একটি ওভারভিউ

  3. রুবি দিয়ে কীভাবে কমান্ড-লাইন অ্যাপ্লিকেশন (সিএলআই) তৈরি করবেন

  4. রেলে রুবি কি এবং কেন এটি দরকারী?