পাঠ ৪৪ · ৫৬-এর মধ্যে · মডিউল ১০

RAID

RAID — Redundant Array of Independent Disks
৮ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • RAID 0, RAID 1 ও RAID 5-এর কাজের পদ্ধতি ও একে অপরের থেকে ভিন্নতা
  • প্রতিটি লেভেলের ব্যবহারযোগ্য ক্যাপাসিটি বাস্তব কোড দিয়ে গণনা ও যাচাই
  • প্রতিটি লেভেল ঠিক কয়টি ডিস্ক ফেইলিওর সহ্য করতে পারে ও কেন
  • RAID 0 কেন কোনোভাবেই একটি ব্যাকআপ স্ট্র্যাটেজি নয় — একটি সাধারণ ভুল ধারণা

১ · RAID কী ও কেন

RAIDRedundant Array of Independent Disksএকাধিক ফিজিক্যাল ডিস্ককে একত্র করে একটি লজিক্যাল স্টোরেজ ইউনিট তৈরি করার কৌশল — পারফরম্যান্স ও/অথবা নির্ভরযোগ্যতা বাড়ানোর জন্য। একাধিক ফিজিক্যাল ডিস্ককে একত্র করে একটি একক লজিক্যাল স্টোরেজ ইউনিট তৈরি করে — OS ও অ্যাপ্লিকেশনের কাছে এটি একটি একক ড্রাইভ হিসেবে দেখা যায় (L01-এর অ্যাবস্ট্রাকশন থিমের আরেকটি প্রয়োগ)। বিভিন্ন "লেভেল" ভিন্ন ভিন্ন ট্রেড-অফ দেয় — কিছু পারফরম্যান্সের জন্য অপ্টিমাইজ করে, কিছু নির্ভরযোগ্যতার জন্য, আর কিছু দুটোর মধ্যে ভারসাম্য রাখার চেষ্টা করে।

২ · RAID 0 (স্ট্রাইপিং) ও RAID 1 (মিররিং)

RAID 0 — স্ট্রাইপিং
ডেটা সমানভাবে সব ডিস্কে ভাগ করে ছড়িয়ে দেওয়া হয়, কোনো রিডানডেন্সি ছাড়াই — একাধিক ডিস্কে প্যারালাল রিড/রাইট সম্ভব হওয়ায় পারফরম্যান্স বাড়ে, কিন্তু যেকোনো একটি ডিস্ক নষ্ট হলে পুরো ডেটা হারিয়ে যায় (প্রতিটি ডিস্কেই ডেটার প্রয়োজনীয় একটি অংশ থাকে)।
RAID 1 — মিররিং
প্রতিটি ডিস্কের একটি হুবহু কপি (মিরর) রাখা হয় — একটি সম্পূর্ণ ডিস্ক হারালেও শূন্য ডেটা লস — কিন্তু এর জন্য ২ গুণ স্টোরেজ কিনে মাত্র ১ গুণ ব্যবহারযোগ্য ক্যাপাসিটি পাওয়া যায়।
একটি গুরুত্বপূর্ণ, প্রায়ই ভুল বোঝা বিষয় — RAID 0 কোনোভাবেই একটি ব্যাকআপ স্ট্র্যাটেজি নয়। এটি শুধু পারফরম্যান্স বাড়ায়, কিন্তু নির্ভরযোগ্যতা প্রকৃতপক্ষে কমায় — একক ডিস্কের চেয়েও বেশি ফেইলিওর ঝুঁকি তৈরি হয়, কারণ n-টি ডিস্কের যেকোনো একটি নষ্ট হলেই সব ডেটা হারায়।

৩ · RAID 5 (স্ট্রাইপিং + ডিস্ট্রিবিউটেড প্যারিটি)

