বর্তমানে পরীক্ষা চলছে: সম্পূর্ণ হলে GitHub কোড উন্মুক্ত করা হবে।

কর্মপ্রণালী

এই পাতায় ক্লায়েন্ট ও সার্ভার (ক্লাস্টার) এর মধ্যে বার্তার প্রকৃত প্রবাহ অনুসরণ করে Ticketing কীভাবে কাজ করে তা ব্যাখ্যা করা হয়েছে। ওয়্যারে যাওয়া বাইটের নিখুঁত স্পেসিফিকেশন পাওয়া যাবে প্রোটোকল (API) এবং প্রোটোকল (ক্লাস্টার)-এ।


সামগ্রিক কাঠামো

ব্যবহারকারীর অনুরোধ গ্রহণকারী সেবাগুলো (যেমন, টিকিট বিক্রি শুরুর অনুরোধ সামলানো ইভেন্ট সার্ভারগুলো) একই কী ব্যবহার করে Ticketing ক্লাস্টারে সারিতে দাঁড়ায়, এবং কেবল যার পালা আসে সেই সার্ভারই ইনভেন্টরি কমানো বা সিট বরাদ্দের মতো কাজ চালিয়ে যায়।

groups
ব্যবহারকারী
আপনার সেবা (যেমন ইভেন্ট সার্ভার)
dns ইভেন্ট সার্ভার 1
dns ইভেন্ট সার্ভার 2
dns ইভেন্ট সার্ভার 3
Ticketing ক্লাস্টার
confirmation_number ticketing-server 1
confirmation_number ticketing-server 2
confirmation_number ticketing-server 3

লক অর্জন ও মুক্তি

মূল প্রবাহ। দখলহীন একটি কী তৎক্ষণাৎ প্রদান করা হয়; দখলে থাকা কী FIFO সারিতে নিজের পালার জন্য অপেক্ষা করে। দখলদার মুক্তি দিলে, লকটি পুনঃপ্রতিযোগিতা ছাড়াই সরাসরি সারির সামনের জনের হাতে হস্তান্তরিত হয় — পরবর্তী অপেক্ষমাণ ব্যক্তি নতুন টোকেন সহ তৎক্ষণাৎ এগিয়ে যায়, ফলে লক কখনো খালি অবস্থায় থাকে না, এবং কেউ সারি ভেঙে সামনে আসতে পারে না।

ক্লায়েন্ট X
ক্লায়েন্ট Y
সার্ভার
A · অর্জন (order-1234)
A · প্রদত্ত (token 41)
A · অর্জন (order-1234)
দখলে আছে → সারিতে যুক্ত, উত্তর স্থগিত
R · মুক্তি
R · মুক্ত হয়েছে
A · সরাসরি হস্তান্তর (token 42)
অনুরোধপ্রতিক্রিয়া
  • lease একটি নিরাপত্তা জাল। কোনো ক্লায়েন্ট মারা গেলে বা মুক্তি দিতে ভুলে গেলে, lease মেয়াদ পার হলে সার্ভার কীটি পুনরুদ্ধার করে পরবর্তী অপেক্ষমাণকে দিয়ে দেয়। এটি এমনভাবে সেট করুন যেন আপনার ক্রিটিক্যাল সেকশনের সবচেয়ে খারাপ পরিস্থিতির সময়ের চেয়েও যথেষ্ট বেশি হয়। v1 কেবল ১–২৫০ সেকেন্ড গ্রহণ করে; এর চেয়ে দীর্ঘ কাজ স্পষ্টভাবে অসমর্থিত এবং প্রত্যাখ্যাত হয়।
  • wait হলো ক্লায়েন্টের অপেক্ষার ঊর্ধ্বসীমা। সেই সময়ের মধ্যে পালা না এলে, সার্ভার লক না দিয়ে T (টাইমআউট) দিয়ে উত্তর দেয়, ফলে কোনো লক কখনো ফাঁস হয় না। 0 মানে সারিতে না ঢুকে একবার তাৎক্ষণিক চেষ্টা। অসীম অপেক্ষা নেই।
  • একই ক্লায়েন্ট নিজের দখলে থাকা কী পুনরায় অর্জন করতে চাইলে, সে অন্য যেকোনো অপেক্ষমাণের মতোই সারিতে দাঁড়ায় — এটি পুনঃপ্রবেশযোগ্য (reentrant) লক নয়

