ইভেন্ট-ড্রিভেন DevOps — মেসেজ কিউ ও ইভেন্ট বাস
এই পাঠে যা শিখবেন
- মেসেজ কিউ ও ইভেন্ট বাস কীভাবে সার্ভিসগুলোকে ডিকাপল করে এবং কেন এটি DevOps-এর অপারেশনাল রিলায়েবিলিটির জন্য গুরুত্বপূর্ণ
- ডেড-লেটার কিউ কী, এবং কেন এটি একটি প্রয়োজনীয় সেফটি নেট
- Python দিয়ে একটি রিট্রাই-উইথ-DLQ প্যাটার্ন সিমুলেট করা
- এই টপিকটি System Design কোর্সের মেসেজ কিউ/ইভেন্ট-ড্রিভেন আর্কিটেকচার লেসনের সাথে কীভাবে সম্পর্কিত
১ · কেন প্রোডিউসার-কনজিউমার সরাসরি সংযুক্ত থাকা ঝুঁকিপূর্ণ
একটি সার্ভিস (প্রোডিউসার) যদি আরেকটি সার্ভিসকে (কনজিউমার) সরাসরি, সিনক্রোনাসভাবে কল করে, তাহলে কনজিউমার ধীর হয়ে গেলে বা সাময়িকভাবে ডাউন থাকলে প্রোডিউসারও ব্লক হয়ে যায় বা ব্যর্থ হয় — দুটি সার্ভিসের স্বাস্থ্য একে অপরের সাথে সরাসরি বাঁধা পড়ে যায়। এছাড়াও, একজনকে আপডেট/রিডিপ্লয় করতে হলে অন্যজন ঠিক সেই মুহূর্তে উপলব্ধ থাকতে হবে এমন একটি ভঙ্গুর কো-অর্ডিনেশন তৈরি হয়। মেসেজ কিউMessage Queueপ্রোডিউসার ও কনজিউমারের মাঝে একটি বাফার — প্রোডিউসার বার্তা কিউতে রেখে দেয়, কনজিউমার নিজের গতিতে সেটা তুলে প্রসেস করে; দুজন একে অপরের সাথে সরাসরি সংযুক্ত থাকে না। বা ইভেন্ট বাসEvent Busএকটি পাবলিশ/সাবস্ক্রাইব চ্যানেল — একটি সার্ভিস একটি ইভেন্ট প্রকাশ করে, যেকোনো সংখ্যক আগ্রহী সার্ভিস সেটা সাবস্ক্রাইব করে নিজের মতো প্রতিক্রিয়া জানায়, প্রকাশকারীকে জানতেও হয় না কারা শুনছে। ব্যবহার করলে এই সরাসরি নির্ভরতা দূর হয়ে যায়।
২ · অপারেশনাল বেনিফিট — স্বাধীন ডিপ্লয়, স্বাধীন স্কেল, স্বাধীন ফেইলিওর
ট্রাফিক স্পাইক হলে বার্তা কিউতে জমা হয়, কনজিউমার নিজের গতিতে ধীরে ধীরে প্রসেস করে — কনজিউমার ওভারলোড হয়ে ক্র্যাশ করে না।
কনজিউমার সার্ভিস রিডিপ্লয়/রিস্টার্ট হওয়ার সময়ও প্রোডিউসার চালিয়ে যেতে পারে — বার্তা কিউতে অপেক্ষা করে, হারিয়ে যায় না।
প্রোডিউসার ও কনজিউমার আলাদাভাবে স্কেল করা যায় — কিউ-এর দৈর্ঘ্য দেখেই বোঝা যায় কনজিউমার সাইড আরও ক্যাপাসিটি প্রয়োজন কিনা।
একটি কনজিউমার ক্র্যাশ করলেও প্রোডিউসার বা অন্য কনজিউমারদের সরাসরি প্রভাবিত করে না — কিউ মধ্যস্থতাকারী হিসেবে কাজ করে।
৩ · ডেড-লেটার কিউ — ব্যর্থ বার্তার জন্য সেফটি নেট
একটি বার্তা প্রসেস করতে ব্যর্থ হলে দুটি খারাপ বিকল্প আছে — নীরবে বার্তাটি ফেলে দেওয়া (ডেটা হারানো) অথবা
অসীমভাবে রিট্রাই করতে থাকা (একটি "পয়জন মেসেজ" পুরো কিউ ব্লক করে রাখতে পারে)।
ডেড-লেটার কিউDead-Letter Queue (DLQ)একটি নির্দিষ্ট সংখ্যক রিট্রাইয়ের পরও ব্যর্থ হওয়া বার্তাগুলোর জন্য আলাদা একটি কিউ — বার্তাটি হারিয়ে যায় না, বরং পরে ম্যানুয়ালি পরীক্ষা করার জন্য জমা থাকে।
এই দুই সমস্যারই সমাধান — একটি নির্দিষ্ট সীমা (max_retries) পর্যন্ত রিট্রাই করা হয়, তারপরও ব্যর্থ হলে
বার্তাটি DLQ-তে সরিয়ে রাখা হয়, প্রধান কিউ ব্লক হয় না, এবং কোনো ইঞ্জিনিয়ার পরে DLQ দেখে ব্যর্থতার কারণ খুঁজে বের করতে পারেন।
# ইভেন্ট-ড্রিভেন প্রসেসিং — রিট্রাই ও ডেড-লেটার কিউ সিমুলেশন (illustrative, কোনো real message broker নয়)
dead_letter_queue = []
attempt_counter = {101: 0, 102: 0}
def flaky_handler(msg):
# msg 101 তৃতীয় চেষ্টায় সফল হয়, msg 102 কখনোই সফল হয় না (ফেক হ্যান্ডলার)
attempt_counter[msg["id"]] += 1
if msg["id"] == 101 and attempt_counter[msg["id"]] >= 3:
return "success"
return "failure"
def process_message(msg, handler, max_retries=3):
attempts = 0
while attempts < max_retries:
attempts += 1
result = handler(msg)
if result == "success":
return f"বার্তা #{msg['id']} সফল — {attempts} নং চেষ্টায়"
print(f" চেষ্টা {attempts}/{max_retries} ব্যর্থ — বার্তা #{msg['id']}")
dead_letter_queue.append(msg)
return f"বার্তা #{msg['id']} {max_retries} বার ব্যর্থ — dead-letter queue-তে পাঠানো হলো"
msg_a = {"id": 101, "payload": "অর্ডার-আপডেট ইভেন্ট"}
msg_b = {"id": 102, "payload": "পেমেন্ট-কনফার্মেশন ইভেন্ট"}
print(process_message(msg_a, flaky_handler, max_retries=3))
print(process_message(msg_b, flaky_handler, max_retries=3))
print("Dead-letter queue-তে থাকা বার্তার id:", [m["id"] for m in dead_letter_queue])
৪ · CI/CD পাইপলাইনে এই প্যাটার্নের ব্যবহার
এই ঠিক প্যাটার্নটি বাস্তব DevOps পাইপলাইনেও দেখা যায় — একটি ডিপ্লয়মেন্ট-সম্পন্ন ইভেন্ট একটি নোটিফিকেশন সার্ভিসে সারিবদ্ধ হতে পারে (স্ল্যাক অ্যালার্ট পাঠানোর জন্য), একটি ইমেজ-স্ক্যান-সম্পন্ন ইভেন্ট ডিপ্লয়মেন্ট পাইপলাইনকে এগিয়ে যেতে বলতে পারে, অথবা একটি ইনফ্রাস্ট্রাকচার-প্রভিশনিং রিকোয়েস্ট একটি কিউতে সারিবদ্ধ হয়ে প্রসেস হতে পারে। প্রতিটি ক্ষেত্রে একই নীতি প্রযোজ্য — সাময়িক ব্যর্থতা রিট্রাই দিয়ে সামলানো, এবং ক্রমাগত ব্যর্থতা DLQ-তে গিয়ে একজন মানুষের নজরে আসা (M10/L44-এর অ্যালার্টিং প্র্যাকটিসের সাথে সরাসরি সম্পর্কিত)।
মেসেজ কিউ ও ইভেন্ট বাস শুধু একটি আর্কিটেকচারাল প্যাটার্ন নয় — এটি একটি অপারেশনাল রিলায়েবিলিটি হাতিয়ার। এটি সার্ভিসগুলোকে ডিকাপল করে স্বাধীন ডিপ্লয়/স্কেল সম্ভব করে, আর ডেড-লেটার কিউ নিশ্চিত করে ব্যর্থতা নীরবে হারিয়ে না গিয়ে দৃশ্যমান ও পরিচালনাযোগ্য থাকে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ যদি একটি কনজিউমার সার্ভিস ধীর হয়ে যায় বা সাময়িকভাবে ডাউন থাকে, প্রোডিউসারকে সরাসরি (সিনক্রোনাসভাবে) কল করলে কী সমস্যা হতে পারে — আর মেসেজ কিউ কীভাবে সেটা প্রতিরোধ করে?
সরাসরি সিনক্রোনাস কল করলে প্রোডিউসারও কনজিউমারের ধীরগতি/ডাউনটাইমের শিকার হয় — হয় ব্লক হয়ে অপেক্ষা করে, নয়তো টাইমআউট/ব্যর্থতার সম্মুখীন হয়, যা পুরো সিস্টেমে ক্যাসকেডিং ব্যর্থতা তৈরি করতে পারে। মেসেজ কিউ ব্যবহার করলে প্রোডিউসার শুধু বার্তা কিউতে রেখে নিজের কাজ চালিয়ে যায় — কনজিউমার সুস্থ হলে যখনই সক্ষম হয় তখন বার্তাটি প্রসেস করে, প্রোডিউসারকে কখনো অপেক্ষা করতে হয় না।
প্র ০২
max_retries ছাড়া শুধু "ব্যর্থ হলে আবার চেষ্টা করো, চিরকাল" — এই নীতি ব্যবহার করলে বাস্তবে কী সমস্যা হতে পারে?
একটি "পয়জন মেসেজ" (যা কখনোই সফলভাবে প্রসেস হবে না — যেমন করাপ্টেড ডেটা) অসীমভাবে রিট্রাই হতে থাকবে, কম্পিউট রিসোর্স নষ্ট করবে এবং কিউ-এর মধ্যে বাকি বার্তাগুলোর প্রসেসিং ব্লক বা ধীর করে দিতে পারে — সমস্যাটিও কোথাও দৃশ্যমান হয় না, কেউ জানতেও পারে না একটি বার্তা আটকে আছে। max_retries + DLQ এই দুটো সমস্যাই সমাধান করে — সীমিত রিট্রাইয়ের পর বার্তাটি সরিয়ে রাখা হয়, দৃশ্যমান ও পরীক্ষাযোগ্য হয়।
প্র ০৩ ইভেন্ট-ড্রিভেন আর্কিটেকচার কীভাবে CI/CD-এর "স্বাধীন ডিপ্লয়যোগ্যতা" লক্ষ্যকে (M8) সরাসরি সাহায্য করে?
সার্ভিসগুলো যদি একে অপরকে সরাসরি সিনক্রোনাসভাবে কল না করে বরং কিউ/ইভেন্ট বাসের মাধ্যমে যোগাযোগ করে, তাহলে একটি সার্ভিস রিডিপ্লয় করার সময় অন্য সার্ভিসগুলোর ঠিক সেই মুহূর্তে উপলব্ধ থাকার দরকার নেই — বার্তা কিউতে অপেক্ষা করবে, সার্ভিস আবার চালু হলে প্রসেস হবে। এতে ডিপ্লয়মেন্ট কো-অর্ডিনেশনের বোঝা অনেক কমে যায়, প্রতিটি টিম নিজের সার্ভিস স্বাধীনভাবে ডিপ্লয় করতে পারে।
অনুশীলন
-
পরিবর্তন করুন:
flaky_handler-কে এমনভাবে বদলান যাতে msg 102 চতুর্থ চেষ্টায় সফল হয় (attempt_counter[msg["id"]] >= 4হলে success), কিন্তুmax_retries৩-ই রাখুন। আবার চালিয়ে দেখুন dead_letter_queue-তে কী থাকে।msg 102-এর সফল হতে ৪ বার চেষ্টা প্রয়োজন, কিন্তু max_retries=৩ মানে সর্বোচ্চ ৩ বার চেষ্টা হবে — চতুর্থ চেষ্টার সুযোগই আসবে না। তাই msg 102 এখনও ব্যর্থ হয়ে dead_letter_queue-তে জমা হবে। এটি দেখায় max_retries সীমা বাস্তবে যথেষ্ট বড় না হলে সাময়িক (transient) সমস্যাও স্থায়ী ব্যর্থতা হিসেবে গণ্য হতে পারে — সঠিক max_retries মান বাছাই করা একটি গুরুত্বপূর্ণ ব্যবহারিক সিদ্ধান্ত।
-
চিন্তা করুন: dead_letter_queue-তে জমা হওয়া বার্তাগুলো নিয়ে একজন ইঞ্জিনিয়ার বাস্তবে পরবর্তীতে কী করবেন বলে আপনার মনে হয়?
সাধারণত DLQ-তে থাকা বার্তাগুলো নিয়মিত পর্যবেক্ষণ করা হয় (একটি অ্যালার্ট, M10/L44-এর প্র্যাকটিস) — ইঞ্জিনিয়ার বার্তার কন্টেন্ট ও সংশ্লিষ্ট লগ দেখে ব্যর্থতার আসল কারণ (একটি বাগ, ভুল ডেটা ফরম্যাট, একটি ডাউনস্ট্রিম ডিপেন্ডেন্সির সমস্যা) খুঁজে বের করেন, সমস্যাটি ঠিক করেন, এবং প্রয়োজনে বার্তাটি ম্যানুয়ালি আবার মূল কিউতে পাঠান (reprocess) — শুধু হারিয়ে যেতে দেওয়া হয় না।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ পরবর্তী পাঠ — সার্ভারলেস CI/CD ও ডিপ্লয়মেন্ট ফ্রেমওয়ার্ক — দেখুন।
- মেসেজ কিউ ও Pub/Sub প্যাটার্ন সঙ্গী কোর্স System Design কোর্সে এই প্যাটার্নের স্থাপত্যগত গভীর তত্ত্ব দেখুন।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity ও Cloud Computing & DevOps — সব এক জায়গায়।