RAID 5 ডেটা এবং প্যারিটিParityএকটি গাণিতিক এনকোডিং যা থেকে একটি হারানো ডিস্কের ডেটা বাকি ডিস্কগুলো থেকে পুনর্গঠন করা যায়। তথ্য — উভয়ই সব ডিস্কে ছড়িয়ে রাখে (কোনো একক "প্যারিটি ডিস্ক" নেই, তাই কোনো একটি ডিস্কই বটলনেক হয় না)। প্যারিটি ব্যবহার করে যেকোনো একটি নষ্ট ডিস্কের ডেটা বাকি ডিস্কগুলো থেকে গাণিতিকভাবে পুনর্গঠন করা সম্ভব। ফলাফল — পারফরম্যান্স, ক্যাপাসিটি-দক্ষতা ও এক-ডিস্ক-ফেইলিওর সহনশীলতার একটি ভালো ভারসাম্য, বাস্তবে অত্যন্ত জনপ্রিয় একটি পছন্দ।

D0 D1 D2 D3 A1 A2 A3 Ap (প্যারিটি) B1 B2 Bp (প্যারিটি) B3 C1 Cp (প্যারিটি) C2 C3 Dp (প্যারিটি) D1 D2 D3
RAID 5 -- প্রতিটি স্ট্রাইপে প্যারিটি ব্লক ভিন্ন ডিস্কে ঘুরিয়ে রাখা হয় (কোনো একক ডিস্ক শুধু প্যারিটি বহন করে না), ফলে যেকোনো একটি ডিস্ক হারালেও বাকিদের থেকে ডেটা পুনর্গঠন করা যায়।
ব্যবহারযোগ্য ক্যাপাসিটির সূত্র

$n$টি ডিস্ক, প্রতিটির আকার $N$ হলে — RAID 0: $C = n \times N$ (কোনো ক্ষতি নেই)। RAID 1: $C = \frac{n}{2} \times N$ (অর্ধেক মিরর হিসেবে ব্যবহৃত)। RAID 5: $C = (n - 1) \times N$ (একটি ডিস্কের সমপরিমাণ ক্যাপাসিটি প্যারিটির জন্য ব্যবহৃত হয়, যদিও ফিজিক্যালি একটি নির্দিষ্ট ডিস্কে নয়)।

নিচের কোডে এই তিনটি সূত্র বাস্তবে ফাংশন হিসেবে ইমপ্লিমেন্ট করে ৪টি ডিস্কের (প্রতিটি ২০০০ GB) একটি উদাহরণের উপর চালিয়ে ব্যবহারযোগ্য ক্যাপাসিটি ও ফল্ট-টলারেন্স গণনা করা হয়েছে — এবং একটি দ্বিতীয় উদাহরণ (৬টি ডিস্ক) দিয়ে সূত্রটি যাচাই করা হয়েছে যাতে বোঝা যায় এটি শুধু একটি নির্দিষ্ট সংখ্যার জন্য নয়, সাধারণভাবে সত্য।

Python
# RAID 0 / 1 / 5 -- ব্যবহারযোগ্য ক্যাপাসিটি ও ফল্ট-টলারেন্স -- বাস্তব গণনা
# (toy in-memory ডেটা -- কোনো আসল ডিস্ক/ফাইল সিস্টেম নয়)

def raid0_capacity(num_disks, disk_size):
    """স্ট্রাইপিং, কোনো রিডানডেন্সি নেই -- সব ডিস্কের সম্পূর্ণ ক্যাপাসিটিই ব্যবহারযোগ্য।"""
    return num_disks * disk_size