কী-অবস্থা অনুযায়ী সার্ভারের আচরণের সম্পূর্ণ নিয়মের জন্য দেখুন অনুরোধ × কী-অবস্থা ম্যাট্রিক্স, এবং ফিল্ডের মান-পরিসরের জন্য দেখুন ফিল্ড সীমাবদ্ধতা

ফেন্সিং টোকেন

একটি নিখুঁত লক সার্ভারও ক্লায়েন্টের ঘড়ি নিয়ন্ত্রণ করতে পারে না। Ticketing একাই পুরনো দখলদার পরিস্থিতি ঠেকাতে পারে না: লক ধরে রাখা অবস্থায় GC পজ বা ওভারলোডে কিছুক্ষণ থমকে থাকা একটি ক্লায়েন্ট, এরপর জেগে ওঠে — তার lease ইতিমধ্যে শেষ হয়ে গেছে তা না জেনেই — এবং কাজ চালিয়ে যায়। এই কারণেই প্রতিটি অর্জন-উত্তরের token একটি প্রতিবার প্রদানের সময় নিশ্চিতভাবে বৃদ্ধি পাওয়া u64 পূর্ণসংখ্যা। আর্থিক বা persistent DB-তে প্রতি-key fencing high-water তুলনা ও update বাস্তব business write-এর সঙ্গে একই DB transaction বা একটি conditional write-এ atomically করতে হবে। আগে শুধু fencing row update করে পরে বাস্তব write করা নিরাপদ নয়।

ক্লায়েন্ট X
ক্লায়েন্ট Y
সার্ভার
সুরক্ষিত রিসোর্স
A · অর্জন
A · প্রদত্ত (token 7)
A · অর্জন → অপেক্ষমাণ
GC/ওভারলোডে থমকে গেছে
lease শেষ → পুনরুদ্ধার
A · সরাসরি হস্তান্তর (token 8)
লেখা (token 8)
token 8 রেকর্ড → গৃহীত
দেরিতে জেগে ওঠে
লেখা (token 7)
7 < 8 → প্রত্যাখ্যাত
অনুরোধপ্রতিক্রিয়া

ক্লাস্টারজুড়েও একঘাতিকতা (monotonicity) বজায় থাকে — টোকেন কাউন্টার নিজেই ঐকমত্যের মাধ্যমে প্রতিলিপি করা হয়, তাই লিডার বদলালেও নতুন লিডার সবসময় আগের চেয়ে বড় সংখ্যা থেকেই এগিয়ে যায়। ফিল্ডের নিখুঁত ফরম্যাটের জন্য দেখুন ফেন্সিং টোকেন (স্পেক)

ক্লাস্টার — Raft ঐকমত্যের মাধ্যমে নিরবচ্ছিন্ন পরিষেবা

ক্লাস্টার মোডে, নোডগুলো Raft ঐকমত্যের মাধ্যমে একটিমাত্র লক অবস্থা ভাগ করে নেয়। কেবল লিডারই ক্লায়েন্ট অনুরোধ সামলায়, এবং প্রতিটি লক-অবস্থা পরিবর্তন (অর্জন, মুক্তি, মেয়াদ শেষ) সংখ্যাগরিষ্ঠ নোড রেকর্ড করার পরই চূড়ান্ত হয়। লিডার নয় এমন নোডে সংযোগ করলে আপনি লিডারের দিকে নির্দেশক M (স্থানান্তরিত) উত্তর পাবেন।

