ফাইল স্টোরেজ সিস্টেম ডিজাইন
সমস্যাটি বোঝা
ড্রপবক্স (Dropbox), গুগল ড্রাইভ (Google Drive) অথবা ওয়ানড্রাইভের (OneDrive) কথা চিন্তা করুন। ব্যবহারকারীরা যেকোনো একটি ডিভাইস থেকে কোনো ফাইল আপলোড করলে তারা আশা করেন যে সঙ্গে সঙ্গেই সেটি অন্য সব ডিভাইসেও দেখাবে। তারা লিংক বা পারমিশন ব্যবহার করে সহকর্মীদের সাথে ফাইল শেয়ার করতে চান, আগের ভার্সনে ফিরে যাওয়ার অপশন চান, এবং কখনোই নিজেদের কোনো ডেটা বা ফাইল হারাতে চান না।
ফাংশনাল রিকয়ারমেন্টস:
- আপলোড এবং ডাউনলোড — ব্যবহারকারীরা যেকোনো ডিভাইস থেকে ফাইল আপলোড এবং ডাউনলোড করতে পারবেন।
- সবার ডিভাইসে সিঙ্ক (Sync across devices) — এক ডিভাইসে কিছু পরিবর্তন করলে তা সাথে সাথে সব ডিভাইসে আপডেট হয়ে যাবে।
- ফাইল শেয়ারিং — লিংক বা পারমিশন ব্যবহার করে অন্যান্য ইউজারদের সাথে ফাইল বা ফোল্ডার শেয়ার করা।
- ভার্সন হিস্টোরি — ফাইলের পুরোনো ভার্সন সংরক্ষণ করে রাখা যেন প্রয়োজন মতো সেগুলোকে রিস্টোর করা যায়।
নন-ফাংশনাল রিকয়ারমেন্টস:
- রিলিজিবিলিটি বা নির্ভরতা: ফাইল কখনোই হারানো যাবে না। ডেটা ডিউরেবিলিটি সর্বোচ্চ পর্যায়ের হতে হবে — হিসাবটি ৯৯.৯৯৯৯৯৯৯৯৯% (১১টি নয়) এর মতো নির্ভরযোগ্য হওয়া চাই।
- লো সিঙ্ক ল্যাটেন্সি: যখন কোনো ব্যবহারকারী একটি ফাইল সেভ করেন, অন্য ডিভাইসগুলোতে কয়েক মিনিটের বদলে সেকেন্ডের মধ্যেই সেই আপডেটটি দেখতে পাওয়ার ব্যবস্থা থাকতে হবে।
- ব্যান্ডউইথের সাশ্রয়ী ব্যবহার: ডেল্টা সিঙ্ক (delta sync) পদ্ধতি ব্যবহার করে ফাইলের শুধু পুরোনো পরিবর্তিত অংশ আপলোড করা উচিত, প্রতিবার সম্পূর্ণ ফাইলটি নয়। এটিই হলো এই ডিজাইনের সবচেয়ে বড় ইঞ্জিনিয়ারিং চ্যালেঞ্জ।
প্রাথমিক একটা হিসাব-নিকাশ
চলুন এই সিস্টেমটার সাইজের একটি হিসাব করি:
- ৫০০ মিলিয়ন (৫০ কোটি) রেজিস্টার্ড ইউজার, যাদের মধ্যে ১০০ মিলিয়ন (১০ কোটি) ডেইলি অ্যাকটিভ ইউজার (DAU)।
- প্রতি ইউজারের গড়ে ২০০টি ফাইল আছে।
- গড় ফাইল সাইজ: ১০০ KB (বেশিরভাগই ছোট ডকুমেন্ট, কিছু বড় মিডিয়া ফাইল থাকতে পারে)।
- মোট স্টোরেজ: ৫০০ মিলিয়ন × ২০০ × ১০০ KB = ১০ PB।
- সিঙ্ক অপারেশন: ১০০ মিলিয়ন DAU × গড়ে প্রতিদিন ১ সিঙ্ক = দৈনিক १०० মিলিয়ন সিঙ্ক অপারেশন (প্রায় ১,১৫০/সেকেন্ড)।
- আপলোড ব্যান্ডউইথ: যদি সিঙ্কের ১০% প্রায় ১০০ KB সাইজের আপলোড হয়, তবে তার জন্য প্রতি সেকেন্ডে ~১.১৫ GB ব্যান্ডউইথ লাগবে।
- পিক ট্রাফিক: কাজের সময় গড় ট্রাফিকের ৩-৫ গুণ বেশি হতে পারে।
আসল চ্যালেঞ্জটা হলো ডেটার শুধু র-থ্রুপুট (raw throughput) সামলানো নয় — বরং ফাইলগুলোকে চাঙ্ক (chunking) ও ডেল্টা (delta) সিঙ্ক করে ব্যান্ডউইথ কমানো এবং সিঙ্ক ল্যাটেন্সি কম রাখা।
API ডিজাইন
নির্ভরযোগ্যতা এবং পরবর্তীতে রিকোয়েস্ট রিজ্যুমেবল (resumable) বা রিট্রাই করার সুবিধা রাখার জন্য ফাইল অপারেশনগুলোকে টুকরো বা চাঙ্কিং (chunked) করা হয়:
ფাইল আপলোড (Chunked)
| Endpoint | POST /api/v1/files/upload |
| Request | {"filename": "report.pdf", "chunks": [{"hash": "a1b2c3", "index": 0, "data": "..."}], "total_chunks": 5} |
| Response | {"file_id": "f123", "version": 1, "status": "uploaded"} |
| Status | 201 Created |
ფাইল ডাউনলোড
| Endpoint | GET /api/v1/files/:id |
| Response | File binary stream with Content-Disposition header |
| Status | 200 OK |
মেটাডেটা আপডেট
| Endpoint | PUT /api/v1/files/:id/metadata |
| Request | {"name": "new-name.pdf", "shared_with": ["user456"]} |
| Status | 200 OK |
ভার্সন হিস্টোরি
| Endpoint | GET /api/v1/files/:id/history |
| Response | {"versions": [{"version": 3, "modified_at": "...", "size": 102400}, ...]} |
কেন চাঙ্ক করা বা টুকরো আপলোড? বড় বড় ফাইলগুলো (১০০ MB বা তার বেশি) অস্থিতিশীল নেটওয়ার্কে আপলোড হতে গিয়ে প্রায়ই ফেইল করে। চাঙ্কিংয়ের মাধ্যমে আপনি যেখানে আপলোড ছেড়েছিলেন, সেখান থেকে আবার শুরু (resume) করতে পারেন। প্রতিটি চাঙ্কের গড় আকার সাধারণত ৪ MB হয়ে থাকে — এটি এতই ছোট যে ফেইল করলে তা দ্রুত আবার রিট্রাই করা যায়, আবার বড় আকারের হওয়া সত্ত্বেও এটি অনেক বেশি বার সার্ভারে রিকোয়েস্ট যাওয়া-আসা করা থেকে বাঁচায়।
ব্লক-লেভেলের ডিডুপ এবং ডেল্টা সিঙ্ক
ফাইল স্টোরেজ সিস্টেম ডিজাইনে ডেটা ডিডুপ্লিকেশন বা কমানোর এই সিদ্ধান্তটি এককথায় সবচেয়ে গুরুত্বপূর্ণ।
এটি যেভাবে কাজ করে:
- ফাইলগুলোকে ব্লকে ভাগ করা — প্রতিটি ফাইলকে নির্দিষ্ট সাইজের ব্লকে (সাধারণত ৪ MB) ভাগ করা হয়। এরপর প্রতিটি ব্লকের জন্য একটি ক্রিপ্টোগ্রাফিক হ্যাশ (যেমন: SHA-256) জেনারেট করা হয়।
- হ্যাশ কম্পারিজন বা হ্যাশের তুলনা করা — আপলোড করার আগে, ক্লায়েন্ট সমস্ত ব্লকের হ্যাশ গণনা করে সার্ভারে পাঠায়। সার্ভার চেক করে দেখে যে কোন ব্লকগুলো তার কাছে ইতিমধ্যে জমা আছে।
- কেবলমাত্র নতুন ব্লক আপলোড — যেগুলোর হ্যাশ নতুন, শুধু সেই ব্লকগুলোই আপলোড হয়। ধরা যাক, আপনি ১০০ মেগাবাইটের কোনো ডকুমেন্টে একটি প্যারাগ্রাফ পরিবর্তন করেছেন; সে ক্ষেত্রে পুরো ১০০ মেগাবাইট আপলোড করার বদলে, আপনি শুধুমাত্র একটি পরিবর্তিত ৪ মেগাবাইট ব্লক আপলোড করবেন।
- ডাউনলোডের সময় পুনর্গঠন — ফাইলটি মূলত ব্লক হ্যাশের একটি তালিকা হিসেবে জমা থাকে। ডাউনলোডের সময়, ওই তালিকা অনুযায়ী প্রতিটি ব্লক ফেচ বা নিয়ে আসা হয় এবং ফাইলটিকে পুনরায় আগের মতো জোড়া লাগানো হয়।
ব্যান্ডউইথ বাঁচানো: ডেল্টা সিঙ্কের মাধ্যমে সাধারণ পরিবর্তনের ক্ষেত্রে ব্যান্ডউইথের চাহিদা ৯০% এর চেয়েও বেশি কমানো সম্ভব হয়। এই কারণেই ড্রপবক্স এত দ্রুত কাজ করে—প্রতিবার 'save' চাপার সময় এটি আপনার পুরো ফাইল আপলোড করে না।
কনফ্লিক্ট বা দ্বন্দ্ব মেটানো: যখন দুটি ডিভাইস একই ফাইলে প্রায় একই সাথে এডিট করা শুরু করে:
- Latest-write-wins (যেটা শেষে সেভ হয়েছে সেটাকে রাখা) — এটি সহজ, তবে এতে ডাটা হারিয়ে যেতে পারে। অধিকাংশ ক্ষেত্রেই এটি মেনে নেওয়া যায়।
- উভয় কপি সংরক্ষণ করা — একটি "conflicted copy" বা দ্বন্দ্ব রয়েছে এ রকম কপি তৈরি করা হয়, এবং ইউজারকে বলে দেওয়া হয় ম্যানুয়ালি এটি ঠিক করার জন্য। ড্রপবক্স সাধারণত এই পদ্ধতি ব্যবহার করে।
- অপারেশনাল ট্রান্সফর্ম — গুগল ডকস রিয়েল-টাইমে কোলাবোরেটিভ (একাধিক ইউজারের একযোগে) এডিটিংয়ের জন্য এটি ব্যবহার করে (যা তুলনামূলকভাবে অনেকটাই জটিল)।
রিয়েল-টাইম সিঙ্ক এবং স্টোরেজের স্তর
নোটিফিকেশন সার্ভিস: প্রায় তাৎক্ষণিকভাবে সিঙ্ক করার জন্য, সার্ভারকে অবশ্যই নিজে থেকে অন্য ক্লায়েন্টগুলোকে আপডেট পুশ (push) করে পাঠাতে হবে। এর জন্য দুটি পদ্ধতি রয়েছে:
- লং পোলিং (Long polling) — ক্লায়েন্ট একটি HTTP কানেকশন ওপেন করে রাখে এবং যখন কোনো পরিবর্তন হয়, তখন সার্ভার রেসপন্স করে। এটি বেশ সহজ পদ্ধতি, কিন্তু এর জন্য অনেক বেশি কানেকশন লাগে।
- ওয়েব সকেট (WebSocket) — এটি একটি স্থায়ী বাই-ডিরেকশনাল (bidirectional) বা দ্বিমুখী কানেকশন, যা ঘন ঘন আপডেট রিসিভ করার জন্য অনেক বেশি কার্যকরী। ডেস্কটপ সিঙ্ক ক্লায়েন্টগুলোতে এ পদ্ধতিটাই বেশি পছন্দ করা হয়।
যখন কোনো ফাইলে পরিবর্তন হয়, তখন নোটিফিকেশন সার্ভিসটি কানেক্ট থাকা সব ডিভাইসকে মেসেজ পাঠায়: "ফাইল X-এ নতুন ব্লক যুক্ত হয়েছে — এখানে হ্যাশগুলো দেওয়া হলো।" এরপর প্রতিটি ডিভাইস শুধুমাত্র সেই ব্লকগুলো ডাউনলোড করে নেয় যেগুলো আগে থেকে তার কাছে নেই।
স্টোরেজ টিয়ার বা স্তরগুলো:
- হট স্টোরেজ (Hot storage) — যেসব ফাইল সাধারণত ঘন ঘন ব্যবহার করা হয় (যেমন: গত ৩০ দিনে অ্যাকসেস করা ফাইল)। ডেটা দ্রুত পড়ার জন্য এই লেয়ারে ফাস্ট SSD (High IOPS) ব্যবহার করা হয়। এটি অনেকটাই S3 Standard-এর মতো কাজ করে।
- কোল্ড স্টোরেজ (Cold storage) — পুরোনো ভার্সন বা খুব একটা অ্যাকসেস না করা ফাইলগুলো সস্তা স্টোরেজে (Amazon S3 Glacier, Tape) জমা করা হয়। এর ডেটা পড়ার সময় মিনিট থেকে কয়েক ঘণ্টা লাগতে পারে, তবে খরচ ১০-২০ গুণ কমে যায়।
- লাইফসাইকেল পলিসি (Lifecycle policies) — ফাইলের ব্যবহার বা অ্যাক্সেস প্যাটার্নের উপর ভিত্তি করে স্বয়ংক্রিয়ভাবে সেগুলোকে হট থেকে কোল্ড স্টোরেজে সরিয়ে নেওয়ার ব্যবস্থা। যেমন: ৯০ দিনের চেয়েও পুরোনো ভার্সনের কোনো হিস্টোরি কোল্ড স্টোরেজে পাঠিয়ে দেওয়া হয়।
Key Metrics
ছোট কুইজ
পড়া চালিয়ে যান