সেশন ১৬

Consensus (Raft, Paxos) - কয়েকটা server যেভাবে একমত হয়

এই সেশনের লক্ষ্য: Crash, ধীর network আর আলাদা ঘড়ির মধ্যেও কয়েকটা server কীভাবে একটা সত্যে একমত হয়, সেটা বোঝা। Majority quorum, Raft এর term, leader election, log replication আর commit ধাপে ধাপে দেখা, আর কেন committed data কখনো হারায় না আর split brain হয় না। শেষে Paxos এর সাথে পরিচয়, আর etcd, ZooKeeper, Consul, Kafka KRaft এ consensus এর জায়গাটা চেনা।

০০ যে প্রশ্নগুলোর উত্তর খুঁজবো

আগের সেশনগুলোতে একটা প্রশ্ন আমরা বারবার পাশ কাটিয়ে গেছি। সেশন ০৩ এ primary down হলে replica কে promote করার কথা বলেছিলাম, কিন্তু কে নিশ্চিত হয়ে বলবে যে primary সত্যিই down? সেশন ১৫ এ quorum দেখেছি, কিন্তু node গুলো আসলে কীভাবে একমত হয়, সেটা দেখিনি।

এই সেশনে সেই প্রশ্নের উত্তর খুঁজবো। একটা রাতের একটা ঘটনা ধরে ধরে আমরা Raft শিখবো, তারপর তার বড় ভাই Paxos এর সাথে পরিচয় হবে। শেষে আপনি বুঝবেন, Kubernetes বা Kafka এর মতো system এর একদম ভেতরে কোন নিয়মটা চুপচাপ সব ঠিক রাখে।

  • ১ তিনটা server কে একটা সত্যে একমত করানো এত কঠিন কেন? (consensus)
  • ২ সবার না, শুধু majority quorum এর সম্মতি কেন যথেষ্ট?
  • ৩ Raft এ leader, follower, candidate আর term কী?
  • ৪ Leader down হলে randomized timeout দিয়ে leader election কীভাবে হয়?
  • ৫ একটা write কীভাবে সবার কাছে পৌঁছায়? (log replication, commit index)
  • ৬ Leader বদলালেও committed entry কেন হারায় না?
  • ৭ Network partition এ split brain কীভাবে আটকায়?
  • ৮ Cluster এ ৩ বা ৫টা node কেন, ২ বা ৪টা নয়?
  • ৯ Paxos কী, আর etcd, ZooKeeper, Consul, Kafka KRaft এ consensus কোথায় চলে?

০১ তিনটা server কে একটা সত্যে একমত করানো এত কঠিন কেন?

রাত তিনটা বারো। ফারহানা একটা food delivery কোম্পানির backend engineer, আর আজ রাতে on-call এ শুধু সে-ই জেগে আছে। হঠাৎ phone এ alert বেজে উঠলো: cfg-1 unreachable। ফারহানার বুক ধক করে উঠলো, কারণ cfg-1 ছিলো config cluster এর leader। Dashboard খুলে সে দেখলো, প্রায় ৩০০ ms এর মধ্যেই cfg-3 নতুন leader হয়ে গেছে, আর একটা order ও আটকায়নি। স্বস্তি নিয়ে চা বানাতে উঠলো সে। কিন্তু মাথায় একটা প্রশ্ন ঘুরতেই থাকলো: কেউ তো ভোট গুনতে বসেনি, তিনটা machine নিজেরা নিজেরা একমত হলো কীভাবে?

Config cluster টা কী রাখে

এই cluster এ তিনটা server: cfg-1, cfg-2 আর cfg-3। এরা কোম্পানির ছোট কিন্তু খুব জরুরি কিছু তথ্য রাখে। যেমন এখন কোন database primary (db_primary), কোন payment gateway চালু, কোন offer চালু (promo_on)। ঢাকার order সামলানো প্রায় ২০০টা app server প্রতি কয়েক সেকেন্ডে এখান থেকে এসব settings পড়ে।

APP SERVERS settings পড়ে App 1 App 2 App 3 ... App 200 config cluster (Raft) cfg-1 LEADER · term 7 db_primary = db-b cfg-2 FOLLOWER · term 7 db_primary = db-b cfg-3 FOLLOWER · term 7 db_primary = db-b 3:12:04 এ cfg-1 এর network fail; নতুন leader লাগবে
ফারহানার config cluster: তিনটা server এ একই settings রাখা, যেমন এখন কোন database primary। ২০০টা app server এখান থেকে settings পড়ে। রাত ৩:১২ তে leader cfg-1 এর network fail করলো।

Server একটা রাখলে সেটা হতো SPOF, মানে single point of failure (সেশন ০১)। ওটা down হলে ২০০টা app server এর কেউই জানতো না কোন database এ লিখতে হবে। তাই কপি তিনটা। কিন্তু তিনটা কপি রাখলেই নতুন একটা দায়িত্ব আসে: তিনজনকে সবসময় একই কথা বলতে হবে।

ধরুন cfg-1 বলছে db_primary হলো db-a, আর cfg-2 বলছে db-b। তখন অর্ধেক app server এক database এ লিখবে, বাকি অর্ধেক আরেকটায়। দুই database এর data আলাদা হয়ে যাবে। এটাই সেশন ০৩ এর split brain, শুধু অন্য চেহারায়।

কয়েকটা server মিলে একটা মান নিয়ে একমত হওয়ার এই কাজটার নাম consensus। আরেকটু ঠিক করে বললে, consensus মানে কয়েকটা server একটা মান (বা একটার পর একটা মানের list) নিয়ে এমনভাবে একমত হয়, যাতে কিছু server crash করলে বা network গোলমাল করলেও একবার নেওয়া সিদ্ধান্ত আর কখনো বদলায় না।

একমত হওয়া কেন কঠিন

চায়ের দোকানে বসে তিন বন্ধু পিকনিকের জায়গা ঠিক করলে কাজটা সহজ। সবাই সামনাসামনি, কথা সাথে সাথে পৌঁছায়। এবার ভাবুন, তিন বন্ধু তিন শহরে, আর কথা হচ্ছে শুধু SMS এ। কোনো SMS দেরিতে আসে, কোনোটা আসেই না, আর কারো phone হঠাৎ বন্ধ হয়ে যায়। Server দের অবস্থা ঠিক এমন। তিনটা সমস্যা একসাথে চলে:

  1. Crash: একটা server কাজের মাঝখানে থেমে যেতে পারে। হয়তো একজনকে খবরটা দিয়েছে, আরেকজনকে দেওয়ার আগেই বন্ধ হয়ে গেছে।
  2. Delay: Network এ message দেরিতে আসে, উল্টো ক্রমে আসে, বা হারিয়ে যায়। একই data center এর ভেতরে যে message সাধারণত ১ ms এ পৌঁছায়, কখনো কখনো সেটাতেই ২ সেকেন্ড লেগে যায়।
  3. Shared clock নেই: প্রতিটা machine এর ঘড়ি একটু একটু আলাদা চলে। তাই কার write আগে হয়েছে, সেটা timestamp দেখে নিশ্চিত বলা যায় না।