ক্লায়েন্ট
ফলোয়ার B
লিডার A
ফলোয়ার C
A · অর্জন
M · লিডারের দিকে নির্দেশ
A · অর্জন
প্রতিলিপি প্রস্তাব
প্রতিলিপি প্রস্তাব
সম্মতি
সম্মতি
সংখ্যাগরিষ্ঠ সম্মতি → কমিট
A · প্রদত্ত (token)
অনুরোধপ্রতিক্রিয়াকনসেনসাস RPC (Raft)
  • লিডার মারা গেলে, বর্তমান defaults প্রায় ২.৩–২.৫ সেকেন্ডের মধ্যে নতুন লিডার নির্বাচন করে। request-এর একটি byte-ও পাঠানো না হলে তবেই একই logical acquire অবশিষ্ট wait budget-এ চালানো যায়। পাঠানো acquire-এর নিশ্চিত response না মিললে সেটি Indeterminate; কখনো স্বয়ংক্রিয়ভাবে পুনরায় পাঠানো হয় না।
  • এমনকি lease মেয়াদ শেষ হওয়াও ঐকমত্যের মধ্য দিয়ে যায়। লিডার মেয়াদ-শেষ কমান্ড কমিট করার পরই একটি লক অদৃশ্য হয়, তাই নোডগুলোর ঘড়িতে সামান্য পার্থক্য থাকলেও লক অবস্থা কখনো ভিন্ন হয়ে যায় না।
  • ক্লাস্টার সংখ্যাগরিষ্ঠতা হারালে (যেমন ৩টির মধ্যে ২টি নোড ডাউন), ভুল লক প্রদানের ঝুঁকি নেওয়ার বদলে এটি লেখা বন্ধ করে দেয় (নিরাপত্তা অগ্রাধিকার)। ৩টির মধ্যে ২টি (বা ৫টির মধ্যে ৩টি) নোডের volatile process state হারালে সেই cluster/fencing domain পুনরুদ্ধার বা একই identity-তে স্বয়ংক্রিয় bootstrap করা যাবে না।

যেহেতু সংখ্যাগরিষ্ঠতাই মুখ্য বিষয়, তাই কেবল ৩ বা ৫টি নোডের অনুমতি আছে। জোড় সংখ্যক নোড শুধু খরচ বাড়ায় কিন্তু ফল্ট-টলারেন্স বাড়ায় না, তাই সার্ভার জোড় সংখ্যক নোড নিয়ে চালু হতে অস্বীকার করে।

নোড সংখ্যানিরবচ্ছিন্নসহনীয় একযোগে ব্যর্থতামন্তব্য
১টিtoken monotonicity শুধু process lifetime পর্যন্ত; পুনরায় চালু হওয়া persistent DB সুরক্ষা অসমর্থিত
৩টি১টিনিরবচ্ছিন্ন পরিষেবার প্রমিত কনফিগারেশন। বেশিরভাগ ক্ষেত্রে যথেষ্ট
৫টি২টিএকটি নোড রক্ষণাবেক্ষণে থাকা অবস্থায়ও রিডানডেন্সি বজায় থাকে

পিয়ার RPC-এর ফ্রেমিং ও পোর্ট নিয়মের জন্য দেখুন প্রোটোকল (ক্লাস্টার), এবং একটি একটি করে নোড বদলানোর জন্য দেখুন নিরবচ্ছিন্ন নতুন NodeId learner প্রতিস্থাপন

ক্লায়েন্টের আচরণ

