Web Services১১ মিনিট পাঠ

পেস্ট সার্ভিস ডিজাইন

স্নিপেট স্টোর এবং শেয়ার করার ব্যবস্থা — পেস্টবিনের (Pastebin) মতো, স্কেলে
scope:রিয়েল-ওয়ার্ল্ড সিস্টেম (Real-World System)difficulty:ইন্টারমিডিয়েট (Intermediate)

সমস্যাটি বোঝা (Understanding the Problem)

পেস্টবিন (Pastebin), গিটহাব গিস্ট (GitHub Gist) এবং হেস্টবিনের (Hastebin) মতো পেস্ট সার্ভিসগুলো ইউজারদের যেকোনো টেক্সট স্নিপেট (snippet) সেভ করা এবং একটি ছোট ইউআরএল বা শর্ট লিঙ্কের (Short URL) মাধ্যমে সেগুলো শেয়ার করার সুযোগ দেয়। চলুন শুরু থেকে এমন একটি সিস্টেম ডিজাইন করি।

প্রথমে, প্রয়োজনীয়তাগুলো পরিষ্কার করে নেওয়া যাক:

ফাংশনাল প্রয়োজনীয়তা (Functional Requirements):

  • ইউজাররা টেক্সট জমা দিয়ে একটি পেস্ট (Paste) তৈরি করতে পারবেন এবং একটি ইউনিক URL পাবেন।
  • ইউজাররা ইউনিক URL-টি ভিজিট করে পুরোনো কোনো পেস্ট রিট্রিভ (Retrieve) করতে পারবেন।
  • পেস্টের একটি এক্সপায়ারেশন টাইম বা মেয়াদ (Expiration Time) সেট করা থাকতে পারে (যেমন: ১০ মিনিট, ১ ঘণ্টা, বা অনন্তকাল)।
  • ঐচ্ছিক (Optional): জনপ্রিয় প্রোগ্রামিং ল্যাঙ্গুয়েজের জন্য সিনট্যাক্স হাইলাইটিং (Syntax highlighting)।
  • ঐচ্ছিক (Optional): কাস্টম শর্ট URL বা এলিয়াস (Aliases)।

নন-ফাংশনাল প্রয়োজনীয়তা (Non-Functional Requirements):

  • রিড-হেভি (Read-heavy): লেখার চেয়ে পড়ার পরিমাণ বেশি। আনুমানিক রেশিও ~৫:১।
  • নিম্ন ল্যাটেন্সি (Low latency): পেস্ট রিট্রিভাল দ্রুত হওয়া উচিত (ক্যাশ করা কনটেন্টের জন্য < ৫০ মিলিসেকেন্ড)।
  • উচ্চ প্রাপ্যতা (High availability): সার্ভিসটি অত্যন্ত এভেইলেবল হতে হবে — শেয়ার করা লিঙ্কগুলো সব সময় কাজ করতে হবে।
  • ডিউরাবিলিটি (Durability): একবার তৈরি করা হলে, মেয়াদ শেষ না হওয়া পর্যন্ত কোনো পেস্ট হারানো যাবে না।
  • সাইজ লিমিট (Size limits): অযাচিত ব্যবহার বা অ্যাবিউস (Abuse) রোধ করতে প্রতিটি পেস্ট প্রায় ১০ MB পর্যন্ত সীমাবদ্ধ রাখা যেতে পারে।
মূল ধারণা: টেক্সট → ইউনিক URL

অ্যাস্টিমেশন (Estimation)

চলুন এই সিস্টেমের সাইজ বা ক্যাপাসিটি পরিমাপ করি:

  • মাসে ৫ মিলিয়ন নতুন পেস্ট (রাইট বা Write): ~২ পেস্ট/সেকেন্ড
  • রিড:রাইট (Read:Write) রেশিও ৫:১: ~১০ রিড/সেকেন্ড, পিকে (Peak) ~৩০/সেকেন্ড
  • গড় পেস্ট সাইজ: ~১০ KB (বেশিরভাগ পেস্টই ছোট কোড স্নিপেট বা কনফিগ ফাইল)
  • প্রতি মাসে স্টোরেজ: ৫ মিলিয়ন × ১০ KB = ৫০ GB/মাস
  • ৫ বছরের স্টোরেজ: ৫০ GB × ৬০ মাস = ৩ TB
  • প্রতি পেস্ট মেটাডেটা (Metadata): ~৫০০ বাইটস (কী (Key), টাইটেল (Title), ভাষা, টাইমস্ট্যাম্প, ব্যবহারকারীর আইডি)
  • মেটাডেটা স্টোরেজ (৫ বছর): ৩০০ মিলিয়ন পেস্ট × ৫০০ বাইটস = ১৫০ GB
  • ক্যাশ (Cache): সবচেয়ে জনপ্রিয় (হট) ২০% পেস্ট ক্যাশ করা হবে। ২০% × ৩ TB = ~৬০০ GB (অথবা শুধুমাত্র মেটাডেটা ক্যাশ করা হলে: ~৩০ GB)