সবচেয়ে কঠিন কথাটা হলো, বাইরে থেকে একটা crash করা server আর একটা ধীর server দেখতে হুবহু এক।

CRASH SLOW NETWORK কিছু নেই cfg-1 crash করেছে cfg-2 অপেক্ষা করছে 300 ms: কোনো heartbeat আসেনি 2 s দেরি cfg-1 চালু, কিন্তু ধীর cfg-2 অপেক্ষা করছে 300 ms: কোনো heartbeat আসেনি cfg-2 এর চোখে দুইটা হুবহু এক: crash না slow, বোঝা যায় না
বাঁ দিকে cfg-1 সত্যিই crash করেছে। ডান দিকে cfg-1 চালু আছে, কিন্তু তার message network এ আটকে আছে। cfg-2 দুই ক্ষেত্রেই একই জিনিস দেখে: নির্দিষ্ট সময়ের মধ্যে কোনো উত্তর আসেনি। এই অনিশ্চয়তাই consensus কে কঠিন করে।
Consensus এর আসল প্রতিশ্রুতি

Consensus algorithm সিদ্ধান্ত দ্রুত হওয়ার নিশ্চয়তা দেয় না। সে নিশ্চয়তা দেয় অন্য একটা জিনিসের: দুইটা আলাদা সিদ্ধান্ত কখনো হবে না। Network খারাপ থাকলে সিদ্ধান্ত আসতে দেরি হতে পারে, কিন্তু ভুল সিদ্ধান্ত কখনো আসবে না।

০২ সবার না, শুধু majority quorum এর সম্মতি কেন যথেষ্ট?

সেশন ১৫ এ quorum দেখেছেন: একটা কাজ সফল ধরার জন্য কমপক্ষে কয়টা node এর সম্মতি লাগে, সেই সংখ্যা। Consensus এ এই সংখ্যাটা সবসময় majority, মানে মোট node এর অর্ধেকের চেয়ে বেশি। একে বলে majority quorum। ৩টা node এ majority হলো ২, আর ৫টা node এ ৩।

প্রশ্ন আসে, সবার সম্মতি নিলেই তো সবচেয়ে নিরাপদ। নিরাপদ ঠিকই, কিন্তু অচল। তিনটার একটা down থাকলে “সবার সম্মতি” আর কখনো পাওয়া যাবে না, আর cluster একটা write ও নিতে পারবে না। Majority লাগলে একটা server down থাকলেও বাকি দুইটা দিয়ে কাজ চলে।

উল্টো দিকে, একজনের সম্মতি কেন যথেষ্ট নয়? কারণ তখন দুইটা server দুইটা আলাদা সিদ্ধান্ত নিয়ে ফেলতে পারে, আর কেউ কারো খবর জানবে না। Majority এর আসল গুণ অন্য জায়গায়:

যেকোনো দুইটা majority তে অন্তত একটা node common থাকে।

ক্লাসের ৪০ জনের মধ্যে ২১ জন বললো, “পিকনিক কক্সবাজারে।” এখন আরেকটা আলাদা ২১ জনের দল কখনো “সিলেটে” বলে সিদ্ধান্ত পাস করাতে পারবে না। কারণ দুই দল মিলে ৪২ জন লাগে, অথচ ক্লাসে আছে ৪০ জন। অন্তত দুইজন দুই দলেই আছে, আর তারা আগের সিদ্ধান্তের কথা জানে।

দল ১ (majority): A, B, C A #41 আছে B #41 আছে C #41 আছে D #41 নেই E #41 নেই দল ২ (majority): C, D, E C দুই দলেই আছে, তাই দল ২ ও #41 এর খবর পায়
৫টা node এ majority মানে ৩টা। দল ১ আর দল ২ যেভাবেই বানান, দুই দল মিলে ৬টা জায়গা, অথচ node মাত্র ৫টা। তাই অন্তত একটা node (এখানে C) দুই দলেই থাকে। দল ১ যে entry লিখেছে, দল ২ এর সিদ্ধান্তের সময় C সেটা মনে রাখে।

ফারহানার cluster এ এর মানে কী? db_primary বদলানোর লেখাটা ছিলো log এর #41 নম্বর entry (log কী, সেটা ০৫ নম্বর সেকশনে দেখবো)। #41 একবার majority তে পৌঁছালে, পরের যেকোনো majority তে অন্তত একজন থাকবে যার কাছে #41 আছে। Cluster এর স্মৃতি এভাবেই টিকে থাকে। পরের সেকশনগুলোতে এই একটা সত্য বারবার কাজে লাগবে।

এক লাইনে majority

Majority এমন একটা সংখ্যা, যার দুইটা আলাদা দল একসাথে বানানো যায় না। তাই একটা majority যে সিদ্ধান্ত নিয়েছে, তার উল্টো সিদ্ধান্ত আরেকটা majority কখনো নিতে পারে না।

০৩ Raft এ leader, follower, candidate আর term কী?

Consensus এর সবচেয়ে জনপ্রিয় algorithm এখন Raft। ২০১৪ সালে Stanford এর Diego Ongaro আর John Ousterhout এটা প্রকাশ করেন। তাঁদের মূল লক্ষ্য ছিলো এমন একটা algorithm বানানো, যেটা সাধারণ engineer রা পড়ে বুঝতে পারে। Raft এর মূল idea সহজ। একসময়ে cluster এ একজনই leader থাকে। সব write leader এর কাছে যায়, আর leader সেটা বাকিদের কাছে copy করে।

Raft এ প্রতিটা server তিনটা role এর যেকোনো একটায় থাকে:

শুরুতে সবাই FOLLOWER শোনে, vote দেয় CANDIDATE vote চায় LEADER write নেয়, heartbeat দেয় 1 2 3 4 5 1 2 3 4 5 Follower: election timeout পর্যন্ত heartbeat আসেনি, তাই candidate হলো Candidate: majority vote পেলো, তাই leader হলো Candidate: অন্য কেউ leader হয়েছে বা বড় term দেখলো, তাই follower হলো Leader: নিজের চেয়ে বড় term দেখলো, তাই চুপচাপ follower হলো Candidate: কেউ majority পায়নি (split vote), তাই নতুন term এ আবার চেষ্টা
প্রতিটা Raft server সবসময় তিনটা role এর একটায় থাকে। শুরুতে সবাই follower। Heartbeat না পেলে follower candidate হয়, আর majority vote পেলে leader হয়। কেউ নিজের চেয়ে বড় term দেখলে, সে যে role এই থাকুক, follower হয়ে যায়।

Term: Raft এর নিজের ঘড়ি