অফিসিয়াল ক্লায়েন্টগুলো একসাথে নিম্নলিখিত আচরণ প্রদর্শন করে (ভাষাভিত্তিক API-এর জন্য দেখুন লাইব্রেরি)।

  • প্রতিটি ঠিকানার জন্য একটি স্থায়ী সংযোগ পটভূমিতে বজায় রাখে। শুধু একটি ঠিকানা দেওয়া হলে, একই নোডের সাথে দুটি সংযোগ বজায় রাখে, ফলে একটি সকেট সাময়িকভাবে বিচ্ছিন্ন হলেও সেবা ব্যাহত হয় না।
  • অনুরোধ পাঠানোর জন্য প্রথমে লিডার, তারপর রাউন্ড-রবিন পদ্ধতিতে সংযোগ বেছে নেয়। M এর মাধ্যমে সর্বশেষ নির্দেশিত লিডারকে মনে রাখে এবং পরবর্তী অনুরোধ সরাসরি সেখানে পাঠায়।
  • অনুরোধ পাইপলাইনড হয়। উত্তরের জন্য অপেক্ষা না করেই পরবর্তী অনুরোধ পাঠানো যায় — অনুরোধ ও উত্তর কীভাবে জোড়া লাগানো হয় তার নিয়ম আছে উত্তর মিলকরণ নিয়ম-এ।
  • বিচ্ছিন্ন সংযোগ এক্সপোনেনশিয়াল ব্যাকঅফ (০.১ সেকেন্ড থেকে সর্বোচ্চ ৩.২ সেকেন্ড পর্যন্ত) দিয়ে পুনঃসংযোগের চেষ্টা চালিয়ে যায়। সংযোগ মারা গেলেও ব্রোকার অবজেক্ট নষ্ট হয় না — এটি নিজে থেকেই সেরে ওঠে।
  • একই logical acquire-এ internal retry হয় শুধু request-এর একটি byte-ও পাঠানো না হলে। সম্পর্কিত B নিশ্চিত Busy/অর্জন না হওয়া, তাই internal retry ছাড়াই caller-কে তাৎক্ষণিক ফেরে। M শুধু পরের connection-এর leader hint; owner/key না থাকায় আগে পাঠানো pending request পুনরায় পাঠানোর ভিত্তি নয়। নিশ্চিত response ছাড়া পাঠানো acquire Indeterminate হিসেবে জানানো হয় এবং critical section-এ ঢোকা যাবে না।
  • Explicit release এবং known-token compensation নির্ভুল owner/token/key match ও bounded dedicated queue ব্যবহার করে। Retry request/enqueue থেকে absolute ৫-second deadline-এ থামে, অবশিষ্ট lease পর্যন্ত নয়। success response ছাড়া explicit release সফল বলা বা ধরে নেওয়া হয় না; server-side lease শেষ নিরাপত্তা জাল।

সংযোগ ও নিরাপত্তা

প্রতিটি সংযোগ (ক্লায়েন্ট বা পিয়ার) TCP → (TLS) → challenge-response প্রমাণীকরণ ক্রমে স্থাপিত হয়। ক্লায়েন্ট সার্ভারের পাঠানো নন্স নিজের টোকেনের সাথে হ্যাশ করে উত্তর দেয়, ফলে টোকেন কখনো ওয়্যারে প্লেইনটেক্সটে যায় না, এবং প্রতিটি সংযোগে নতুন নন্স রিপ্লে ঠেকায়। নিখুঁত স্পেসিফিকেশনের জন্য দেখুন প্রমাণীকরণ হ্যান্ডশেক

সঙ্গতি সম্পর্কে একটি নোট

  • পারস্পরিক বর্জন (mutual exclusion) ঐকমত্যের মাধ্যমে নিশ্চিত করা হয়। প্রতিটি প্রদান সংখ্যাগরিষ্ঠ কমিটের মধ্য দিয়ে যাওয়ায়, নেটওয়ার্ক বিভাজন বা লিডার পরিবর্তনের সময়ও একই কী কখনো একসাথে দুই দখলদারকে দেওয়া হয় না।
  • Persistent DB-তে fencing বাধ্যতামূলক। protected write-এর সঙ্গে একই transaction/conditional write-এ atomically চালানো প্রতি-key high-water condition-ই lease শেষে জেগে ওঠা client-কে থামাতে পারে। Lock কাজের ক্রম ঠিক করে; DB fencing শেষ stale write আটকায়।