পেস্টের কনটেন্ট বা লেখার মূল অংশ স্টোর করাটাই সবচেয়ে বড় খরচ। একটি রিলেশনাল ডেটাবেসের চেয়ে একটি অবজেক্ট স্টোরেজে (যেমন: S3) এটি সংরক্ষণ করা অনেক সাশ্রয়ী। মেটাডেটাগুলো একটি ট্র্যাডিশনাল ডেটাবেসেই থাকবে।

এপিআই ডিজাইন (API Design)

একটি সিম্পল REST API:

ক্রিয়েট পেস্ট (Create Paste)

EndpointPOST /api/v1/pastes
Request{"content": "print('hello')", "title": "My Snippet", "language": "python", "expires_in": 3600}
Response{"key": "abc123", "url": "https://paste.ly/abc123", "created_at": "...", "expires_at": "..."}
Status201 Created

গেট পেস্ট (Get Paste)

EndpointGET /api/v1/pastes/:key
Response{"key": "abc123", "content": "print('hello')", "title": "My Snippet", "language": "python", "created_at": "...", "expires_at": "...", "views": 42}
Status200 OK অথবা 404 Not Found (মেয়াদ শেষ বা মুছে ফেলা হলে)

কনটেন্ট এবং মেটাডেটার বিভাজন (Content vs Metadata separation): API মেটাডেটা এবং কনটেন্ট উভয়ই একসাথে রিটার্ন করে, কিন্তু ইন্টারনাল স্তরে এগুলো আলাদাভাবে সংরক্ষিত হয়। দ্রুত কোয়েরির জন্য মেটাডেটা (নাম, ভাষা, টাইমস্ট্যাম্প) ডেটাবেসে অবস্থান করে। আর সাশ্রয়ী ও টেকসই স্টোরেজের জন্য আসল পেস্ট কনটেন্ট অবজেক্ট স্টোরে (যেমন: S3) অবস্থান করে।

রাইট ফ্লো (Write flow): একটি পেস্ট তৈরি করা
Click chart to zoom
রাইট পাথ (Write path): এপিআই একটি প্রি-জেনারেটেড কী (pre-generated key) নেয়, এস-থ্রিতে (S3) কনটেন্ট স্টোর করে, ডেটাবেসে মেটাডেটা সেভ করে এবং এটিকে ক্যাশে পাঠায়
রিড ফ্লো (Read flow): পেস্ট রিট্রিভ করা
Click chart to zoom
রিড পাথ (Read path): মেটাডেটা ক্যাশ/ডেটাবেস থেকে আসে আর কনটেন্ট অবজেক্ট স্টোর থেকে। হট (জনপ্রিয়) পেস্টগুলো সিডিএন (CDN) ক্যাশিং থেকেও সুবিধা পায়।

স্টোরেজ ডিজাইন (Storage Design)

মূল বিষয়: কনটেন্ট থেকে মেটাডেটাকে আলাদা রাখুন

মেটাডেটা (SQL বা NoSQL ডেটাবেস):

  • paste_key (VARCHAR 8, PRIMARY KEY) — অনন্য ছোট কী (Unique short key)
  • title (VARCHAR 255) — ঐচ্ছিক শিরোনাম
  • language (VARCHAR 32) — সিনট্যাক্স হাইলাইটিংয়ের জন্য ভাষা
  • s3_path (VARCHAR 255) — অবজেক্ট স্টোরে কনটেন্টের পাথ
  • content_size (INT) — বাইট হিসেবে আকার
  • user_id (BIGINT) — পেস্ট ক্রিয়েটর (যাদের একাউন্ট নেই তাদের জন্য null)
  • created_at (TIMESTAMP)
  • expires_at (TIMESTAMP, nullable) — Null মানে কখনও মেয়াদ শেষ হবে fix
  • view_count (BIGINT) — কতবার পড়া হয়েছে তার সংখ্যা

কনটেন্ট (Object Store — S3, GCS, বা MinIO):

  • paste_key দ্বারা প্লেইন টেক্সট ফাইল হিসেবে সংরক্ষিত হয়
  • অবজেক্ট স্টোরগুলো বড় আকারের (Large) ব্লব (BLOB) স্টোরেজের জন্য অসাধারন পারফর্ম করে — যা ডেটাবেসের চেয়ে প্রতি গিগাবাইটে (GB) অনেক বেশি সাশ্রয়ী
  • ইন-বিল্ট (Built-in) ডিউরাবিলিটি (S3 এর জন্য ১১ নাইনস), রিপ্লিকেশন এবং CDN ইন্টিগ্রেশন পাওয়া যায়

কেন ডেটাবেসে কনটেন্ট স্টোর করা হবে না? গড় ১০ KB পেস্ট সাইজ এবং ৩০০ মিলিয়ন পেস্টের জন্য ৫ বছরে আপনার ডেটাবেসে ৩ TB ব্লব ডেটা জমা হবে। এটি ডেটাবেসকে বিশাল ও ভারি করে তোলে, ব্যাকআপকে ধীর করে এবং অবজেক্ট স্টোরেজের চেয়ে এটি ১০-৫০ গুণ বেশি ব্যয়বহুল। ডেটাবেস শুধু ছোট আকারের স্ট্রাকচারড মেটাডেটা পরিচালনা করা উচিত।