০১ নম্বর সেকশনে দেখেছি, machine গুলোর মধ্যে shared clock নেই। Raft এই সমস্যা এড়ায় একটা সাধারণ সংখ্যা দিয়ে, যার নাম term। Term হলো election এর ক্রমিক নম্বর। প্রতিটা নতুন election এ term এক করে বাড়ে, আর এক term এ বড়জোর একজন leader থাকে। ফারহানার রাতে cfg-1 ছিলো term 7 এর leader। Election এর পর cfg-3 হলো term 8 এর leader।

Term এর নিয়ম তিনটা, আর তিনটাই সহজ:

  1. প্রতিটা message এর সাথে পাঠানো server নিজের term লিখে দেয়।
  2. কেউ নিজের চেয়ে বড় term দেখলে সাথে সাথে নিজের term আপডেট করে, আর follower হয়ে যায়। সে leader হলেও।
  3. নিজের চেয়ে ছোট term এর message এলে সেটা বাতিল করে দেয়, কারণ ওটা পুরোনো সময়ের খবর।
Term কেন এত কাজের

ঘড়ির সময় machine ভেদে আলাদা হতে পারে, কিন্তু term নম্বর সবাই একইভাবে তুলনা করতে পারে। ৭ সবসময় ৮ এর চেয়ে পুরোনো। তাই কোনো পুরোনো leader অনেকক্ষণ পর ফিরে এসে term 7 এর message পাঠালে, term 8 এ থাকা সবাই বুঝে যায় যে এটা বাসি খবর।

০৪ Leader down হলে randomized timeout দিয়ে leader election কীভাবে হয়?

Leader প্রতি ৫০ ms এ heartbeat পাঠায়। প্রতিটা follower এর একটা election timeout থাকে: এই সময়ের মধ্যে heartbeat না এলে সে ধরে নেয় leader নেই। এই timeout টা fixed নয়। প্রতিবার ১৫০ থেকে ৩০০ ms এর মধ্যে random একটা মান বেছে নেওয়া হয়। একে বলে randomized timeout। কেন random, সেটা একটু পরেই দেখবো। আগে ফারহানার রাতটা ধাপে ধাপে দেখি। নতুন leader বেছে নেওয়ার এই পুরো কাজটার নাম leader election।

cfg-1 leader · term 7 cfg-2 follower · term 7 cfg-3 follower · term 7 0 ms 286 ms 287 ms 288 ms ~290 ms network fail timer: 298 ms timer: 286 ms CANDIDATE term 8, নিজেকে vote RequestVote (term 8) vote: হ্যাঁ বিচ্ছিন্ন, কিছুই জানে না নিজেকে leader ভাবে LEADER · term 8 3 এর মধ্যে 2 vote heartbeat (term 8) cfg-2 এর timer reset
সময় উপর থেকে নিচে চলে। cfg-3 এর random timer (286 ms) cfg-2 এর (298 ms) আগে শেষ হয়। সে term 8 এ candidate হয়ে vote চায়, cfg-2 এর vote পেয়ে majority পায়, আর heartbeat পাঠিয়ে cfg-2 এর timer reset করে দেয়। RequestVote cfg-1 এর কাছেও যায়, কিন্তু পৌঁছায় না।
  1. ০ ms: cfg-1 এর network card fail করলো। শেষ heartbeat এর পর আর কিছু আসছে না।
  2. অপেক্ষা: cfg-2 এর random timer ২৯৮ ms, আর cfg-3 এর ২৮৬ ms। দুজনেই চুপচাপ অপেক্ষা করছে।
  3. ২৮৬ ms: cfg-3 এর timer আগে শেষ হলো। সে term 7 থেকে term 8 এ গেলো, candidate হলো, নিজেকে একটা vote দিলো। তারপর cfg-1 আর cfg-2 কে RequestVote message পাঠালো, মানে “আমাকে vote দিন” অনুরোধ।
  4. ২৮৭ ms: cfg-2 এখনো term 8 এ কাউকে vote দেয়নি। সে cfg-3 কে vote দিলো, আর নিজের timer আবার শুরু থেকে চালু করলো।
  5. ২৮৮ ms: cfg-3 এর হাতে এখন ৩টার মধ্যে ২টা vote, মানে majority। সে term 8 এর leader।
  6. প্রায় ২৯০ ms: নতুন leader সাথে সাথে heartbeat পাঠালো। cfg-2 এর timer reset হলো, তাই সে আর candidate হলো না।

ফারহানার dashboard এ যে ৩০০ ms দেখাচ্ছিলো, তার প্রায় পুরোটাই ছিলো অপেক্ষা: leader সত্যিই নেই কিনা, সেটা নিশ্চিত হওয়ার সময়। আসল ভোটাভুটিতে লেগেছে মাত্র ২ ms।

একটা server এক term এ মাত্র একবার vote দেয়, আর vote টা disk এ লিখে রাখে। তাই restart করেও একই term এ দ্বিতীয়বার vote দিতে পারে না। এক term এ দুইজন majority পাবে না, এই নিশ্চয়তা এখান থেকেই আসে।

Timeout random কেন

ধরুন দুজনের timer ই ঠিক ২০০ ms। তখন cfg-2 আর cfg-3 একসাথে candidate হবে। দুজনেই নিজেকে vote দেবে, আর একে অপরকে vote দেবে না, কারণ এই term এর vote তো দেওয়া হয়ে গেছে। দুজনের হাতে ১টা করে vote, majority কারো নেই। একে বলে split vote। Timer আবার একসাথে শেষ হলে একই ঘটনা চলতেই থাকবে।

Random timer এই অচলাবস্থা ভাঙে। একই data center এ একটা message যেতে আর ফিরতে ১ ms এর মতো লাগে। দুইটা random timer এর ব্যবধান সাধারণত এর চেয়ে অনেক বেশি; ফারহানার রাতে সেটা ছিলো ১২ ms। তাই একজন প্রায় সবসময় আগে জাগে, আর অন্যজন জাগার আগেই vote চেয়ে জিতে যায়। তবু কখনো split vote হলে term আরো এক বাড়ে, সবাই নতুন random timer নেয়, আর এক দুই round এর মধ্যেই কেউ জিতে যায়।

heartbeat interval   = 50 ms
election timeout     = random(150, 300) ms    # প্রতিবার নতুন করে বাছা হয়
round trip           = ~1 ms                  # একই data center এর ভেতরে

ফারহানার রাত:
  cfg-2 timer = 298 ms
  cfg-3 timer = 286 ms    # আগে শেষ, ব্যবধান 12 ms
  ব্যবধান / round trip = 12 / 1 = 12 গুণ

etcd এর default: heartbeat 100 ms, election timeout 1000 ms
Timeout বেছে নেওয়ার হিসাব

