সিস্টেম কম্পোনেন্ট (System components)
এই বিভাগে, আমরা একটি কী-ভ্যালু স্টোর তৈরি করতে ব্যবহৃত নিম্নলিখিত মূল কম্পোনেন্ট এবং কৌশলগুলো নিয়ে আলোচনা করব:
- ডেটা পার্টিশন (Data partition)
- ডেটা রেপ্লিকেশন (Data replication)
- কনসিস্টেন্সি (Consistency)
- ইনকনসিস্টেন্সি রেজোলিউশন (Inconsistency resolution)
- ফেইলিওর হ্যান্ডলিং (Handling failures)
- সিস্টেম আর্কিটেকচার ডায়াগ্রাম (System architecture diagram)
- রাইট পাথ (Write path)
- রিড পাথ (Read path)
নিচের বিষয়বস্তু প্রধানত তিনটি জনপ্রিয় কী-ভ্যালু স্টোর সিস্টেমের ওপর ভিত্তি করে: Dynamo [4], Cassandra [5], এবং BigTable [6]।
ডেটা পার্টিশন
বড় অ্যাপ্লিকেশনগুলোর জন্য, সম্পূর্ণ ডেটা সেট একটি সিঙ্গেল সার্ভারে রাখা অসম্ভব। এটি সম্পন্ন করার সবচেয়ে সহজ উপায় হলো ডেটাকে ছোট ছোট পার্টিশনে ভাগ করে একাধিক সার্ভারে সংরক্ষণ করা। ডেটা পার্টিশন করার সময় দুটি চ্যালেঞ্জ থাকে:
- একাধিক সার্ভার জুড়ে ডেটা সমানভাবে বিতরণ করা।
- নোড যোগ বা সরানো হলে ডেটা মুভমেন্ট কমানো।
পূর্ববর্তী অধ্যায়ে আলোচিত কনসিস্টেন্ট হ্যাশিং (consistent hashing) এই সমস্যাগুলো সমাধান করার একটি দুর্দান্ত কৌশল। আসুন উচ্চ-স্তরে কনসিস্টেন্ট হ্যাশিং কীভাবে কাজ করে তা পুনরায় দেখি।
প্রথমে, সার্ভারগুলোকে একটি হ্যাশ রিং-এ স্থাপন করা হয়। চিত্র ৪-এ, আটটি সার্ভার, যাদের s0, s1, …, s7 দ্বারা প্রতিনিধিত্ব করা হয়েছে, হ্যাশ রিং-এ স্থাপন করা হয়েছে।
এরপর, একটি কীকে একই রিং-এ হ্যাশ করা হয়, এবং ঘড়ির কাঁটার দিকে (clockwise) ঘোরার সময় প্রথম যে সার্ভারের সাথে দেখা হয় তাতে এটি সংরক্ষিত হয়। উদাহরণস্বরূপ, এই যুক্তি ব্যবহার করে key0 কে s1-এ সংরক্ষণ করা হয়।
[চিত্র ৪-এর বর্ণনা: ছবিটি আটটি নোডের একটি বৃত্তাকার বিন্যাস উপস্থাপন করে, যাদের s0 থেকে s7 পর্যন্ত লেবেল করা হয়েছে, একটি রিং গঠন করে একটি ধূসর রেখা দ্বারা সংযুক্ত। প্রতিটি নোড একটি বৃত্ত যাতে এর সংশ্লিষ্ট লেবেল রয়েছে। ‘key0’ লেবেলযুক্ত একটি গাঢ় ধূসর ভরাট বৃত্ত, রিং-এর ঠিক বাইরে, n0 নোডের পাশে অবস্থিত। ‘key0’ থেকে একটি বক্র তীর চিহ্ন উৎপন্ন হয়ে সরাসরি s1 নোডের দিকে নির্দেশ করে, যা ‘key0’ থেকে s1-এর দিকে একটি দিকনির্দেশক সংযোগ বা ডেটা প্রবাহ নির্দেশ করে। নিচে ‘Viewer does not support full SVG 1.1’ টেক্সটটি উপস্থিত, যা ইমেজটি সম্পূর্ণরূপে রেন্ডার করার একটি সীমাবদ্ধতা নির্দেশ করে, সম্ভবত ভিউয়ারের SVG ফরম্যাট সম্পূর্ণরূপে হ্যান্ডেল করতে না পারার কারণে। সামগ্রিক কাঠামোটি একটি বৃত্তাকার ডেটা স্ট্রাকচার বা সিস্টেমের একটি সরলীকৃত উপস্থাপনা নির্দেশ করে যার মধ্যে একটি মূল উপাদান (‘key0’) বৃত্তাকার প্রবাহের মধ্যে একটি নির্দিষ্ট নোডকে (s1) প্রভাবিত করে।] চিত্র ৪
ডেটা পার্টিশন করতে কনসিস্টেন্ট হ্যাশিং ব্যবহার করার নিম্নলিখিত সুবিধা রয়েছে:
- স্বয়ংক্রিয় স্কেলিং: লোডের ওপর নির্ভর করে সার্ভার স্বয়ংক্রিয়ভাবে যোগ এবং সরানো যেতে পারে।
- হেটারোজিনিটি (Heterogeneity): একটি সার্ভারের জন্য ভার্চুয়াল নোডের সংখ্যা সার্ভারের ক্ষমতার সমানুপাতিক। উদাহরণস্বরূপ, উচ্চ ক্ষমতাসম্পন্ন সার্ভারগুলোকে আরও বেশি ভার্চুয়াল নোড অ্যাসাইন করা হয়।
ডেটা রেপ্লিকেশন
উচ্চ প্রাপ্যতা এবং নির্ভরযোগ্যতা অর্জন করতে, ডেটা N সংখ্যক সার্ভার জুড়ে অ্যাসিঙ্ক্রোনাসভাবে রেপ্লিকেট করতে হবে, যেখানে N একটি কনফিগারযোগ্য প্যারামিটার। নিম্নলিখিত যুক্তি ব্যবহার করে এই N সংখ্যক সার্ভার বেছে নেওয়া হয়: একটি কীকে হ্যাশ রিং-এর একটি অবস্থানে ম্যাপ করার পরে, সেই অবস্থান থেকে ঘড়ির কাঁটার দিকে হাঁটুন এবং ডেটা কপি সংরক্ষণ করতে রিং-এর প্রথম N সংখ্যক সার্ভার বেছে নিন। চিত্র ৫-এ (N = 3), key0 কে s1, s2, এবং s3-এ রেপ্লিকেট করা হয়েছে।
[চিত্র ৫-এর বর্ণনা: ছবিটি আটটি নোডের একটি বৃত্তাকার বিন্যাস উপস্থাপন করে, যাদের s0 থেকে s7 পর্যন্ত লেবেল করা হয়েছে, একটি সম্পূর্ণ রিং গঠন করে একটি ধূসর রেখা দ্বারা সংযুক্ত। তিনটি নোড, s1, s2, এবং s3, গাঢ় সবুজ রঙে হাইলাইট করা হয়েছে। s0 নোডটি একটি সাদা বৃত্ত, যখন বাকি নোডগুলো (s1-s7)ও বৃত্ত কিন্তু ছোট। ‘key0’ লেবেলযুক্ত একটি গাঢ় ধূসর ভরাট বৃত্ত s0-এর ডানদিকে অবস্থিত। বিন্যাসটি একটি রিং টপোলজি বা একটি বৃত্তাকার ডেটা স্ট্রাকচার নির্দেশ করে। কোনো তীর চিহ্ন উপস্থিত নেই, যা নোডগুলোর মধ্যে একটি অ-দিকনির্দেশক সম্পর্ক নির্দেশ করে। নিচে ‘Viewer does not support full SVG 1.1’ টেক্সটটি ছবিটি প্রদর্শন করতে ব্যবহৃত ভিউয়ারের একটি সীমাবদ্ধতা নির্দেশ করে, ডায়াগ্রামের কোনো বৈশিষ্ট্য নয়। লেবেলগুলো নির্দেশ করে যে নোডগুলো একটি সিস্টেমের মধ্যে স্টেট বা ডেটা পয়েন্ট নির্দেশ করতে পারে, যেখানে ‘key0’ সম্ভবত একটি কী বা রেফারেন্স পয়েন্ট নির্দেশ করে।] চিত্র ৫
ভার্চুয়াল নোড সহ, রিং-এর প্রথম N নোড N সংখ্যক ফিজিক্যাল সার্ভারের চেয়ে কম সংখ্যক সার্ভারের মালিকানাধীন হতে পারে। এই সমস্যা এড়াতে, আমরা ঘড়ির কাঁটার দিকে হাঁটার যুক্তি সম্পাদন করার সময় শুধুমাত্র অনন্য (unique) সার্ভার বেছে নিই।
একই ডেটা সেন্টারের নোডগুলো প্রায়শই পাওয়ার আউটেজ, নেটওয়ার্ক সমস্যা, প্রাকৃতিক দুর্যোগ ইত্যাদির কারণে একই সময়ে ফেইল করে। ভালো নির্ভরযোগ্যতার জন্য, রেপ্লিকাগুলো পৃথক ডেটা সেন্টারে স্থাপন করা হয়, এবং ডেটা সেন্টারগুলো হাই-স্পিড নেটওয়ার্কের মাধ্যমে সংযুক্ত থাকে।
কনসিস্টেন্সি
যেহেতু ডেটা একাধিক নোডে রেপ্লিকেট করা হয়, তাই এটি রেপ্লিকা জুড়ে সিঙ্ক্রোনাইজ করতে হবে। কোরাম কনসেনসাস (Quorum consensus) রিড এবং রাইট উভয় অপারেশনের জন্য কনসিস্টেন্সি নিশ্চিত করতে পারে। আসুন প্রথমে কয়েকটি সংজ্ঞা প্রতিষ্ঠা করি।
- N = রেপ্লিকার সংখ্যা
- W = W সাইজের একটি রাইট কোরাম। একটি রাইট অপারেশনকে সফল হিসাবে বিবেচনা করার জন্য, রাইট অপারেশনটি W সংখ্যক রেপ্লিকা থেকে স্বীকৃতি (acknowledged) পেতে হবে।
- R = R সাইজের একটি রিড কোরাম। একটি রিড অপারেশনকে সফল হিসাবে বিবেচনা করার জন্য, রিড অপারেশনকে অবশ্যই কমপক্ষে R সংখ্যক রেপ্লিকা থেকে রেসপন্সের জন্য অপেক্ষা করতে হবে।
চিত্র ৬-এ দেখানো নিম্নলিখিত উদাহরণটি বিবেচনা করুন যেখানে N = 3।
[চিত্র ৬-এর বর্ণনা: ছবিটি ডেটা স্টোরেজের জন্য একটি সরলীকৃত ডিস্ট্রিবিউটেড সিস্টেম আর্কিটেকচার উপস্থাপন করে, সম্ভবত একটি কী-ভ্যালু স্টোর। একটি কেন্দ্রীয় উপাদান, ‘coordinator…’ লেবেলযুক্ত, তিনটি অন্যান্য নোডের জন্য যোগাযোগের একটি কেন্দ্রবিন্দু হিসাবে কাজ করে, যাদের লেবেল ‘s0,’ ‘s1,’ এবং ‘s2।’ এই নোডগুলো একটি বৃত্তাকার ফ্যাশনে কোঅর্ডিনেটরের চারপাশে সাজানো থাকে, যোগাযোগ চ্যানেল নির্দেশকারী ধূসর রেখা দ্বারা সংযুক্ত। তীর চিহ্নগুলো ডেটা প্রবাহের দিক নির্দেশ করে। প্রতিটি নোড (s0, s1, s2) put(key1, val1) অপারেশন ব্যবহার করে কোঅর্ডিনেটরে ডেটা পাঠায়, যা সম্ভবত একটি কী-ভ্যালু পেয়ার সংরক্ষণ করে। কোঅর্ডিনেটর তারপর সফল রিসিপ্ট এবং স্টোরেজ নিশ্চিত করতে প্রতিটি নোডে একটি ‘ACK’ (স্বীকৃতি) ফেরত পাঠায়। ড্যাশ করা রেখাগুলো যোগাযোগের অ্যাসিঙ্ক্রোনাস প্রকৃতি নির্দেশ করে, বোঝায় যে কোঅর্ডিনেটর put রিকোয়েস্ট পাওয়ার পরে সাথে সাথে রেসপন্স করে না। ডায়াগ্রামটি তৈরি করতে ব্যবহৃত ভিজ্যুয়ালাইজেশন সফটওয়্যারের একটি সীমাবদ্ধতা ‘Viewer does not support full SVG 1.1’ নির্দেশ করে।]
চিত্র ৬ (ACK = acknowledgement)
W = 1 এর অর্থ এই নয় যে ডেটা একটি সার্ভারে লেখা হয়েছে। উদাহরণস্বরূপ, চিত্র ৬-এর কনফিগারেশন সহ, ডেটা s0, s1, এবং s2-এ রেপ্লিকেট করা হয়েছে। W = 1 এর অর্থ হলো রাইট অপারেশনটিকে সফল হিসাবে বিবেচনা করার আগে কোঅর্ডিনেটরকে অবশ্যই কমপক্ষে একটি স্বীকৃতি পেতে হবে। উদাহরণস্বরূপ, যদি আমরা s1 থেকে একটি স্বীকৃতি পাই, তবে আমাদের আর s0 এবং s2 থেকে স্বীকৃতির জন্য অপেক্ষা করার দরকার নেই। একটি কোঅর্ডিনেটর ক্লায়েন্ট এবং নোডগুলোর মধ্যে একটি প্রক্সি হিসাবে কাজ করে।
W, R এবং N-এর কনফিগারেশন হলো লেটেন্সি এবং কনসিস্টেন্সির মধ্যে একটি সাধারণ ট্রেড-অফ। যদি W = 1 বা R = 1 হয়, তবে একটি অপারেশন দ্রুত রিটার্ন করা হয় কারণ একটি কোঅর্ডিনেটরের শুধুমাত্র যেকোনো একটি রেপ্লিকা থেকে একটি রেসপন্সের জন্য অপেক্ষা করার প্রয়োজন হয়। যদি W বা R > 1 হয়, তবে সিস্টেমটি ভালো কনসিস্টেন্সি অফার করে; তবে, কোয়েরিটি ধীরগতির হবে কারণ কোঅর্ডিনেটরকে অবশ্যই সবচেয়ে ধীরগতির রেপ্লিকা থেকে রেসপন্সের জন্য অপেক্ষা করতে হবে।
যদি W + R > N হয়, তবে স্ট্রং কনসিস্টেন্সি নিশ্চিত করা হয় কারণ কনসিস্টেন্সি নিশ্চিত করতে অবশ্যই কমপক্ষে একটি ওভারল্যাপিং নোড থাকতে হবে যার কাছে সর্বশেষ ডেটা রয়েছে।
আমাদের ব্যবহারের ক্ষেত্রের সাথে মানানসই করতে N, W, এবং R কীভাবে কনফিগার করবেন? এখানে কিছু সম্ভাব্য সেটআপ দেওয়া হলো:
- যদি R = 1 এবং W = N হয়, তবে সিস্টেমটি দ্রুত রিডের জন্য অপ্টিমাইজ করা হয়।
- যদি W = 1 এবং R = N হয়, তবে সিস্টেমটি দ্রুত রাইটের জন্য অপ্টিমাইজ করা হয়।
- যদি W + R > N হয়, তবে স্ট্রং কনসিস্টেন্সি নিশ্চিত করা হয় (সাধারণত N = 3, W = R = 2)।
- যদি W + R <= N হয়, তবে স্ট্রং কনসিস্টেন্সি নিশ্চিত করা হয় না।
প্রয়োজনীয়তার ওপর ভিত্তি করে, আমরা কাঙ্ক্ষিত স্তরের কনসিস্টেন্সি অর্জন করতে W, R, N-এর মান টিউন করতে পারি।
কনসিস্টেন্সি মডেল
একটি কী-ভ্যালু স্টোর ডিজাইন করার সময় বিবেচনা করার জন্য কনসিস্টেন্সি মডেল আরেকটি গুরুত্বপূর্ণ ফ্যাক্টর। একটি কনসিস্টেন্সি মডেল ডেটা কনসিস্টেন্সির মাত্রা সংজ্ঞায়িত করে, এবং সম্ভাব্য কনসিস্টেন্সি মডেলগুলোর একটি বিস্তৃত পরিসর বিদ্যমান:
- স্ট্রং কনসিস্টেন্সি (Strong consistency): যেকোনো রিড অপারেশন সবচেয়ে আপডেট করা রাইট ডেটা আইটেমের ফলাফলের সাথে সামঞ্জস্যপূর্ণ একটি ভ্যালু রিটার্ন করে। একজন ক্লায়েন্ট কখনও পুরানো ডেটা দেখে না।
- উইক কনসিস্টেন্সি (Weak consistency): পরবর্তী রিড অপারেশনগুলো সবচেয়ে আপডেট করা ভ্যালু নাও দেখতে পারে।
- ইভেনচুয়াল কনসিস্টেন্সি (Eventual consistency): এটি উইক কনসিস্টেন্সির একটি নির্দিষ্ট রূপ। যথেষ্ট সময় দেওয়া হলে, সমস্ত আপডেট প্রোপাগেট হয়, এবং সমস্ত রেপ্লিকা কনসিস্টেন্ট হয়ে যায়।
স্ট্রং কনসিস্টেন্সি সাধারণত একটি রেপ্লিকাকে নতুন রিড/রাইট গ্রহণ না করতে বাধ্য করে অর্জন করা হয় যতক্ষণ না প্রতিটি রেপ্লিকা বর্তমান রাইটের বিষয়ে একমত হয়। এই পদ্ধতিটি অত্যন্ত প্রাপ্য (highly available) সিস্টেমগুলোর জন্য আদর্শ নয় কারণ এটি নতুন অপারেশন ব্লক করতে পারে। Dynamo এবং Cassandra ইভেনচুয়াল কনসিস্টেন্সি গ্রহণ করে, যা আমাদের কী-ভ্যালু স্টোরের জন্য আমাদের সুপারিশকৃত কনসিস্টেন্সি মডেল। একযোগে রাইট (concurrent writes) থেকে, ইভেনচুয়াল কনসিস্টেন্সি সিস্টেমে ইনকনসিস্টেন্ট ভ্যালু প্রবেশ করতে দেয় এবং ক্লায়েন্টকে ভ্যালুগুলো পড়ে মীমাংসা (reconcile) করতে বাধ্য করে। পরবর্তী বিভাগে ব্যাখ্যা করা হয়েছে কীভাবে ভার্সনিং (versioning) এর সাথে মীমাংসা কাজ করে।
ইনকনসিস্টেন্সি রেজোলিউশন: ভার্সনিং
রেপ্লিকেশন উচ্চ প্রাপ্যতা দেয় কিন্তু রেপ্লিকাগুলোর মধ্যে ইনকনসিস্টেন্সি তৈরি করে। ইনকনসিস্টেন্সির সমস্যা সমাধান করতে ভার্সনিং এবং ভেক্টর লক (vector locks) ব্যবহার করা হয়। ভার্সনিং এর অর্থ হলো প্রতিটি ডেটা পরিবর্তনকে ডেটার একটি নতুন অপরিবর্তনীয় (immutable) ভার্সন হিসাবে বিবেচনা করা। ভার্সনিং নিয়ে কথা বলার আগে, আসুন ইনকনসিস্টেন্সি কীভাবে ঘটে তা ব্যাখ্যা করতে একটি উদাহরণ ব্যবহার করি:
চিত্র ৭-এ দেখানো হয়েছে, উভয় রেপ্লিকা নোড n1 এবং n2-এর একই ভ্যালু রয়েছে। আসুন এই ভ্যালুটিকে অরিজিনাল ভ্যালু বলি। সার্ভার ১ এবং সার্ভার ২ get(“name”) অপারেশনের জন্য একই ভ্যালু পায়।
[চিত্র ৭-এর বর্ণনা: ছবিটি দুটি পৃথক সার্ভার (সার্ভার ১ এবং সার্ভার ২) থেকে একটি ডাটাবেস অ্যাক্সেস করে ডেটা পুনরুদ্ধার চিত্রিত করে এমন একটি সরলীকৃত সিস্টেম আর্কিটেকচার ডায়াগ্রাম উপস্থাপন করে। প্রতিটি সার্ভার, যথাক্রমে ‘server 1’ এবং ‘server 2’ লেবেলযুক্ত একটি সবুজ আয়তক্ষেত্র হিসাবে চিত্রিত, একটি ডাটাবেস ইনস্ট্যান্সে ‘get(‘name’)’ রিকোয়েস্ট পাঠায়। ডাটাবেসগুলো, নীল সিলিন্ডার হিসাবে উপস্থাপিত যাদের লেবেল ‘n1’ এবং ‘n2’, প্রতিটিতে একটি একক এন্ট্রি ‘name: john’ থাকে। রিকোয়েস্ট পাওয়ার পরে, প্রতিটি ডাটাবেস ইনস্ট্যান্স সংশ্লিষ্ট সার্ভারে ‘john’ ভ্যালুটি রিটার্ন করে। তীর চিহ্নগুলো ডেটা প্রবাহের দিক নির্দেশ করে, সার্ভার থেকে ডাটাবেসে রিকোয়েস্ট এবং রেসপন্স সার্ভারে ফিরে আসা দেখায়। ডায়াগ্রামটি দৃশ্যত একটি রিডান্ডেন্ট সিস্টেম প্রদর্শন করে যেখানে উভয় সার্ভার স্বাধীনভাবে তাদের সংশ্লিষ্ট ডাটাবেস ইনস্ট্যান্স থেকে একই ডেটা (‘john’) পুনরুদ্ধার করতে পারে।] চিত্র ৭
এরপর, সার্ভার ১ নামটি “johnSanFrancisco”-তে পরিবর্তন করে, এবং সার্ভার ২ নামটি “johnNewYork”-তে পরিবর্তন করে যেমনটি চিত্র ৮-এ দেখানো হয়েছে। এই দুটি পরিবর্তন একই সময়ে সম্পাদন করা হয়। এখন, আমাদের কাছে দ্বন্দ্বপূর্ণ (conflicting) ভ্যালু রয়েছে, যাদের ভার্সন v1 এবং v2 বলা হয়।
[চিত্র ৮-এর বর্ণনা: ছবিটি দুটি পৃথক ডাটাবেসে ডেটা ইনসার্শন চিত্রিত করে এমন একটি সরলীকৃত সিস্টেম আর্কিটেকচার ডায়াগ্রাম উপস্থাপন করে। দুটি সার্ভার, ‘server 1’ এবং ‘server 2’ লেবেলযুক্ত, সবুজ আয়তক্ষেত্র হিসাবে চিত্রিত। প্রতিটি সার্ভার যথাক্রমে নীল সিলিন্ডার হিসাবে উপস্থাপিত পৃথক ডাটাবেসে ডেটা পাঠায় যাদের লেবেল ‘n1’ এবং ‘n2’। সার্ভার ১ ডাটাবেস n1-এ কী-ভ্যালু পেয়ার (‘name’, ‘johnSanFrancisco’) সহ একটি ‘put’ রিকোয়েস্ট পাঠায়, যা তখন n1-এর পাশে ‘name: johnSanFrancisco’ হিসাবে নির্দেশ করে ডেটা সংরক্ষণ করে। একইভাবে, সার্ভার ২ ডাটাবেস n2-এ কী-ভ্যালু পেয়ার (‘name’, ‘johnNewYork’) সহ একটি ‘put’ রিকোয়েস্ট পাঠায়, যার ফলে n2-এর মধ্যে ‘name: johnNewYork’ সংরক্ষিত হয়। তীর চিহ্নগুলো সার্ভার থেকে তাদের ডাটাবেসে ডেটা প্রবাহের দিক নির্দেশ করে। n1 এবং n2-কে সংযুক্ত করে একটি উল্লম্ব রেখা রয়েছে, যা দুটি ডাটাবেসের মধ্যে একটি সম্ভাব্য সম্পর্ক বা সংযোগ নির্দেশ করে, যদিও ডায়াগ্রামে এই সংযোগের প্রকৃতি স্পষ্টভাবে সংজ্ঞায়িত করা হয়নি।] চিত্র ৮
এই উদাহরণে, অরিজিনাল ভ্যালুটিকে উপেক্ষা করা যেতে পারে কারণ পরিবর্তনগুলো এর ওপর ভিত্তি করে করা হয়েছিল। তবে, শেষ দুটি ভার্সনের দ্বন্দ্ব সমাধান করার কোনো স্পষ্ট উপায় নেই। এই সমস্যা সমাধান করতে, আমাদের একটি ভার্সনিং সিস্টেম প্রয়োজন যা দ্বন্দ্ব সনাক্ত করতে পারে এবং দ্বন্দ্ব মীমাংসা করতে পারে। একটি ভেক্টর ক্লক (vector clock) এই সমস্যা সমাধান করার একটি সাধারণ কৌশল। আসুন পরীক্ষা করি ভেক্টর ক্লক কীভাবে কাজ করে।
একটি ভেক্টর ক্লক হলো একটি ডেটা আইটেমের সাথে যুক্ত একটি [server, version] পেয়ার। এটি পরীক্ষা করতে ব্যবহার করা যেতে পারে যে একটি ভার্সন অন্যগুলোর আগে আসে, পরে আসে, নাকি দ্বন্দ্বপূর্ণ।
ধরে নিন একটি ভেক্টর ক্লক D([S1, v1], [S2, v2], …, [Sn, vn]) দ্বারা উপস্থাপন করা হয়েছে, যেখানে D একটি ডেটা আইটেম, v1 একটি ভার্সন কাউন্টার, এবং s1 একটি সার্ভার নম্বর, ইত্যাদি। যদি ডেটা আইটেম D সার্ভার Si-তে লেখা হয়, তবে সিস্টেমকে অবশ্যই নিম্নলিখিত টাস্কগুলোর একটি সম্পাদন করতে হবে।
- যদি [Si, vi] বিদ্যমান থাকে তবে vi ইনক্রিমেন্ট করুন।
- অন্যথায়, একটি নতুন এন্ট্রি [Si, 1] তৈরি করুন।
উপরের বিমূর্ত যুক্তিটি চিত্র ৯-এ দেখানো একটি বাস্তব উদাহরণ দিয়ে ব্যাখ্যা করা হয়েছে।
[চিত্র ৯-এর বর্ণনা: ছবিটি ডেটা রেপ্লিকেশন এবং মীমাংসা প্রক্রিয়া চিত্রিত করে এমন একটি ডেটা ফ্লো ডায়াগ্রাম উপস্থাপন করে। একটি উপর থেকে নিচের প্রবাহ D1([Sx, 1]) ডেটা দিয়ে শুরু হয়, যেখানে Sx সম্ভবত একটি সোর্স এবং 1 একটি ভার্সন বা টাইমস্ট্যাম্প নির্দেশ করে, যা Sx দ্বারা লেখা হয়েছে (ধাপ ১)। এই ডেটাটি তারপর D2([Sx, 2]) তৈরি করতে Sx দ্বারা আবার লেখা হয় (ধাপ ২)। D2 তারপর দুটি পথে বিভক্ত হয়: একটি যেখানে ডেটা Sy দ্বারা লেখা হয় (ধাপ ৩) যার ফলে D3([Sx, 2], [Sy, 1]) হয়, যা Sy-তে রেপ্লিকেশন নির্দেশ করে মূল সোর্স এবং ভার্সন তথ্য সহ; এবং অন্যটি যেখানে ডেটা Sz দ্বারা লেখা হয় (ধাপ ৪) যার ফলে D4([Sx, 2], [Sz, 1]) হয়, একইভাবে Sz-তে রেপ্লিকেট হয়। পরিশেষে, D3 এবং D4 মিলিত হয়, এবং তাদের ডেটা মীমাংসা করা হয় এবং Sx দ্বারা লেখা হয় (ধাপ ৫) D5([Sx, ...]) তৈরি করতে, যা Sx, Sy, এবং Sz থেকে তথ্য অন্তর্ভুক্ত করে একটি চূড়ান্ত, একীভূত ডেটা সেট নির্দেশ করে। D5-এর উপবৃত্তাকার চিহ্ন (…) চূড়ান্ত মীমাংসাকৃত ডেটাতে সম্ভাব্য আরও তথ্য অন্তর্ভুক্ত নির্দেশ করে। বন্ধনীতে সংখ্যাগুলো প্রক্রিয়ার ক্রমিক ধাপ নির্দেশ করে।]
চিত্র ৯
১. একজন ক্লায়েন্ট সিস্টেমে একটি ডেটা আইটেম D1 লেখে, এবং রাইটটি সার্ভার Sx দ্বারা হ্যান্ডেল করা হয়, যার এখন ভেক্টর ক্লক D1[(Sx, 1)] রয়েছে। ২. অন্য একজন ক্লায়েন্ট সর্বশেষ D1 পড়ে, এটিকে D2-তে আপডেট করে, এবং এটি আবার লেখে। D2 D1 থেকে নেমে আসে তাই এটি D1-কে ওভাররাইট করে। ধরে নিন রাইটটি একই সার্ভার Sx দ্বারা হ্যান্ডেল করা হয়, যার এখন ভেক্টর ক্লক D2([Sx, 2]) রয়েছে। ৩. অন্য একজন ক্লায়েন্ট সর্বশেষ D2 পড়ে, এটিকে D3-তে আপডেট করে, এবং এটি আবার লেখে। ধরে নিন রাইটটি সার্ভার Sy দ্বারা হ্যান্ডেল করা হয়, যার এখন ভেক্টর ক্লক D3([Sx, 2], [Sy, 1])) রয়েছে। ৪. অন্য একজন ক্লায়েন্ট সর্বশেষ D2 পড়ে, এটিকে D4-তে আপডেট করে, এবং এটি আবার লেখে। ধরে নিন রাইটটি সার্ভার Sz দ্বারা হ্যান্ডেল করা হয়, যার এখন D4([Sx, 2], [Sz, 1])) রয়েছে। ৫. যখন অন্য একজন ক্লায়েন্ট D3 এবং D4 পড়ে, তখন এটি একটি দ্বন্দ্ব আবিষ্কার করে, যা ডেটা আইটেম D2 উভয় Sy এবং Sz দ্বারা পরিবর্তিত হওয়ার কারণে ঘটে। দ্বন্দ্বটি ক্লায়েন্ট দ্বারা সমাধান করা হয় এবং আপডেট করা ডেটা সার্ভারে পাঠানো হয়। ধরে নিন রাইটটি Sx দ্বারা হ্যান্ডেল করা হয়, যার এখন D5([Sx, 3], [Sy, 1], [Sz, 1]) রয়েছে। আমরা শীঘ্রই ব্যাখ্যা করব কীভাবে দ্বন্দ্ব সনাক্ত করতে হয়।
ভেক্টর ক্লক ব্যবহার করে, এটি বলা সহজ যে একটি ভার্সন X হলো ভার্সন Y-এর একটি পূর্বপুরুষ (অর্থাৎ কোনো দ্বন্দ্ব নেই) যদি Y-এর ভেক্টর ক্লকে প্রতিটি অংশগ্রহণকারীর জন্য ভার্সন কাউন্টারগুলো X-এর কাউন্টারগুলোর চেয়ে বড় বা সমান হয়। উদাহরণস্বরূপ, ভেক্টর ক্লক D([s0, 1], [s1, 1])] হলো D([s0, 1], [s1, 2])-এর একটি পূর্বপুরুষ। তাই, কোনো দ্বন্দ্ব রেকর্ড করা হয় না।
একইভাবে, আপনি বলতে পারেন যে একটি ভার্সন X হলো Y-এর একটি সহোদর (অর্থাৎ, একটি দ্বন্দ্ব বিদ্যমান) যদি Y-এর ভেক্টর ক্লকে এমন কোনো অংশগ্রহণকারী থাকে যার কাউন্টার X-এর সংশ্লিষ্ট কাউন্টারের চেয়ে কম। উদাহরণস্বরূপ, নিম্নলিখিত দুটি ভেক্টর ক্লক নির্দেশ করে যে একটি দ্বন্দ্ব রয়েছে: D([s0, 1], [s1, 2]) এবং D([s0, 2], [s1, 1])।
যদিও ভেক্টর ক্লক দ্বন্দ্ব সমাধান করতে পারে, এর দুটি উল্লেখযোগ্য অসুবিধা রয়েছে। প্রথমত, ভেক্টর ক্লক ক্লায়েন্টে জটিলতা যোগ করে কারণ এটিকে দ্বন্দ্ব সমাধানের যুক্তি বাস্তবায়ন করতে হয়।
দ্বিতীয়ত, ভেক্টর ক্লকে [server: version] পেয়ারগুলো দ্রুত বৃদ্ধি পেতে পারে। এই সমস্যা সমাধান করতে, আমরা দৈর্ঘ্যের জন্য একটি থ্রেশহোল্ড সেট করি, এবং যদি এটি সীমা অতিক্রম করে, তবে পুরানো পেয়ারগুলো সরিয়ে দেওয়া হয়। এর ফলে মীমাংসায় অদক্ষতা দেখা দিতে পারে কারণ বংশধর সম্পর্ক সঠিকভাবে নির্ধারণ করা যায় না। তবে, Dynamo পেপার [4] এর ওপর ভিত্তি করে, Amazon এখনও প্রোডাকশনে এই সমস্যার সম্মুখীন হয়নি; তাই, এটি সম্ভবত বেশিরভাগ কোম্পানির জন্য একটি গ্রহণযোগ্য সমাধান।
ফেইলিওর হ্যান্ডলিং
স্কেলে যেকোনো বড় সিস্টেমের মতো, ফেইলিওরগুলো কেবল অনিবার্যই নয় বরং সাধারণও। ফেইলিওর পরিস্থিতি হ্যান্ডেল করা অত্যন্ত গুরুত্বপূর্ণ। এই বিভাগে, আমরা প্রথমে ফেইলিওর সনাক্ত করার কৌশলগুলো পরিচয় করিয়ে দিই। তারপর, আমরা সাধারণ ফেইলিওর রেজোলিউশন কৌশলগুলো পর্যালোচনা করি।
ফেইলিওর ডিটেকশন
একটি ডিস্ট্রিবিউটেড সিস্টেমে, একটি সার্ভার ডাউন হয়ে গেছে তা বিশ্বাস করা অপর্যাপ্ত কারণ অন্য একটি সার্ভার তাই বলে। সাধারণত, একটি সার্ভারকে ডাউন হিসাবে চিহ্নিত করতে কমপক্ষে দুটি স্বাধীন তথ্যের উৎস প্রয়োজন হয়।
চিত্র ১০-এ দেখানো হয়েছে, অল-টু-অল মাল্টিকাস্টিং একটি সহজবোধ্য সমাধান। তবে, সিস্টেমে অনেক সার্ভার থাকলে এটি অদক্ষ।
[চিত্র ১০-এর বর্ণনা: ছবিটি চারটি নোডের একটি সম্পূর্ণরূপে সংযুক্ত গ্রাফ বা সম্পূর্ণ গ্রাফ উপস্থাপন করে যাদের S0, S1, S2, এবং S3 লেবেলযুক্ত, একটি বড় ধূসর বৃত্তের মধ্যে চক্রাকারে সাজানো। প্রতিটি নোড নীল তীর চিহ্ন দ্বারা উপস্থাপিত নির্দেশিত এজের মাধ্যমে অন্য প্রতিটি নোডের সাথে সংযুক্ত। তীর চিহ্নগুলো তথ্য প্রবাহ বা নোডগুলোর মধ্যে যোগাযোগের দিক নির্দেশ করে। বিশেষ করে, S0 এবং S1, S2, এবং S3 প্রতিটির মধ্যে দ্বিমুখী সংযোগ রয়েছে, যার অর্থ তথ্য S0 থেকে এবং S0-তে উভয় দিকে প্রবাহিত হয়। একইভাবে, S1, S2, এবং S3-ও দ্বিমুখী তীর চিহ্ন দ্বারা আন্তঃসংযুক্ত, যা তাদের মধ্যে তথ্য আদান-প্রদানের অনুমতি দেয়। সামগ্রিক কাঠামোটি এমন একটি সিস্টেম নির্দেশ করে যেখানে প্রতিটি উপাদান (S0, S1, S2, S3) সরাসরি অন্য প্রতিটি উপাদানের সাথে যোগাযোগ করতে পারে, যা উচ্চ মাত্রার সংযোগস্থল এবং সম্ভাব্য বিকেন্দ্রীভূত যোগাযোগ আর্কিটেকচার নির্দেশ করে। নিচে ‘Viewer does not support full SVG 1.1’ টেক্সটটি প্রদর্শন মিডিয়ামের একটি সীমাবদ্ধতা নির্দেশ করে, ডায়াগ্রামটির নয়।] চিত্র ১০
একটি ভালো সমাধান হলো গসিপ প্রোটোকলের (gossip protocol) মতো বিকেন্দ্রীভূত ফেইলিওর ডিটেকশন পদ্ধতি ব্যবহার করা। গসিপ প্রোটোকল নিম্নরূপে কাজ করে:
- প্রতিটি নোড একটি নোড মেম্বারশিপ লিস্ট বজায় রাখে, যাতে মেম্বার আইডি এবং হার্টবিট কাউন্টার থাকে।
- প্রতিটি নোড পর্যায়ক্রমে এর হার্টবিট কাউন্টার ইনক্রিমেন্ট করে।
- প্রতিটি নোড পর্যায়ক্রমে র্যান্ডম নোডগুলোর একটি সেটে হার্টবিট পাঠায়, যা আবার অন্য একটি সেট নোডে প্রোপাগেট হয়।
- নোডগুলো হার্টবিট পাওয়ার পরে, মেম্বারশিপ লিস্টটি সর্বশেষ তথ্যে আপডেট করা হয়।
- যদি হার্টবিট পূর্বনির্ধারিত সময়ের চেয়ে বেশি সময় ধরে বৃদ্ধি না পায়, তবে মেম্বারকে অফলাইন হিসাবে বিবেচনা করা হয়।
[চিত্র ১১-এর বর্ণনা: ছবিটি একটি মেম্বারশিপ লিস্ট এবং একটি রিং টপোলজি নেটওয়ার্ক দেখায় এমন একটি সিস্টেম ডায়াগ্রাম উপস্থাপন করে। উপরের বাম দিকে একটি আংশিক মেম্বারশিপ লিস্ট দেখানো হয়েছে যার লেবেল ‘s0’s membership list,’ একটি নমুনা এন্ট্রি প্রদর্শন করে: ‘Member ID Heartbeat counter Time 0 10232 12:00:01 1 10224 12:00:10 2 99081 11:58:02 3 1…’। ছবির মূল অংশটি পাঁচটি নোড s0, s1, s2, s3, এবং s5 সহ একটি রিং নেটওয়ার্ক চিত্রিত করে। নোডগুলো বৃত্ত হিসাবে উপস্থাপিত, একটি ধূসর চাপ দ্বারা সংযুক্ত যা রিং গঠন করে। নির্দেশিত নীল তীর চিহ্ন যোগাযোগ প্রবাহ নির্দেশ করে। s0 থেকে s2-এর দিকে একটি ড্যাশ করা নীল রেখা সংযুক্ত, ‘detected s2 is down’ লেবেলযুক্ত, যা নির্দেশ করে যে s0 s2-এর একটি ফেইলিওর সনাক্ত করেছে। সলিড নীল তীর চিহ্ন s0 থেকে s1, s0 থেকে s3, s3 থেকে s4, s3 থেকে s5, এবং s4 থেকে s3-এর দিকে নির্দেশিত সংযোগ দেখায়। নোড s2 দৃশ্যত রিং-এর অংশ কিন্তু কোনো আগত বা বহির্গামী সংযোগ দেখানো হয়নি। নিচের ডানদিকের কোণায় একটি বার্তা প্রদর্শিত হয়: ‘Viewer does not support full SVG 1.1’।] চিত্র ১১
চিত্র ১১-এ দেখানো হিসাবে:
- নোড s0 বাম দিকে দেখানো একটি নোড মেম্বারশিপ লিস্ট বজায় রাখে।
- নোড s0 লক্ষ্য করে যে নোড s2-এর (member ID = 2) হার্টবিট কাউন্টার দীর্ঘ সময় ধরে বৃদ্ধি পায়নি।
- নোড s0 s2-এর তথ্য সহ হার্টবিট র্যান্ডম নোডগুলোর একটি সেটে পাঠায়। অন্যান্য নোডগুলো নিশ্চিত করার পরে যে s2-এর হার্টবিট কাউন্টার দীর্ঘ সময় ধরে আপডেট করা হয়নি, নোড s2-কে ডাউন হিসাবে চিহ্নিত করা হয়, এবং এই তথ্য অন্যান্য নোডে প্রোপাগেট করা হয়।
অস্থায়ী ফেইলিওর হ্যান্ডলিং
গসিপ প্রোটোকলের মাধ্যমে ফেইলিওর সনাক্ত হওয়ার পরে, প্রাপ্যতা নিশ্চিত করতে সিস্টেমের কিছু নির্দিষ্ট মেকানিজম মোতায়েন করা প্রয়োজন। স্ট্রিক্ট কোরাম পদ্ধতিতে, রিড এবং রাইট অপারেশন ব্লক হতে পারে যেমনটি কোরাম কনসেনসাস বিভাগে চিত্রিত করা হয়েছে।
প্রাপ্যতা উন্নত করতে “sloppy quorum” [4] নামক একটি কৌশল ব্যবহার করা হয়। কোরাম প্রয়োজনীয়তা জোর করে কার্যকর করার পরিবর্তে, সিস্টেমটি হ্যাশ রিং-এ রাইটের জন্য প্রথম W সংখ্যক সুস্থ সার্ভার এবং রিডের জন্য প্রথম R সংখ্যক সুস্থ সার্ভার বেছে নেয়। অফলাইন সার্ভারগুলো উপেক্ষা করা হয়।
যদি নেটওয়ার্ক বা সার্ভার ফেইলিওরের কারণে একটি সার্ভার অনুপলব্ধ হয়, তবে অন্য একটি সার্ভার সাময়িকভাবে রিকোয়েস্ট প্রসেস করবে। যখন ডাউন সার্ভারটি চালু হয়, তখন ডেটা কনসিস্টেন্সি অর্জন করতে পরিবর্তনগুলো পুশ ব্যাক করা হবে। এই প্রক্রিয়াটিকে হিন্টেড হ্যান্ডঅফ (hinted handoff) বলা হয়। চিত্র ১২-এ যেহেতু s2 অনুপলব্ধ, তাই রিড এবং রাইট সাময়িকভাবে s3 দ্বারা হ্যান্ডেল করা হবে। যখন s2 অনলাইনে ফিরে আসে, তখন s3 ডেটাটি s2-এর কাছে ফেরত দেবে।
[চিত্র ১২-এর বর্ণনা: ছবিটি একটি সরলীকৃত ডিস্ট্রিবিউটেড সিস্টেম আর্কিটেকচার উপস্থাপন করে, সম্ভবত একটি কী-ভ্যালু স্টোরের জন্য, যা চারটি নোড s0, s1, s2, এবং s3-এর একটি বৃত্তাকার বিন্যাস হিসাবে চিত্রিত, সবগুলো একটি কেন্দ্রীয় ‘coordinator’ এর সাথে আন্তঃসংযুক্ত এবং যোগাযোগ করে। সলিড তীর চিহ্নগুলো ডেটা প্রবাহ নির্দেশ করে, বিশেষ করে put(key1, val1) অপারেশন, যা একটি কী-ভ্যালু পেয়ার ইনসার্শন নির্দেশ করে। এই ডেটা প্রবাহগুলো কোঅর্ডিনেটর থেকে উৎপন্ন হয় এবং s0 এবং s1-এর দিকে নির্দেশিত হয়, প্রতিটি রিসিভিং নোড একটি পৃথক তীর চিহ্ন বরাবর কোঅর্ডিনেটরে একটি ‘ACK’ স্বীকৃতি পাঠায়। কোঅর্ডিনেটর থেকে s2-এর দিকে একটি ড্যাশ করা তীর চিহ্ন একটি put(key1, val1) অপারেশন দেখায়, যা কম নির্ভরযোগ্য বা ভিন্ন যোগাযোগ পদ্ধতি নির্দেশ করে। নোড s3 বৃত্তের সাথে সংযুক্ত দেখানো হয়েছে কিন্তু কোনো স্পষ্ট ডেটা প্রবাহ চিত্রিত করা হয়নি। নোডগুলো s0, s1, s2, এবং s3 সম্ভবত ডেটা স্টোরের রেপ্লিকা বা শার্ড, এবং কোঅর্ডিনেটর ডেটা বিতরণ এবং কনসিস্টেন্সি পরিচালনা করে। ছবিটি প্রদর্শন করতে ব্যবহৃত রেন্ডারিং সফটওয়্যারের একটি সীমাবদ্ধতা ‘Viewer does not support full SVG 1.1’ নির্দেশ করে।]
চিত্র ১২
স্থায়ী ফেইলিওর হ্যান্ডলিং
হিন্টেড হ্যান্ডঅফ অস্থায়ী ফেইলিওর হ্যান্ডেল করতে ব্যবহার করা হয়। যদি একটি রেপ্লিকা স্থায়ীভাবে অনুপলব্ধ হয় তবে কী হবে? এমন পরিস্থিতি হ্যান্ডেল করতে, আমরা রেপ্লিকাগুলো সিঙ্কে রাখতে একটি অ্যান্টি-এন্ট্রপি (anti-entropy) প্রোটোকল বাস্তবায়ন করি। অ্যান্টি-এন্ট্রিপিতে রেপ্লিকার প্রতিটি ডেটার টুকরো তুলনা করা এবং প্রতিটি রেপ্লিকাকে সর্বশেষ ভার্সনে আপডেট করা জড়িত। ইনকনসিস্টেন্সি সনাক্তকরণ এবং স্থানান্তরিত ডেটার পরিমাণ কমাতে একটি মার্কল ট্রি (Merkle tree) ব্যবহার করা হয়।
উইকিপিডিয়া [7] থেকে উদ্ধৃত: “একটি হ্যাশ ট্রি বা মার্কল ট্রি হলো একটি ট্রি যেখানে প্রতিটি নন-লিফ নোডকে এর চাইল্ড নোডগুলোর লেবেল বা ভ্যালুর (লিফের ক্ষেত্রে) হ্যাশ দিয়ে লেবেল করা হয়। হ্যাশ ট্রি বড় ডেটা স্ট্রাকচারের বিষয়বস্তুর দক্ষ এবং নিরাপদ যাচাইয়ের অনুমতি দেয়”।
ধরে নিচ্ছি কী স্পেস ১ থেকে ১২ পর্যন্ত, নিচের ধাপগুলো দেখায় কীভাবে একটি মার্কল ট্রি তৈরি করতে হয়। হাইলাইট করা বাক্সগুলো ইনকনসিস্টেন্সি নির্দেশ করে।
ধাপ ১: চিত্র ১৩-এ দেখানো হিসাবে কী স্পেসকে বাকেটে (আমাদের উদাহরণে ৪টি) ভাগ করুন। ট্রির একটি সীমিত গভীরতা বজায় রাখতে একটি বাকেটকে রুট লেভেলের নোড হিসাবে ব্যবহার করা হয়।
[চিত্র ১৩-এর বর্ণনা: ছবিটি ‘server 1’ এবং ‘server 2’ লেবেলযুক্ত দুটি সার্ভার জুড়ে ডেটা পার্টিশনিং চিত্রিত করে এমন একটি সরলীকৃত ডায়াগ্রাম উপস্থাপন করে। প্রতিটি সার্ভারকে একটি গোলাকার আয়তক্ষেত্র হিসাবে চিত্রিত করা হয়েছে যাতে ডেটা পার্টিশন নির্দেশকারী কয়েকটি উল্লম্ব আয়তক্ষেত্রাকার ব্লক রয়েছে। সার্ভার ১ ‘1…’, ’…’, ‘7…’, এবং ‘10…’ লেবেলযুক্ত পার্টিশন দেখায়, যা প্রতিটি পার্টিশনের মধ্যে সংরক্ষিত ডেটার একটি পরিসর নির্দেশ করে। একইভাবে, সার্ভার ২ একই লেবেল ‘1…’, ’…’, ‘7…’, এবং ‘10…’ সহ পার্টিশন প্রদর্শন করে, যা একটি রেপ্লিকেশন বা বিতরণ কৌশল নির্দেশ করে। লেবেলের ভেতরের উপবৃত্তাকার চিহ্ন (’…’) বোঝায় যে প্রতিটি পার্টিশনে কেবল দেখানো সংখ্যাগুলোই নয়, বরং একাধিক ডেটা এন্ট্রি রয়েছে। সার্ভারগুলোর মধ্যে কোনো স্পষ্ট সংযোগ আঁকা হয়নি, যা বোঝায় যে ডেটা অ্যাক্সেস স্বাধীনভাবে বা একটি পৃথক, অ-চিত্রিত মেকানিজমের মাধ্যমে হ্যান্ডেল করা হতে পারে। নিচের টেক্সট ‘Viewer does not support full SVG 1.1’ মূল ডায়াগ্রাম রেন্ডার করার একটি প্রযুক্তিগত সীমাবদ্ধতা নির্দেশ করে, সিস্টেমের ডিজাইনের একটি অংশ নয়।] চিত্র ১৩
ধাপ ২: বাকেটগুলো তৈরি হওয়ার পরে, একটি ইউনিফর্ম হ্যাশিং পদ্ধতি ব্যবহার করে একটি বাকেটের প্রতিটি কী হ্যাশ করুন (চিত্র ১৪)।
[চিত্র ১৪-এর বর্ণনা: ছবিটি ‘server 1’ এবং ‘server 2’ লেবেলযুক্ত দুটি সার্ভার জুড়ে ডেটা বিতরণ চিত্রিত করে এমন একটি সরলীকৃত ডায়াগ্রাম উপস্থাপন করে। প্রতিটি সার্ভারকে একটি গোলাকার আয়তক্ষেত্র হিসাবে চিত্রিত করা হয়েছে যাতে ডেটা পার্টিশন নির্দেশকারী কয়েকটি আয়তক্ষেত্রাকার বাক্স রয়েছে। সার্ভার ১ ডেটা ম্যাপিং নির্দেশকারী লেবেল সহ তিনটি পার্টিশন দেখায়: ‘1 -> 2343…’, ‘7 -> 9654…’, এবং ‘10 -> 3542…’। উপবৃত্তাকার চিহ্ন (…) বোঝায় যে সাংখ্যিক ক্রমগুলো দেখানোর বাইরেও চলতে থাকে। সার্ভার ২ এই কাঠামোটি আয়না করে, একই ক্রমে একই ডেটা ম্যাপিং লেবেল প্রদর্শন করে। বিন্যাসটি একটি সম্ভাব্য ডেটা রেপ্লিকেশন বা শার্ডিং কৌশল নির্দেশ করে, যেখানে অনুরূপ ডেটা রিডান্ডেন্সি বা লোড ব্যালেন্সিংয়ের জন্য একাধিক সার্ভার জুড়ে বিতরণ করা হয়। নিচে ‘Viewer does not support full SVG 1.1’ টেক্সটটি ইমেজ রেন্ডারিং সফটওয়্যারের একটি সীমাবদ্ধতা নির্দেশ করে।] চিত্র ১৪
ধাপ ৩: প্রতিটি বাকেটের জন্য একটি একক হ্যাশ নোড তৈরি করুন (চিত্র ১৫)।
[চিত্র ১৫-এর বর্ণনা: ছবিটি দুটি সার্ভার, ‘server 1’ এবং ‘server 2’ লেবেলযুক্ত একটি ডিস্ট্রিবিউটেড সিস্টেম আর্কিটেকচার চিত্রিত করে। প্রতিটি সার্ভারে সংখ্যাসূচক আইডি দ্বারা চিহ্নিত চারটি আয়তক্ষেত্রাকার বাক্স রয়েছে যা প্রসেস বা সার্ভিস নির্দেশ করে: 6901, 6773, 8601 (সার্ভার ১-এ হালকা লাল রঙে হাইলাইট করা এবং সার্ভার ২-এ 7975), এবং 7812। এই বাক্সগুলো ডেটা স্টোর বা অন্যান্য রিসোর্স নির্দেশকারী ড্যাশ-লাইনের সীমানাযুক্ত আয়তক্ষেত্রাকার বাক্সের সাথে রেখার মাধ্যমে সংযুক্ত। সংযোগগুলো ডেটা প্রবাহ দেখায়, লেবেলগুলো ডেটা আইটেম (একটি সংখ্যা) এবং একটি তীর চিহ্ন দিক নির্দেশ করে। উদাহরণস্বরূপ, সার্ভার ১-এ, প্রসেস 6901 ‘1 -> 2343…’ লেবেলযুক্ত একটি ডেটা স্টোরে ডেটা আইটেম ‘1’ পাঠায়, যখন প্রসেস 8601 ‘7 -> 9654…’ লেবেলযুক্ত একটি ডেটা স্টোরে ডেটা আইটেম ‘7’ পাঠায়। সার্ভার ২ অনুরূপ কাঠামো দেখায় সংশ্লিষ্ট প্রসেস এবং ডেটা প্রবাহ সহ, কিন্তু ভিন্ন ডেটা আইটেম সহ (যেমন, 7975 ‘7’ কে ‘7 -> 9654…’-এ পাঠায়)। নিচের নোটটি ডায়াগ্রাম প্রদর্শন করতে ব্যবহৃত ভিউয়ারের একটি সীমাবদ্ধতা নির্দেশ করে।] চিত্র ১৫
ধাপ ৪: চাইল্ডগুলোর হ্যাশ গণনা করে রুট পর্যন্ত ট্রিটি উপরের দিকে তৈরি করুন (চিত্র ১৬)।
[চিত্র ১৬-এর বর্ণনা: ছবিটি ‘server 1’ এবং ‘server 2’ লেবেলযুক্ত দুটি সার্ভার জুড়ে ডেটা বিতরণ চিত্রিত করে এমন একটি ডায়াগ্রাম উপস্থাপন করে। প্রতিটি সার্ভারে একটি ট্রি-এর মতো কাঠামো রয়েছে। প্রতিটি ট্রির উপরের নোডটি একটি রঙিন আয়তক্ষেত্র (হালকা লাল/গোলাপী) যাতে একটি সাংখ্যিক আইডি রয়েছে (সার্ভার ১-এর জন্য 5357 এবং সার্ভার ২-এর জন্য 9213)। এই উপরের নোডগুলো অন্যান্য নোডে শাখা-প্রশাখাযুক্ত হয়, কিছু রঙিন আয়তক্ষেত্র (হালকা লাল/গোলাপী) এবং কিছু সাদা আয়তক্ষেত্র, প্রতিটিতে সাংখ্যিক আইডি রয়েছে। সাদা আয়তক্ষেত্রগুলো ডেটা চাঙ্ক নির্দেশ করে, যখন হালকা লাল/গোলাপী আয়তক্ষেত্রগুলো তাদের নিচের ডেটা চাঙ্কগুলোর অ্যাগ্রিগেশন বা সারাংশ নির্দেশ করে। প্রতিটি ট্রির সর্বনিম্ন স্তরে সাদা আয়তক্ষেত্র রয়েছে যার লেবেল ডেটার একটি পরিসর নির্দেশ করে (যেমন, ‘1 -> 2343…’, ‘7 -> 9654…’, ‘10 -> 3542…’), যা একটি পার্টিশনিং স্কিম নির্দেশ করে। কাঠামোটি উভয় সার্ভার জুড়ে সামঞ্জস্যপূর্ণ, উভয়েই অনুরূপ সাংখ্যিক আইডি উপস্থিত থাকে, কিন্তু সর্বনিম্ন স্তরে ভিন্ন অ্যাগ্রিগেশন এবং ডেটা পরিসর থাকে, যা একটি ডিস্ট্রিবিউটেড ডেটা স্টোরেজ এবং পুনরুদ্ধার সিস্টেম নির্দেশ করে। ডায়াগ্রামটি একটি হায়ারার্কিক্যাল কাঠামো দেখায় যেখানে উচ্চ-স্তরের নোডগুলো নিম্ন-স্তরের নোডগুলোর ডেটা সারাংশ বা অ্যাগ্রিগেট করে।] চিত্র ১৬
দুটি মার্কল ট্রি তুলনা করতে, রুট হ্যাশ তুলনা করে শুরু করুন। যদি রুট হ্যাশ মিলে যায়, তবে উভয় সার্ভারে একই ডেটা রয়েছে। যদি রুট হ্যাশ দ্বিমত পোষণ করে, তবে বাম চাইল্ড হ্যাশ তুলনা করা হয় তারপর ডান চাইল্ড হ্যাশ। আপনি কোন বাকেটগুলো সিঙ্ক্রোনাইজ করা হয়নি তা খুঁজে পেতে ট্রিটি ট্রাভার্স করতে পারেন এবং শুধুমাত্র সেই বাকেটগুলো সিঙ্ক্রোনাইজ করতে পারেন।
মার্কল ট্রি ব্যবহার করে, সিঙ্ক্রোনাইজ করতে প্রয়োজনীয় ডেটার পরিমাণ দুটি রেপ্লিকার মধ্যে পার্থক্যের সমানুপাতিক, তারা যে পরিমাণ ডেটা ধারণ করে তার নয়। বাস্তব-বিশ্বের সিস্টেমে, বাকেটের সাইজ বেশ বড় হয়। উদাহরণস্বরূপ, একটি সম্ভাব্য কনফিগারেশন হলো প্রতি এক বিলিয়ন কীতে এক মিলিয়ন বাকেট, তাই প্রতিটি বাকেটে কেবল ১০০০টি কী থাকে।
ডেটা সেন্টার আউটেজ হ্যান্ডলিং
পাওয়ার আউটেজ, নেটওয়ার্ক আউটেজ, প্রাকৃতিক দুর্যোগ ইত্যাদির কারণে ডেটা সেন্টার আউটেজ ঘটতে পারে। ডেটা সেন্টার আউটেজ হ্যান্ডেল করতে সক্ষম একটি সিস্টেম তৈরি করতে, একাধিক ডেটা সেন্টার জুড়ে ডেটা রেপ্লিকেট করা গুরুত্বপূর্ণ। এমনকি যদি একটি ডেটা সেন্টার সম্পূর্ণ অফলাইন থাকে, ব্যবহারকারীরা এখনও অন্য ডেটা সেন্টারগুলোর মাধ্যমে ডেটা অ্যাক্সেস করতে পারবেন।
সিস্টেম আর্কিটেকচার ডায়াগ্রাম
যেহেতু আমরা একটি কী-ভ্যালু স্টোর ডিজাইন করার বিভিন্ন প্রযুক্তিগত বিবেচনা নিয়ে আলোচনা করেছি, আমরা এখন চিত্র ১৭-এ দেখানো আর্কিটেকচার ডায়াগ্রামের ওপর আমাদের ফোকাস সরাতে পারি।
[চিত্র ১৭-এর বর্ণনা: ছবিটি একটি ক্লায়েন্ট একটি ডিস্ট্রিবিউটেড সিস্টেমের সাথে মিথস্ক্রিয়া করে এমন একটি সিস্টেম আর্কিটেকচার ডায়াগ্রাম দেখায়। ‘Client’ লেবেলযুক্ত একটি আয়তক্ষেত্রাকার বাক্স ‘n6’ লেবেলযুক্ত একটি কেন্দ্রীয় নোডে ‘read/write’ রিকোয়েস্ট পাঠায় এবং ‘coordinator’ হিসাবে চিহ্নিত। এই কোঅর্ডিনেটর নোড রিকোয়েস্ট গ্রহণ করে এবং একটি ড্যাশ করা রেখার মাধ্যমে ক্লায়েন্টে ‘response’ ডেটা ফেরত পাঠায় যা একটি দ্বিমুখী যোগাযোগ নির্দেশ করে। নোড n6 সাতটি অন্যান্য নোডের (n0-n5, n7) একটি রিং-এর সাথে সলিড ধূসর রেখার মাধ্যমে সংযুক্ত। সলিড কালো তীর চিহ্ন n6 থেকে n0, n1, এবং n2 নোডে ডেটা প্রবাহ নির্দেশ করে, যখন ড্যাশ করা কালো তীর চিহ্ন n0, n1, এবং n2 নোড থেকে n6-এ ফিরে ডেটা প্রবাহ দেখায়। এটি একটি ডিস্ট্রিবিউটেড ডেটা স্টোরেজ বা প্রসেসিং সিস্টেম নির্দেশ করে যেখানে কোঅর্ডিনেটর অন্যান্য নোডগুলোর মধ্যে যোগাযোগ এবং ডেটা বিতরণ পরিচালনা করে। নোড n0, n1, এবং n2 হালকা নীল বৃত্ত হিসাবে চিত্রিত, যা নির্দেশ করে যে তাদের রিং-এর অন্যান্য নোডগুলোর (n3, n4, n5, n7) তুলনায় একটি ভিন্ন ভূমিকা বা স্ট্যাটাস থাকতে পারে, যা সাধারণ সাদা বৃত্ত দ্বারা উপস্থাপিত। ছবির নিচে একটি বার্তা রয়েছে যা নির্দেশ করে যে ভিউয়ার সম্পূর্ণ SVG 1.1 সমর্থন করে না।] চিত্র ১৭
আর্কিটেকচারের মূল বৈশিষ্ট্যগুলো নিচে তালিকাভুক্ত করা হলো:
- ক্লায়েন্টগুলো সাধারণ API-এর মাধ্যমে কী-ভ্যালু স্টোরের সাথে যোগাযোগ করে:
get(key)এবংput(key, value)। - একটি কোঅর্ডিনেটর হলো একটি নোড যা ক্লায়েন্ট এবং কী-ভ্যালু স্টোরের মধ্যে একটি প্রক্সি হিসাবে কাজ করে।
- নোডগুলো কনসিস্টেন্ট হ্যাশিং ব্যবহার করে একটি রিং-এ বিতরণ করা হয়।
- সিস্টেমটি সম্পূর্ণ বিকেন্দ্রীভূত তাই নোড যোগ এবং সরানো স্বয়ংক্রিয় হতে পারে।
- ডেটা একাধিক নোডে রেপ্লিকেট করা হয়।
- কোনো সিঙ্গেল পয়েন্ট অফ ফেইলিওর নেই কারণ প্রতিটি নোডের দায়িত্বের সেট একই।
যেহেতু ডিজাইনটি বিকেন্দ্রীভূত, প্রতিটি নোড চিত্র ১৮-এ উপস্থাপিত অনেকগুলো টাস্ক সম্পাদন করে।
[চিত্র ১৮-এর বর্ণনা: ছবিটি একটি ডিস্ট্রিবিউটেড সিস্টেমে একটি একক নোড উপস্থাপন করে, যা ‘node’ লেবেলযুক্ত একটি বড় বৃত্ত হিসাবে চিত্রিত। এই বৃত্তের ভেতরে ৩x২ গ্রিডে সাজানো ছয়টি আয়তক্ষেত্রাকার বাক্স রয়েছে, প্রতিটি নোডের একটি কম্পোনেন্ট নির্দেশ করে। উপরের সারিতে বাম দিকে ‘Client API’ (যা ক্লায়েন্ট রিকোয়েস্ট হ্যান্ডেল করে) এবং ডান দিকে ‘Failure detection’ (যা সিস্টেমের স্বাস্থ্য পর্যবেক্ষণের জন্য দায়ী) রয়েছে। দ্বিতীয় সারিতে বাম দিকে ‘Conflict resolution’ (যা ডেটা ইনকনসিস্টেন্সি পরিচালনা করে) এবং ডান দিকে ‘Failure repair mecha…’ (যা ফেইলিওর থেকে পুনরুদ্ধারের জন্য একটি মেকানিজম নির্দেশ করে, পূর্ণ টেক্সটটি কেটে ফেলা হয়েছে) দেখানো হয়েছে। তৃতীয় সারিতে বাম দিকে ‘Replication’ (যা রিডান্ডেন্সির জন্য ডেটা রেপ্লিকেশন নির্দেশ করে) এবং ডান দিকে ‘Storage engine’ (যা স্থায়ী ডেটা স্টোরেজের জন্য দায়ী) প্রদর্শিত হয়। নিচের সারিতে নোডের ভেতরে অতিরিক্ত অনির্দিষ্ট কম্পোনেন্ট নির্দেশ করে ’…’ সহ দুটি খালি বাক্স রয়েছে। বাক্সগুলোর মধ্যে কোনো স্পষ্ট সংযোগ আঁকা হয়নি, যা নোডের মধ্যে এই কম্পোনেন্টগুলোর মধ্যে অভ্যন্তরীণ যোগাযোগ এবং ডেটা প্রবাহ নির্দেশ করে।] চিত্র ১৮
রাইট পাথ
চিত্র ১৯ ব্যাখ্যা করে একটি নির্দিষ্ট নোডে একটি রাইট রিকোয়েস্ট নির্দেশিত হওয়ার পরে কী ঘটে। অনুগ্রহ করে মনে রাখবেন রাইট/রিড পাথের জন্য প্রস্তাবিত ডিজাইনগুলো প্রধানত Cassandra [8]-এর আর্কিটেকচারের ওপর ভিত্তি করে।
[চিত্র ১৯-এর বর্ণনা: ছবিটি একটি ডাটাবেস সিস্টেমে একটি রাইট অপারেশনের একটি সরলীকৃত আর্কিটেকচার ডায়াগ্রাম উপস্থাপন করে। একজন Client একটি Server-এ একটি Write রিকোয়েস্ট পাঠায়। সার্ভার প্রথমে ডেটা একটি সবুজ Memory cache-এ লেখে (লেবেল ‘2’)। একই সময়ে, সার্ভার MEMORY বিভাগের মধ্যে DISK-এ অবস্থিত একটি নীল Commit log-এও ডেটা লেখে (লেবেল ‘1’)। মেমরি ক্যাশে ডেটা লেখার পরে, একটি Flush অপারেশন (লেবেল ‘3’) Memory cache থেকে ডেটা হালকা নীল SSTables (Sorted String Tables)-এর একটি সংগ্রহে সরিয়ে নেয়, যা DISK-এও অবস্থিত। ডায়াগ্রামটি ক্লায়েন্ট থেকে ডেটার প্রবাহ চিত্রিত করে, সার্ভারের মেমরি ক্যাশ এবং কমিট লগের মাধ্যমে, শেষ পর্যন্ত ডিস্কে SSTables-এ স্থায়ীভাবে সংরক্ষণ করে, ডেটা ডিউরেবিলিটি নিশ্চিত করে। সংখ্যাগুলো (1, 2, 3) সম্ভবত প্রক্রিয়ার ক্রমিক ধাপ নির্দেশ করে।]
চিত্র ১৯
১. রাইট রিকোয়েস্টটি একটি কমিট লগ ফাইলে স্থায়ীভাবে সংরক্ষণ (persist) করা হয়। ২. ডেটা মেমরি ক্যাশে সংরক্ষণ করা হয়। ৩. যখন মেমরি ক্যাশ পূর্ণ হয় বা একটি পূর্বনির্ধারিত থ্রেশহোল্ডে পৌঁছায়, তখন ডেটা ডিস্কে SSTable [9]-এ ফ্লাশ করা হয়। নোট: একটি সর্টেড-স্ট্রিং টেবিল (SSTable) হলো <key, value> পেয়ারগুলোর একটি সর্টেড লিস্ট। SStable সম্পর্কে আরও জানতে আগ্রহী পাঠকরা রেফারেন্স ম্যাটেরিয়াল [9] দেখতে পারেন।
রিড পাথ
একটি রিড রিকোয়েস্ট একটি নির্দিষ্ট নোডে নির্দেশিত হওয়ার পরে, এটি প্রথমে পরীক্ষা করে ডেটা মেমরি ক্যাশে আছে কিনা। যদি থাকে, তবে ডেটাটি ক্লায়েন্টে ফেরত দেওয়া হয় যেমনটি চিত্র ২০-এ দেখানো হয়েছে।
[চিত্র ২০-এর বর্ণনা: ছবিটি একটি রিড অপারেশন চিত্রিত করে এমন একটি সিস্টেম আর্কিটেকচার ডায়াগ্রাম উপস্থাপন করে। ‘Client’ লেবেলযুক্ত একটি হালকা নীল আয়তক্ষেত্র একটি ‘Read request’ শুরু করে যা ‘Server’ লেবেলযুক্ত একটি হালকা ধূসর আয়তক্ষেত্রে ভ্রমণ করে। সার্ভারের মধ্যে, একটি নম্বরযুক্ত বৃত্ত ‘1’ একটি প্রসেসিং ধাপ নির্দেশ করে। রিকোয়েস্টটি ‘Memory cache’ লেবেলযুক্ত একটি গাঢ় সবুজ আয়তক্ষেত্রে অগ্রসর হয়। যদি ক্যাশে ডেটা পাওয়া যায়, তবে ক্লায়েন্টে ‘Return result’ ফেরত পাঠানোর জন্য একটি ড্যাশ করা রেখা নির্দেশ করে। সার্ভারের নিচে, ‘DISK’ লেবেলযুক্ত একটি ফ্যাকাশে হলুদ বিভাগ স্থায়ী স্টোরেজ দেখায়। এই বিভাগটিতে ‘Result data’ লেবেলযুক্ত একটি হালকা নীল আয়তক্ষেত্র, ‘SSTables’ লেবেলযুক্ত একটি বড় হালকা নীল আয়তক্ষেত্রের মধ্যে গ্রুপ করা ছয়টি ছোট হালকা নীল বর্গের একটি গ্রুপ, এবং ‘Bloom filter’ লেবেলযুক্ত একটি হালকা নীল আয়তক্ষেত্র রয়েছে। ‘SSTables’ এবং ‘Bloom filter’ সম্ভবত ডিস্কে দক্ষ ডেটা লুকআপের জন্য ব্যবহৃত হয়। সামগ্রিক ডায়াগ্রামটি দ্রুত অ্যাক্সেসের জন্য একটি মেমরি ক্যাশ এবং বড় ডেটাসেটের জন্য ডিস্কে স্থায়ী স্টোরেজ সহ একটি টিয়ার্ড আর্কিটেকচার চিত্রিত করে, SSTables অ্যাক্সেস করার আগে দক্ষ ডেটা অস্তিত্ব চেকের জন্য একটি ব্লুম ফিল্টার ব্যবহার করে।] চিত্র ২০
যদি ডেটা মেমরিতে না থাকে, তবে এটি পরিবর্তে ডিস্ক থেকে পুনরুদ্ধার করা হবে। কোন SSTable-এ কী রয়েছে তা খুঁজে বের করার জন্য আমাদের একটি দক্ষ পদ্ধতি প্রয়োজন। ব্লুম ফিল্টার (Bloom filter) [10] সাধারণত এই সমস্যা সমাধান করতে ব্যবহৃত হয়।
যখন ডেটা মেমরিতে থাকে না তখন রিড পাথ চিত্র ২১-এ দেখানো হয়েছে।
[চিত্র ২১-এর বর্ণনা: ছবিটি একটি ডাটাবেস সিস্টেমে একটি রিড অপারেশন চিত্রিত করে এমন একটি সিস্টেম আর্কিটেকচার ডায়াগ্রাম উপস্থাপন করে। একজন ক্লায়েন্ট একটি সার্ভারে একটি ‘Read request’ (1) শুরু করে। সার্ভার প্রথমে একটি সবুজ ‘Memory cache’ (1) পরীক্ষা করে। যদি ডেটা উপস্থিত থাকে, তবে এটি সরাসরি ক্লায়েন্টে ফেরত দেওয়া হয় (5)। যদি না থাকে, তবে সার্ভার ‘DISK’ (2) লেবেলযুক্ত ডিস্ক স্তরে অগ্রসর হয়। এখানে, অন্তর্নিহিত স্টোরেজে অনুরোধ করা ডেটা বিদ্যমান আছে কিনা তা দ্রুত পরীক্ষা করতে একটি ‘Bloom filter’ (3) পরামর্শ করা হয়। যদি ব্লুম ফিল্টার ডেটার উপস্থিতি নির্দেশ করে, তবে সিস্টেম ‘SSTables’ (4) অ্যাক্সেস করে, যা ডেটা সেগমেন্টের সংগ্রহ হিসাবে চিত্রিত হালকা নীল ব্লক দ্বারা উপস্থাপিত। পুনরুদ্ধার করা ‘Result data’ (4) তারপর সার্ভারের মাধ্যমে ক্লায়েন্টে (5) ফেরত পাঠানো হয়। পুরো প্রক্রিয়াটি রিকোয়েস্ট এবং রেসপন্সের প্রবাহ দেখাতে ক্রমিকভাবে (1-5) নম্বরযুক্ত। ডায়াগ্রামটি স্পষ্টভাবে মেমরি এবং ডিস্ক স্তরগুলোকে পৃথক করে, ক্যাশিং মেকানিজম এবং দক্ষ ডেটা লুকআপের জন্য একটি ব্লুম ফিল্টারের ব্যবহার হাইলাইট করে।] চিত্র ২১
১. সিস্টেম প্রথমে পরীক্ষা করে ডেটা মেমরিতে আছে কিনা। যদি না থাকে, তবে ধাপ ২-এ যান। ২. যদি ডেটা মেমরিতে না থাকে, তবে সিস্টেম ব্লুম ফিল্টার পরীক্ষা করে। ৩. ব্লুম ফিল্টার কোন SSTable-গুলোতে কী থাকতে পারে তা বের করতে ব্যবহৃত হয়। ৪. SSTables ডেটা সেটের ফলাফল রিটার্ন করে। ৫. ডেটা সেটের ফলাফল ক্লায়েন্টে ফেরত দেওয়া হয়।
সারাংশ
এই অধ্যায়টি অনেকগুলো ধারণা এবং কৌশল কভার করে। আপনার স্মৃতি ঝালাই করতে, নিচের টেবিলটি একটি ডিস্ট্রিবিউটেড কী-ভ্যালু স্টোরের জন্য ব্যবহৃত বৈশিষ্ট্য এবং সংশ্লিষ্ট কৌশলগুলো সংক্ষেপে উপস্থাপন করে।
| লক্ষ্য/সমস্যা | কৌশল |
|---|---|
| বড় ডেটা সংরক্ষণ করার ক্ষমতা | সার্ভার জুড়ে লোড ছড়াতে কনসিস্টেন্ট হ্যাশিং ব্যবহার করুন |
| উচ্চ প্রাপ্যতা রিড | ডেটা রেপ্লিকেশন, মাল্টি-ডেটা সেন্টার সেটআপ |
| অত্যন্ত প্রাপ্য রাইট | ভেক্টর ক্লক সহ ভার্সনিং এবং দ্বন্দ্ব সমাধান |
| ডেটাসেট পার্টিশন | কনসিস্টেন্ট হ্যাশিং |
| ইনক্রিমেন্টাল স্কেলেবিলিটি | কনসিস্টেন্ট হ্যাশিং |
| হেটারোজিনিটি | কনসিস্টেন্ট হ্যাশিং |
| টিউনেবল কনসিস্টেন্সি | কোরাম কনসেনসাস |
| অস্থায়ী ফেইলিওর হ্যান্ডলিং | স্লপি কোরাম এবং হিন্টেড হ্যান্ডঅফ |
| স্থায়ী ফেইলিওর হ্যান্ডলিং | মার্কল ট্রি |
| ডেটা সেন্টার আউটেজ হ্যান্ডলিং | ক্রস-ডেটা সেন্টার রেপ্লিকেশন |
টেবিল ২