পূর্ণাঙ্গ আর্কিটেকচার (Full architecture)

এক্সপায়ারেশন এবং ক্লিনআপ (Expiration & Cleanup)

মেয়াদ শেষ বা এক্সপায়ারিং (Expiration): যখন expires_in হিসেবে একটি টাইম দেয়া হয়, তখন একটি পেস্ট তৈরি হয়, যা expires_at সময় ক্যালকুলেট করে মেটাডেটাতে স্টোর করে রাখে। যখন ইউজার পেস্টের জন্য রিকোয়েস্ট পাঠায় (রিড করার জন্য), তখন এপিআই (API) প্রথমে expires_at চেক করে। যদি মেয়াদ উত্তীর্ণ হয়ে যায়, তবে এটি ৪০৪ (404) রিটার্ন করে। এটি একটি অলস ডিলিশন (Lazy deletion) পদ্ধতি।

অ্যাক্টিভ ক্লিনআপ (Active cleanup): নির্দিষ্ট সময়ে (যেমন, প্রতি ঘণ্টায়) একটি অ্যাসিনক্রোনাস ক্লিনআপ ওয়ার্কার (Async cleanup worker) চালান। এটি ডেটাবেসে মেয়াদ উত্তীর্ণ পেস্টগুলো খুঁজে বের করে, S3 থেকে তাদের কনটেন্ট মুছে ফেলে এবং মেটাডেটা সারিগুলোও ডেটাবেস থেকে সরিয়ে ফেলার ব্যবস্থা করে। মুছে ফেলা পেস্টের কী (Key) পরবর্তীতে পুনর্গঠনের জন্য Key Generation Service (KGS)-এ পাঠানো যেতে পারে।

রেট লিমিটিং (Rate Limiting): অপব্যবহার বা অ্যাবিউজ রোধ করার জন্য একটি আইপি-ভিত্তিক এবং ইউজার-ভিত্তিক রেট লিমিট প্রয়োগ করুন। এর জন্য টোকেন বাকেট (Token bucket) বা স্লাইডিং উইন্ডো (Sliding window) ব্যবহার করা যেতে পারে। সাধারণ লিমিট: রেজিস্টারড ইউজারদের জন্য মিনিটে ৬০টি পেস্ট, বেনামী (অ্যাকাউন্ট নেই এমন) ইউজারদের জন্য মিনিটে ১০টি পেস্ট। এছাড়া, এপিআই গেটওয়ে (API gateway)-তে পেস্টের ফাইলের সাইজ যেমন ১০ MB পর্যন্ত সীমাবদ্ধ করার ব্যবস্থা করতে হবে।

Note: ইন্টারভিউ টিপস (Interview tip): একটি পেস্ট সার্ভিস ও ইউআরএল শর্টনার সিস্টেমের মধ্যে প্রধান পার্থক্য হচ্ছে তাদের স্টোরেজ কৌশল। ইউআরএল শর্টনার একটি ডেটাবেসে অতি সামান্য ডেটা (যেমন একটি ইউআরএল) স্টোর করে। কিন্তু পেস্ট সার্ভিস বেশ কিছুটা বড় আকারের ফাইল (যেমন ১০ MB পর্যন্ত) স্টোর করে থাকে - যে কারণে একটি অবজেক্ট স্টোরের প্রয়োজন পড়ে। এ কারণেই মেটাডেটা এবং প্রকৃত কনটেন্ট পৃথক রাখার কথা বারবার বলতে হবে — এতে আপনার সাশ্রয়ী আর্কিটেকচার সম্পর্কে গভীর ধারণা প্রতিফলিত হবে।

Key Metrics

ক্রিয়েট পেস্ট (Create paste)
KGS কী + S3 আপলোড + DB তে মেটাডেটা লেখা
~৫০ ms \(O(1)\)
রিড পেস্ট - ক্যাশ হিট (Read paste - cache hit)
Redis মেটাডেটা + S3 কনটেন্ট ফেচ (Fetch)
~৫-১০ ms \(O(1)\)
রিড পেস্ট - ক্যাশ মিস (Read paste - cache miss)
DB মেটাডেটা + S3 ফেচ + ক্যাশ ব্যাকফিল (Cache backfill)
~৩০-৫০ ms \(O(1)\)
৮-ক্যারেক্টার কী স্পেস (8-char key space)
৬২^৮ ইউনিক পেস্ট কী (Keys)
২১৮ ট্রিলিয়ন —
স্টোরেজ (৫ বছরের জন্য)
মাসে ৫ মিলিয়ন পেস্ট × ১০ KB প্র গড়ে
~৩ TB —
মেটাডেটা স্টোরেজ (৫ বছরের জন্য)
৩০০ মিলিয়ন পেস্ট × ৫০০ বাইট মেটাডেটা
~১৫০ GB —

ছোট কুইজ

কেন পেস্টের কনটেন্ট সরাসরি ডেটাবেসে সংরক্ষণ করার পরিবর্তে অবজেক্ট স্টোরে (যেমন: S3) রাখা উচিত?

পড়া চালিয়ে যান