Election timeout হতে হবে network round trip এর চেয়ে অনেক বড়, কিন্তু দুইটা server failure এর মাঝের গড় সময়ের চেয়ে অনেক ছোট। খুব ছোট হলে network একটু ধীর হলেই অকারণে election শুরু হবে। খুব বড় হলে leader down হওয়ার পর cluster অনেকক্ষণ কোনো write নিতে পারবে না।

০৫ একটা write কীভাবে সবার কাছে পৌঁছায়?

Leader বেছে নেওয়া গেলো। কিন্তু leader এর আসল কাজ হলো data নিরাপদে কয়েক জায়গায় রাখা। Raft প্রতিটা পরিবর্তনকে একটা log এ entry হিসেবে লেখে। Log হলো হিসাবের খাতার মতো: পুরোনো লাইন বদলায় না, নতুন লাইন শুধু শেষে যোগ হয়।

প্রতিটা entry তে তিনটা জিনিস থাকে: index (ক্রমিক নম্বর), term (কোন leader এর আমলে লেখা), আর command (যেমন SET db_primary = db-b)। সব server একই log একই ক্রমে apply করলে সবার data ও হুবহু এক হয়। এই log সবার কাছে হুবহু একরকম রাখার কাজটাকে বলে log replication।

উদাহরণ: #41 কীভাবে commit হলো

Network fail করার ছয় সেকেন্ড আগে, রাত ৩:১১:৫৮ এ, database টিমের একটা script SET db_primary = db-b পাঠিয়েছিলো। পুরোনো primary db-a এর disk ভরে আসছিলো, তাই এই বদল। তখনো cfg-1 leader। এই একটা write এর যাত্রা দেখুন:

Client DB টিমের script cfg-1 leader · term 7 cfg-2 follower cfg-3 follower ১. SET db_primary = db-b ২. log এ #41 লেখে এখনো commit নয় ৩. AppendEntries #41 AppendEntries #41 ৪. OK (~1 ms) GC pause, ধীর ৫. COMMIT 3 এর 2 এ আছে: majority ৬. success ৭. commit index = 41 commit index = 41
রাত ৩:১১:৫৮ এ #41 এর যাত্রা। Leader আগে নিজের log এ লেখে, তারপর দুই follower কে পাঠায়। cfg-2 OK দিতেই #41 এর কাছে ৩ এর মধ্যে ২টা copy, তাই এটা committed। তখনই client success পায়। পরের heartbeat এ follower রা commit index জেনে নিজেরাও #41 apply করে।
  1. Script টা leader cfg-1 এর কাছে command পাঠালো।
  2. cfg-1 সেটা নিজের log এ #41 হিসেবে disk এ লিখলো। কিন্তু এখনো apply করেনি, কারণ entry টা এখনো শুধু তার কাছেই আছে।
  3. cfg-1 একসাথে cfg-2 আর cfg-3 কে AppendEntries message এ #41 পাঠালো। এই message টাই leader এর “এই entry গুলো log এর শেষে যোগ করুন” অনুরোধ, আর খালি AppendEntries টাই heartbeat হিসেবে কাজ করে।
  4. cfg-2 নিজের disk এ লিখে ১ ms এর মধ্যে OK দিলো। cfg-3 তখন একটা GC pause এ আটকে ছিলো (Java এর garbage collector কিছু সময়ের জন্য পুরো program থামিয়ে মেমরি পরিষ্কার করে), তাই একটু পিছিয়ে পড়লো।
  5. এখন #41 আছে ৩টার মধ্যে ২টায়, মানে majority তে। cfg-1 #41 কে committed ধরলো, নিজের key-value store এ apply করলো, আর script কে success জানালো।
  6. পরের heartbeat এ leader জানিয়ে দিলো commit index = 41। Follower রাও তখন #41 apply করলো। cfg-3 কয়েক ms পরে ধরে ফেললো, কারণ পিছিয়ে থাকা follower কে leader বারবার পাঠাতেই থাকে।

Commit মানে: একটা entry majority তে পৌঁছে গেছে। এরপর সেটা আর কখনো হারাবে না, বদলাবেও না। Commit index হলো সবচেয়ে বড় committed entry র নম্বর। এই নম্বর পর্যন্ত সব entry নিশ্চিন্তে apply করা যায়।

commit index = 41 cfg-1 (leader) cfg-2 cfg-3 #38 term 7 #39 term 7 #40 term 7 #41 term 7 #42 term 7 #38 term 7 #39 term 7 #40 term 7 #41 term 7 #38 term 7 #39 term 7 #40 term 7 #41 term 7 committed: majority তে আছে, হারাবে না uncommitted #41 = SET db_primary = db-b (3:11:58, DB টিমের script) #42 = SET promo_on = true (3:12:03.990, marketing tool)
Network fail করার মুহূর্তে তিন server এর log। প্রতিটা ঘরে entry র index আর term। #41 পর্যন্ত সব entry majority তে আছে, তাই commit index 41। #42 শুধু leader এর নিজের log এ, কারো কাছে পৌঁছানোর আগেই network বন্ধ হয়ে গেছে।

উপরের ছবিটা রাত ৩:১২:০৪ এর, ঠিক যে মুহূর্তে network fail করলো। #41 তিনজনের কাছেই আছে, কারণ cfg-3 ততক্ষণে ধরে ফেলেছে। কিন্তু #42 শুধু cfg-1 এর কাছে। সেটার গল্প পরের সেকশনে।

একটা write এর খরচ

প্রতিটা write কে majority তে পৌঁছাতে হয়। প্রতিটা server কে disk এ পাকাপাকি লিখে (fsync করে) তবেই OK বলতে হয়। একই data center এ round trip ১ ms এর মতো, আর SSD তে fsync এ আরো কয়েক ms। তাই Raft এর একটা write সাধারণত কয়েক ms নেয়। Memory তে লেখা একটা Redis write এর তুলনায় এটা অনেক ধীর। এই বাড়তি সময়টুকুই নিরাপত্তার খরচ।

Commit কখন হয়

Leader এর log এ লেখা হলেই entry committed নয়। Majority র disk এ পৌঁছালে তবেই committed। Client success পায় ঠিক এর পরে, এক মুহূর্ত আগেও নয়।

০৬ Leader বদলালেও committed entry কেন হারায় না?

#42 এর কী হলো

রাত ৩:১২:০৩.৯৯০, network fail করার মাত্র ১০ ms আগে। Marketing টিমের একটা tool পাঠালো SET promo_on = true। cfg-1 সেটা নিজের log এ #42 হিসেবে লিখলো, তারপর AppendEntries পাঠাতে গেলো। কিন্তু তার আগেই network card বন্ধ হয়ে গেলো। #42 আছে ৩ জনের মধ্যে মাত্র ১ জনের কাছে, তাই সেটা committed নয়। Tool টা success পায়নি; কয়েক সেকেন্ড পর timeout পেলো।