def raid1_capacity(num_disks, disk_size):
    """মিররিং -- অর্ধেক ডিস্ক আসল ডেটা, বাকি অর্ধেক তাদের মিরর কপি (num_disks জোড় সংখ্যা ধরে নেওয়া হচ্ছে)।"""
    return (num_disks // 2) * disk_size


def raid5_capacity(num_disks, disk_size):
    """ডিস্ট্রিবিউটেড প্যারিটি -- একটি ডিস্কের সমপরিমাণ ক্যাপাসিটি প্যারিটির জন্য ব্যয় হয়।"""
    return (num_disks - 1) * disk_size


def fault_tolerance(level):
    return {
        "RAID 0": "০টি -- যেকোনো একটি ডিস্ক নষ্ট হলে সম্পূর্ণ ডেটা হারায়",
        "RAID 1": "প্রতিটি মিরর-জোড়া থেকে ১টি করে -- একই জোড়ার দুটি ডিস্ক একসাথে না হারালে নিরাপদ",
        "RAID 5": "ঠিক ১টি -- যেকোনো একটি ডিস্ক নষ্ট হলে প্যারিটি দিয়ে পুনর্গঠন সম্ভব, দুটি একসাথে নষ্ট হলে ডেটা হারায়",
    }[level]


for num_disks, disk_size_gb in [(4, 2000), (6, 2000)]:
    print(f"--- {num_disks}টি ডিস্ক, প্রতিটি {disk_size_gb} GB ---")
    print(f"RAID 0 ব্যবহারযোগ্য ক্যাপাসিটি: {raid0_capacity(num_disks, disk_size_gb)} GB  | ফল্ট-টলারেন্স: {fault_tolerance('RAID 0')}")
    print(f"RAID 1 ব্যবহারযোগ্য ক্যাপাসিটি: {raid1_capacity(num_disks, disk_size_gb)} GB  | ফল্ট-টলারেন্স: {fault_tolerance('RAID 1')}")
    print(f"RAID 5 ব্যবহারযোগ্য ক্যাপাসিটি: {raid5_capacity(num_disks, disk_size_gb)} GB  | ফল্ট-টলারেন্স: {fault_tolerance('RAID 5')}")
    print()

    
৪টি ২০০০ GB ডিস্কের জন্য কোডটি নিশ্চিত করে — RAID 0 = ৮০০০ GB ($4N$), RAID 1 = ৪০০০ GB ($2N$), RAID 5 = ৬০০০ GB ($3N$) — ঠিক এই পাঠের শুরুতে বলা সূত্রের সাথে মিলে যায়। ৬টি ডিস্কের দ্বিতীয় উদাহরণে (RAID 0 = ১২০০০ GB, RAID 1 = ৬০০০ GB, RAID 5 = ১০০০০ GB) সূত্রটি সাধারণভাবেই সঠিক প্রমাণিত হয়, শুধু একটি বিশেষ সংখ্যার জন্য নয়।
মূল কথা · Key takeaway

RAID লেভেল বেছে নেওয়া মানে সবসময় একটি সচেতন ট্রেড-অফ — RAID 0 বিশুদ্ধ গতি চায় (নির্ভরযোগ্যতা বিসর্জন দিয়ে), RAID 1 বিশুদ্ধ নিরাপত্তা চায় (ক্যাপাসিটি বিসর্জন দিয়ে), আর RAID 5 দুটোর মাঝে একটি ব্যবহারিক ভারসাম্য খোঁজে। কোনো "সবচেয়ে ভালো" RAID লেভেল নেই — শুধু ভিন্ন প্রয়োজনের জন্য ভিন্ন সঠিক পছন্দ আছে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ কেউ বলল "আমি RAID 0 ব্যবহার করছি, তাই আমার আর আলাদা ব্যাকআপ দরকার নেই।" এই দাবিতে কী ভুল আছে?

এটি একটি গুরুতর ভুল ধারণা। RAID 0 কোনো রিডানডেন্সি রাখে না — এটি শুধু ডেটা একাধিক ডিস্কে ছড়িয়ে পারফরম্যান্স বাড়ায়। বরং RAID 0-তে ডিস্ক সংখ্যা বাড়ার সাথে সাথে ফেইলিওরের সম্ভাবনাও বাড়ে (n-টি ডিস্কের যেকোনো একটি নষ্ট হলেই সব ডেটা হারায়) — তাই RAID 0 আসলে একক ডিস্কের চেয়েও কম নির্ভরযোগ্য। ব্যাকআপ RAID-এর বিকল্প নয় — RAID মূলত আপটাইম/পারফরম্যান্সের জন্য, ব্যাকআপ ডেটা-লস থেকে রক্ষার জন্য, দুটো ভিন্ন উদ্দেশ্য।

প্র ০২ RAID 5-এ একই সাথে দুটি ডিস্ক নষ্ট হলে কী হবে? RAID 5 কি সেটি সামলাতে পারে?

না, RAID 5 শুধু ঠিক একটি ডিস্ক ফেইলিওর সহ্য করতে ডিজাইন করা — প্যারিটি গণনা একটি একক ডিস্কের ডেটা পুনর্গঠনের জন্য যথেষ্ট তথ্য রাখে, কিন্তু দুটি ডিস্ক একসাথে হারালে সেই গণিতটি আর সম্ভব নয় (একাধিক অজানা পরিবর্তনশীল, একটি সমীকরণ দিয়ে সমাধানযোগ্য নয়)। এই কারণেই RAID 6 (এই কোর্সে বিস্তারিত না গেলেও) দ্বিতীয় একটি স্বাধীন প্যারিটি ব্লক যোগ করে দুটি একযোগে ডিস্ক ফেইলিওর সহ্য করার জন্য ডিজাইন করা হয়েছে।

প্র ০৩ উপরের কোড সেলে RAID 1-এর জন্য num_disks // 2 ব্যবহার করা হয়েছে — যদি num_disks বিজোড় সংখ্যা (যেমন ৫) হয়, তাহলে কী সমস্যা হতে পারে?

RAID 1 ধরে নেয় ডিস্কগুলো জোড়ায় জোড়ায় সাজানো — প্রতিটি জোড়ায় একটি "আসল" ও একটি "মিরর"। বিজোড় সংখ্যক ডিস্ক হলে একটি ডিস্ক জোড়াবিহীন থেকে যায়, যা প্রকৃত RAID 1 কনফিগারেশনে সাধারণত অনুমোদিত নয় (বা সেই বাড়তি ডিস্কটি hot-spare হিসেবে আলাদা রাখা হয়, ব্যবহারযোগ্য ক্যাপাসিটিতে যোগ হয় না)। কোডে // (ইন্টিজার ডিভিশন) ব্যবহারের ফলে এই বাড়তি ডিস্কটি স্বয়ংক্রিয়ভাবে ক্যাপাসিটি হিসাব থেকে বাদ পড়ে যায় — যা বাস্তব আচরণের সাথে সামঞ্জস্যপূর্ণ।

অনুশীলন

  1. চিন্তা করুন: একটি ছোট ব্যক্তিগত ফাইল-সার্ভারের জন্য, যেখানে ডেটা হারানো একদম গ্রহণযোগ্য নয় কিন্তু বাজেট সীমিত, কোন RAID লেভেলটি সবচেয়ে যুক্তিসঙ্গত মনে হয়?

    RAID 1 প্রায়ই সবচেয়ে সহজ, নির্ভরযোগ্য পছন্দ ছোট সেটআপে (মাত্র ২টি ডিস্ক দিয়েই কাজ করে, ইমপ্লিমেন্ট করা সহজ) — যদিও ব্যবহারযোগ্য ক্যাপাসিটি অর্ধেক, তবু ডেটা-লস প্রতিরোধ এখানে অগ্রাধিকার। যদি বাজেটে আরও ডিস্ক (৪+) থাকে এবং ক্যাপাসিটি-দক্ষতাও গুরুত্বপূর্ণ হয়, RAID 5 একটি ভালো মধ্যবর্তী পছন্দ হতে পারে।

  2. পরীক্ষা করুন: উপরের কোড সেলে ডিস্ক তালিকায় (8, 4000) (৮টি ৪০০০ GB ডিস্ক) যোগ করে Run চাপুন — তিনটি লেভেলের ব্যবহারযোগ্য ক্যাপাসিটি কত আসে হিসেব করে দেখুন।

    সূত্র অনুযায়ী — RAID 0 = 8 × 4000 = ৩২,০০০ GB, RAID 1 = (8 // 2) × 4000 = ১৬,০০০ GB, RAID 5 = (8 − 1) × 4000 = ২৮,০০০ GB। কোড চালিয়ে এই মানগুলো নিশ্চিত হবে কি না মিলিয়ে দেখুন — এটি আবার প্রমাণ করে সূত্রগুলো যেকোনো ডিস্ক সংখ্যার জন্য সাধারণভাবে কাজ করে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
ডিস্ক শিডিউলিং অ্যালগরিদম