নতুন leader cfg-3 এর log #41 এ শেষ। তার কাছে term 7 এর কোনো #42 নেই। Term 8 এ cfg-3 যে নতুন entry গুলো নেবে (যেমন SET surge_limit = 1.2), সেগুলো #42 নম্বর থেকেই বসবে।

রাত ৩:২০ এ data center এর লোকজন cfg-1 এর network card বদলে দিলেন। cfg-1 ফিরে এসে term 8 এর heartbeat পেলো। বড় term দেখে সে চুপচাপ follower হয়ে গেলো। তারপর leader তার log মিলিয়ে দেখলো।

cfg-1 (ফিরে এসে) cfg-3 (leader) cfg-1 (মেলানোর পর) #38 term 7 #39 term 7 #40 term 7 #41 term 7 #42 term 7 মিলছে না, মুছে যাবে #38 term 7 #39 term 7 #40 term 7 #41 term 7 #42 term 8 leader থেকে copy #38 term 7 #39 term 7 #40 term 7 #41 term 7 #42 term 8 #41 টিকে গেলো; term 7 এর #42 কখনো success পায়নি
রাত ৩:২০ এ cfg-1 ফিরে আসে। Leader cfg-3 এর সাথে মেলাতে গিয়ে দেখা যায়, #41 পর্যন্ত দুজনের log এক, কিন্তু #42 আলাদা (term 7 বনাম term 8)। cfg-1 নিজের পুরোনো #42 মুছে leader এর #42 বসিয়ে নেয়। Committed কিছুই হারায়নি।

মেলানোর নিয়মটা সহজ। Leader প্রতিটা AppendEntries এর সাথে ঠিক আগের entry র index আর term পাঠায়। Follower এর log এ ঐ জায়গায় একই term এর entry না থাকলে সে “না” বলে দেয়। Leader তখন এক ধাপ পিছিয়ে আবার চেষ্টা করে। এভাবে যেখান থেকে দুজনের log আলাদা হয়েছে, সেখানে পৌঁছে leader নিজের entry গুলো বসিয়ে দেয়। cfg-1 এর ক্ষেত্রে #41 পর্যন্ত মিললো, #42 মিললো না। তাই cfg-1 নিজের পুরোনো #42 মুছে leader এর #42 copy করে নিলো।

এটা কি data হারানো? না। #42 কখনো commit হয়নি, আর tool টা কখনো success পায়নি। Tool টা timeout পেয়ে আবার চেষ্টা করলে নতুন leader এর কাছে লেখা হবে। Raft এর প্রতিশ্রুতি হলো committed entry কখনো হারাবে না। Uncommitted entry হারাতে পারে, আর client সেটা জানে, কারণ সে success পায়নি।

পুরোনো log নিয়ে কেউ leader হতে পারে না কেন

একটা ভয় তবু থেকে যায়। এমন কেউ যদি leader হয়ে যায়, যার কাছে #41 নেই? তাহলে তো সে নিজের log সবার উপর বসিয়ে দেবে, আর committed #41 মুছে যাবে। Raft এটা আটকায় vote দেওয়ার একটা নিয়ম দিয়ে:

RequestVote আসে (term 8) সাথে candidate এর শেষ entry: index আর term cfg-2 নিজের log এর সাথে মেলায় candidate এর log কি আমার log এর মতো নতুন? হ্যাঁ না VOTE দেয় এক term এ শুধু একবার, vote টা disk এ লিখে রাখে VOTE দেয় না যেমন candidate এর শেষ #40, কিন্তু cfg-2 এর শেষ #41 "নতুন" log এর নিয়ম শেষ entry এর term বড় হলে নতুন; term সমান হলে যার index বড়, সে নতুন
প্রতিটা server vote দেওয়ার আগে candidate এর log দেখে নেয়। Candidate এর log নিজের log এর চেয়ে পুরোনো হলে সে vote দেয় না। তাই committed entry যার কাছে নেই, সে majority র vote জোগাড় করতে পারে না।

এখানে ০২ নম্বর সেকশনের সেই সত্যটা কাজে লাগে। #41 committed মানে সেটা majority র কাছে আছে। Leader হতে হলে candidate কে majority র vote পেতে হবে। দুইটা majority তে অন্তত একজন common, আর সেই common জন #41 ছাড়া কোনো candidate কে vote দেবে না। তাই যে জিতবে, তার কাছে #41 থাকবেই।

ফারহানার রাতে ব্যাপারটা কেমন হতো, একবার ভাবুন। ধরুন cfg-3 তখনো GC pause থেকে ধরে উঠতে পারেনি, তার শেষ entry #40। তাহলে cfg-2 তাকে vote দিতো না। মাত্র ১২ ms পরে cfg-2 এর নিজের timer শেষ হতো। সে term 9 এ candidate হতো, আর cfg-3 তাকে vote দিতো, কারণ cfg-2 এর log বেশি নতুন। Election এ কয়েক ms বেশি লাগতো, কিন্তু #41 হারাতো না।

Safety এর মূল কথা

Committed entry majority তে থাকে। নতুন leader হতে majority র vote লাগে। দুইটা majority অন্তত একটা node এ মেলে, আর সেই node পুরোনো log এর candidate কে vote দেয় না। এই তিনটা কথা মিলেই Raft এর সবচেয়ে বড় প্রতিশ্রুতি: committed data কখনো হারায় না।

০৭ Network partition এ split brain কীভাবে আটকায়?

সেশন ০৩ এ split brain দেখেছেন: একসাথে দুইটা primary, দুটোই write নিচ্ছে, আর দুই জায়গার data আলাদা হয়ে যাচ্ছে। Raft এটা কীভাবে আটকায়, সেটা ৫ node এর একটা cluster এ সবচেয়ে পরিষ্কার দেখা যায়।

ধরুন পরের বছর ফারহানার টিম cluster টা ৫ node এ বাড়ালো: cfg-1 থেকে cfg-5। একদিন একটা network switch খারাপ হয়ে network দুই ভাগ হয়ে গেলো। এক পাশে cfg-1 (তখনকার leader) আর cfg-2, অন্য পাশে cfg-3, cfg-4 আর cfg-5। Network এর এভাবে দুই ভাগ হয়ে যাওয়াকে বলে network partition, যেটা সেশন ১৫ এ দেখেছেন।

network partition MINORITY MAJORITY AppendEntries cfg-1 নিজেকে leader ভাবে (term 7) cfg-2 follower 5 এ 2: majority নেই commit হয় না, timeout cfg-3: LEADER term 8, 5 এর মধ্যে 3 vote cfg-4 follower · term 8 cfg-5 follower · term 8 5 এ 3: majority আছে write commit হয়, client success পায়
Network দুই ভাগ হলে দুই পাশেই একজন করে "leader" থাকতে পারে। কিন্তু commit করতে majority লাগে, আর ৫ node এর majority (৩টা) একসাথে শুধু এক পাশেই থাকতে পারে। তাই data শুধু বড় পাশে লেখা হয়, দুই ভাগ হয় না।

অর্থাৎ কিছুক্ষণের জন্য দুইজন নিজেকে leader ভাবছে ঠিকই, কিন্তু commit করতে পারছে শুধু একজন। ফলে data দুই ভাগ হয় না। Network ঠিক হলে cfg-1 term 8 দেখে follower হয়ে যায়, আর তার uncommitted entry গুলো আগের সেকশনের মতো মুছে যায়।

একটা সূক্ষ্ম ফাঁক তবু থাকে: read। পুরোনো leader cfg-1 এর কাছে কেউ db_primary পড়তে চাইলে সে নিজের পুরোনো মান দিয়ে দিতে পারে। তাই etcd এর মতো system read এর উত্তর দেওয়ার আগে leader একবার heartbeat পাঠিয়ে নিশ্চিত হয় যে majority এখনো তাকে leader মানে। এতে read একটু ধীর হয়, কিন্তু বাসি উত্তর আসে না।

সেশন ০৩ এর failover এর সাথে পার্থক্য

সেশন ০৩ এ primary down কিনা, সেটা একটা monitor একা ঠিক করতো। Monitor ভুল করলে split brain হতো। Raft এ কেউ একা সিদ্ধান্ত নেয় না। Majority ছাড়া কেউ leader হতে পারে না, write ও commit করতে পারে না। আর একটা majority একসাথে দুই পাশে থাকতে পারে না।

০৮ Cluster এ ৩ বা ৫টা node কেন, ২ বা ৪টা নয়?

উত্তরটা majority quorum এর হিসাব থেকেই আসে। N টা node এর cluster এ majority কত, আর cluster একসাথে কয়টা node হারিয়েও চলতে পারে, সেটা নিচের দুইটা সূত্রে:

majority(N) = floor(N / 2) + 1
tolerate(N) = N - majority(N)          # কয়টা node একসাথে fail করলেও চলে

N = 5:  majority = floor(2.5) + 1 = 3
        tolerate = 5 - 3 = 2
N = 4:  majority = 2 + 1 = 3
        tolerate = 4 - 3 = 1           # N = 3 এর সমান, কিন্তু machine একটা বেশি
মোট nodeMajorityকয়টা fail সহ্য করে
১১০
২২০
৩২১
৪৩১
৫৩২
৬৪২
৭৪৩

টেবিল থেকে তিনটা কথা বেরিয়ে আসে:

  1. ২টা node একটার চেয়েও খারাপ: দুইটাই majority তে লাগে, তাই একটা down হলেই cluster থেমে যায়। অথচ machine লাগছে দ্বিগুণ।
  2. জোড় সংখ্যায় লাভ নেই: ৪টা node ও ৩টার মতো মাত্র ১টা failure সহ্য করে, কিন্তু একটা machine বেশি চালাতে হয়। তার উপর network ঠিক ২ আর ২ এ ভাগ হলে কোনো পাশেই majority থাকে না, আর পুরো cluster write নেওয়া বন্ধ করে দেয়।
  3. বেশি node মানে ধীর write: ৭টা node এ প্রতিটা write কে ৪টা OK এর জন্য অপেক্ষা করতে হয়, আর leader কে ৬ জনের কাছে copy পাঠাতে হয়।

তাই বাস্তবে প্রায় সবাই ৩ বা ৫ বেছে নেয়। ৩টা node একটা failure সহ্য করে, আর বেশিরভাগ ক্ষেত্রে এটুকুই যথেষ্ট। ৫টা node দুইটা failure সহ্য করে। ফলে একটা server এ maintenance চলার সময় আরেকটা হঠাৎ fail করলেও cluster চলতে থাকে।

Availability zone এ ছড়িয়ে রাখুন

Cloud এ availability zone হলো একই region এর ভেতরে আলাদা বিদ্যুৎ আর আলাদা network এর একটা data center। ৫টা node কে তিনটা zone এ ২, ২ আর ১ করে রাখুন। যেকোনো একটা zone পুরো বন্ধ হলেও বাকি দুই zone এ অন্তত ৩টা node থাকে, যা majority।

০৯ Paxos কী, আর etcd, ZooKeeper, Consul, Kafka KRaft এ consensus কোথায় চলে?

Paxos: Raft এর বড় ভাই

Raft আসার অনেক আগে, ১৯৮৯ সালে, Leslie Lamport Paxos লিখেছিলেন। Paper টা প্রকাশ হয় ১৯৯৮ সালে। সেটা লেখা ছিলো Paxos নামের এক কাল্পনিক গ্রিক দ্বীপের সংসদের গল্প হিসেবে, যেখানে সাংসদরা যখন খুশি সংসদে আসেন আর চলে যান। Algorithm টা নির্ভুল, কিন্তু বোঝা এত কঠিন যে ২০০১ সালে Lamport কে “Paxos Made Simple” নামে আরেকটা paper লিখতে হয়েছিলো। Raft এর জন্মই হয়েছিলো এই কঠিনতা কমানোর জন্য।

Basic Paxos একটা মাত্র মান নিয়ে একমত হয়, দুই ধাপে। এখানে role দুইটা: proposer মান প্রস্তাব করে, আর acceptor রা ভোট দেয়।

PHASE 1 PHASE 2 PROPOSER মান প্রস্তাব করে ACCEPTOR 1 ভোট দেয় ACCEPTOR 2 ভোট দেয় ACCEPTOR 3 offline prepare(n = 5) prepare(n = 5) promise: 5 এর ছোট আর না promise accept(5, db-b) accept(5, db-b) accepted accepted 3 এর মধ্যে 2 acceptor রাজি: db-b এখন chosen
প্রথম ধাপে proposer একটা proposal number (5) পাঠায়, আর acceptor রা কথা দেয় যে এর ছোট number আর মানবে না। দ্বিতীয় ধাপে আসল মান (db-b) পাঠানো হয়। Acceptor 3 offline থাকলেও ক্ষতি নেই, কারণ ৩টার মধ্যে ২টার রাজি হওয়াই majority।
  1. Prepare আর promise: Proposer একটা unique proposal number বেছে নেয় (এখানে 5), যেটা আগের সব number এর চেয়ে বড়। সে acceptor দের বলে prepare(5)। প্রতিটা acceptor কথা দেয়: এখন থেকে ৫ এর ছোট কোনো proposal সে আর মানবে না। আগে কোনো মান accept করে থাকলে সেটাও জানিয়ে দেয়।
  2. Accept আর accepted: Majority কথা দিলে proposer আসল মানটা পাঠায়: accept(5, db-b)। একটা কড়া নিয়ম আছে। কোনো acceptor আগে কোনো মান accept করে থাকলে, proposer কে নিজের মান বাদ দিয়ে সেই মানটাই পাঠাতে হয়। Acceptor রা এর মধ্যে বড় কোনো number কে কথা না দিয়ে থাকলে মানটা accept করে। Majority accept করলেই মানটা chosen, আর সেটা কখনো বদলাবে না।

চেনা চেনা লাগছে? Proposal number অনেকটা Raft এর term এর মতো, আর এখানেও সব সিদ্ধান্ত majority দিয়ে। একটার পর একটা মান নিয়ে, মানে পুরো একটা log নিয়ে একমত হতে Paxos কে বারবার চালাতে হয়। এই রূপটাকে বলে Multi-Paxos। সেখানে একজন স্থায়ী leader প্রথম ধাপটা বারবার না করে শুধু দ্বিতীয় ধাপ চালায়। তখন সেটা দেখতে অনেকটা Raft এর মতোই হয়ে যায়।

RaftPaxos
জন্ম২০১৪, Ongaro আর Ousterhout১৯৮৯ এ লেখা, ১৯৯৮ এ প্রকাশ, Lamport
মূল লক্ষ্যসহজে বোঝা আর বানানোগাণিতিকভাবে নির্ভুল হওয়া
Leaderশুরু থেকেই design এর অংশBasic Paxos এ নেই, Multi-Paxos এ যোগ হয়
পুরোনো নতুন চেনার উপায়termproposal number
কোথায় চলেetcd, Consul, Kafka KRaft, CockroachDBGoogle এর Chubby আর Spanner

Consensus কোথায় চলে

আপনি নিজে হয়তো কখনো Raft লিখবেন না। কিন্তু প্রায় প্রতিটা বড় system এর ভেতরে কোথাও না কোথাও এটা চলছে:

সবগুলোর pattern একই। একটা ছোট consensus cluster পুরো system এর “সত্য” টুকু রাখে: কে leader, কোন configuration চালু, কোন lock কার হাতে। বড় data, যেমন কোটি কোটি order, থাকে অন্য database এ।

APP SERVERS orders: অনেক write config পড়ে, কম write App 1 App 2 ... App 200 order database orders 50M row · 3,000 write/s config cluster (etcd, Raft) cfg-3 cfg-1 cfg-2 ~5 MB · মিনিটে ~10 write leader কে, db_primary, lock
বাস্তবের ভাগাভাগি: কোটি কোটি order আর হাজারো write থাকে সাধারণ database এ। কয়েক MB এর "সত্য" (কে leader, কোন database primary, কোন lock কার) থাকে ছোট consensus cluster এ, যেখানে প্রতিটা write majority র সম্মতি নিয়ে হয়।

Consensus যা দেয়

  • একটাই সত্য: সব server একই log একই ক্রমে apply করে, তাই সবার data এক।
  • নিজে থেকে failover: Leader down হলে কয়েকশো ms এর মধ্যে নতুন leader আসে, কাউকে জাগাতে হয় না।
  • Committed data হারায় না: Majority তে পৌঁছানো entry যেকোনো leader বদলের পরও টিকে থাকে।
  • Split brain নেই: Majority ছাড়া কেউ commit করতে পারে না, আর majority একসাথে দুই জায়গায় থাকে না।

Consensus এর downside

  • প্রতিটা write ধীর: Majority র কাছে round trip আর disk এ fsync শেষ না হলে success আসে না।
  • সব write এক leader দিয়ে: Write এর ক্ষমতা একটা machine এর ক্ষমতার বেশি হয় না।
  • Majority না থাকলে write বন্ধ: ৩ এর ২টা down হলে cluster write নেওয়া থামিয়ে দেয়। এটা সেশন ১৫ এর CP পছন্দ।
  • শুধু ছোট data এর জন্য: etcd এর default সীমা 2 GB। বড় data এখানে রাখার জিনিস নয়।
সবচেয়ে গুরুত্বপূর্ণ শিক্ষা

Consensus কয়েকটা server কে crash আর ধীর network এর মধ্যেও একটা সত্যে একমত রাখে। Raft এটা করে একজন leader, ক্রমে বাড়তে থাকা term, আর প্রতিটা সিদ্ধান্তে majority র সম্মতি দিয়ে। বিনিময়ে প্রতিটা write ধীর হয়, আর majority না থাকলে write বন্ধ থাকে।

তাই consensus এর জায়গা হলো ছোট কিন্তু জরুরি data: কে leader, কোন database primary, কোন lock কার। বড় data রাখার জন্য সাধারণ database ব্যবহার করুন, আর তার leader কে, সেটা consensus কে ঠিক করতে দিন।

১০ মগজে প্রেশার দিন

আগে নিজে ভাবুন। তারপর উত্তর খুলে দেখুন: বেশিরভাগ মানুষ কীভাবে ভাবে, সেই চিন্তায় কী বাদ পড়ে, আর আসল কথাটা কোথায়।

প্রশ্ন ১: একটা main আর একটা backup, এই দুইটা server দিয়েই তো failover হয়। Consensus এর জন্য ৩টা লাগবে কেন?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“Main down হলে backup সেটা টের পেয়ে নিজেই main হয়ে যাবে। দুইটা server ই যথেষ্ট, তৃতীয়টা শুধু বাড়তি খরচ।”

শুনতে যুক্তিসঙ্গত, কিন্তু একটা প্রশ্নের উত্তর এখানে নেই: backup কীভাবে বুঝবে main সত্যিই down?

যে জায়গাটা যোগ করা দরকার

দুইজনের মাঝের network কেটে গেলে backup এর চোখে main down, আর main এর চোখে backup down। Backup নিজেকে main ঘোষণা করলে দুইজনই write নেবে: split brain। আর backup অপেক্ষা করলে সত্যিকারের crash এ system থেমে থাকবে। দুইটা node এ majority হলো ২, তাই কোনো পাশই একা নিশ্চিত হতে পারে না।

তৃতীয় node টা ঠিক এই জট খোলে। Network ভাগ হলে যে পাশে ২টা node, শুধু সেই পাশ সিদ্ধান্ত নিতে পারে। তৃতীয়টা ছোট একটা machine হলেও চলে, অনেক system এ একে witness বা tiebreaker বলে।

মাথায় রাখুন

দুইটা node দিয়ে crash আর network partition আলাদা করা যায় না। নিরাপদ automatic failover এর জন্য কমপক্ষে ৩টা node লাগে, যাতে majority সিদ্ধান্ত নিতে পারে।

প্রশ্ন ২: Raft cluster এ write এর success পেলেন। এখন কি data তিনটা server এই আছে?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“হ্যাঁ। Leader সবাইকে copy করে, তারপর success দেয়। তাই যেকোনো server থেকে পড়লেই নতুন data পাবো।”

প্রথম অর্ধেক প্রায় ঠিক, কিন্তু উপসংহারটা বিপজ্জনক।

যে জায়গাটা যোগ করা দরকার

Success আসে majority তে পৌঁছানোর পর, সবার কাছে পৌঁছানোর পর নয়। ৩টা node এ ২টার কাছে data আছে, তৃতীয়টা হয়তো ফারহানার cfg-3 এর মতো GC pause এ পিছিয়ে। ঐ follower থেকে পড়লে পুরোনো মান আসতে পারে।

তাই সবসময় নতুন data লাগলে read leader এর কাছে পাঠান, আর leader উত্তর দেওয়ার আগে নিশ্চিত হয়ে নেয় যে সে এখনো leader। একটু পুরোনো data চললে follower থেকে পড়ুন, তাতে leader এর চাপ কমে।

সঠিক ভাষায়

Committed মানে majority র কাছে নিরাপদ, সবার কাছে পৌঁছানো নয়। Durability আর নতুন data পড়া দুইটা আলাদা প্রশ্ন।

প্রশ্ন ৩: Consensus এত নিরাপদ হলে পুরো order database টাই etcd তে রাখি না কেন?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“etcd ছোট data এর জন্য বানানো, তাই বড় data রাখা যায় না।”

কথাটা সত্যি, কিন্তু কেন ছোট data এর জন্য, সেটা বলা হলো না।

যে জায়গাটা যোগ করা দরকার

কারণ তিনটা। প্রথমত, প্রতিটা write কে majority র round trip আর disk fsync এর জন্য অপেক্ষা করতে হয়। দ্বিতীয়ত, সব write একজন leader এর মধ্য দিয়ে যায়, তাই write এর ক্ষমতা একটা machine এর ক্ষমতায় আটকে থাকে। তৃতীয়ত, প্রতিটা node এ পুরো data এর copy থাকে। এজন্য etcd এর default storage সীমা 2 GB, আর documentation 8 GB এর বেশি না রাখতে বলে। প্রতি সেকেন্ডে ৩,০০০ order এর database এর জন্য এটা উপযুক্ত নয়।

সঠিক ভাগাভাগি হলো: order থাকে সাধারণ database এ, আর সেই database এর primary কে, সেটা থাকে etcd তে। CockroachDB বা TiDB এর মতো database আরেকটা পথ নেয়। তারা data কে হাজারো ছোট টুকরায় ভাগ করে, আর প্রতিটা টুকরার জন্য আলাদা ছোট একটা Raft group চালায়।

মূল pattern

Consensus cluster কে system এর “মগজ” ভাবুন, গুদাম নয়। ছোট আর জরুরি সিদ্ধান্ত সেখানে রাখুন। বড় data রাখার জন্য অন্য store ব্যবহার করুন।

১১ যে টার্মগুলো শিখলাম

টার্মমানে
Consensusকয়েকটা server এর একটা মান নিয়ে এমনভাবে একমত হওয়া, যাতে crash বা network সমস্যাতেও সিদ্ধান্ত না বদলায়।
Majority quorumমোট node এর অর্ধেকের বেশি। যেকোনো দুইটা majority তে অন্তত একটা node common থাকে।
Raft২০১৪ সালের consensus algorithm, সহজে বোঝার জন্য বানানো। একজন leader সব write সামলায়।
Leaderযে server client এর write নেয়, follower দের copy পাঠায়, আর heartbeat দেয়।
Followerযে server leader এর কথা শোনে, entry জমা রাখে আর vote দেয়।
CandidateHeartbeat না পেয়ে যে follower নিজেই leader হতে vote চাইছে।
TermElection এর ক্রমিক নম্বর। এক term এ বড়জোর একজন leader; বড় term দেখলে সবাই follower হয়।
Leader electionপুরোনো leader চলে গেলে majority র vote দিয়ে নতুন leader বেছে নেওয়া।
Election timeoutযতক্ষণ heartbeat না এলে follower ধরে নেয় leader নেই।
Randomized timeoutপ্রতিটা follower এর timeout random রাখা (যেমন ১৫০-৩০০ ms), যাতে একসাথে সবাই candidate না হয়।
Split voteএকাধিক candidate এর মধ্যে vote ভাগ হয়ে কেউ majority না পাওয়া।
RequestVoteCandidate এর পাঠানো vote চাওয়ার message।
AppendEntriesLeader এর পাঠানো নতুন entry যোগ করার message। খালি AppendEntries ই heartbeat।
Logপ্রতিটা পরিবর্তনের ক্রমিক তালিকা। প্রতিটা entry তে index, term আর command থাকে।
Log replicationLeader এর log সব follower এর কাছে হুবহু একরকম করে copy করা।
Commitএকটা entry majority তে পৌঁছানো। এরপর সেটা আর হারায় না, বদলায় না।
Commit indexসবচেয়ে বড় committed entry র নম্বর; এই পর্যন্ত সব entry apply করা নিরাপদ।
Network partitionNetwork দুই বা তার বেশি ভাগ হয়ে যাওয়া, যাতে এক ভাগ আরেক ভাগের সাথে কথা বলতে পারে না।
PaxosLeslie Lamport এর consensus algorithm (১৯৮৯)। Prepare আর accept, এই দুই ধাপে majority দিয়ে একটা মান ঠিক করে।
Proposal numberPaxos এ প্রতিটা প্রস্তাবের ক্রমে বাড়তে থাকা unique নম্বর; Raft এর term এর মতো কাজ করে।
Multi-Paxosএকটার পর একটা মান (একটা log) ঠিক করতে স্থায়ী leader সহ বারবার Paxos চালানো।
etcd / Consul / ZooKeeper / KRaftConsensus চালানো প্রচলিত system: Kubernetes, service discovery, coordination আর Kafka এর metadata এর জন্য।

১২ শর্ট সামারি

  1. Consensus মানে কয়েকটা server একটা মান নিয়ে এমনভাবে একমত হয় যে crash, ধীর network বা আলাদা ঘড়ির মধ্যেও সিদ্ধান্ত কখনো বদলায় না। এর ভিত্তি majority quorum, কারণ যেকোনো দুইটা majority তে অন্তত একটা node common থাকে।
  2. Raft এ একজন leader সব write নেয় আর প্রতি ৫০ ms এ heartbeat পাঠায়। Heartbeat বন্ধ হলে যে follower এর random timeout আগে শেষ হয়, সে term বাড়িয়ে vote চায়, আর majority পেলে নতুন leader হয়।
  3. প্রতিটা write log এ entry হিসেবে লেখা হয়, আর majority তে পৌঁছালে তবেই commit হয়। নতুন leader হতে majority র vote লাগে, আর পুরোনো log এর candidate vote পায় না। তাই committed entry কখনো হারায় না।
  4. Network ভাগ হলে majority শুধু এক পাশে থাকে, তাই শুধু সেই পাশ commit করতে পারে, আর split brain হয় না। এজন্য cluster সাধারণত ৩ বা ৫ node এর হয়, আর etcd, Consul, ZooKeeper, Kafka KRaft এর মতো system এভাবেই system এর ছোট কিন্তু জরুরি সত্য রাখে।

১৩ মনে রাখুন