০০ যে প্রশ্নগুলোর উত্তর খুঁজবো
এতক্ষণ পর্যন্ত আমাদের সব কিছুই ছিলো synchronous: request আসে, কাজটা শেষ না হওয়া পর্যন্ত user বসে অপেক্ষা করে, তারপর গিয়ে response পায়। এই সেশনে আমরা একটা নতুন কনসেপ্ট শিখবো: কাজটা এখনই accept করে নেওয়া, আর আসল কাজটা পরে করা। প্রতিটা প্রশ্নের উত্তর জানা হয়ে গেলে আপনি বুঝবেন একটা queue কীভাবে একটা system কে responsive আর reliable বানিয়ে তোলে।
- ১ User একটা video upload করলো। Process শেষ হওয়া পর্যন্ত তাকে অপেক্ষা করানো কেন সমস্যা?
- ২ যদি সাথে সাথে "পেয়েছি" বলে দিই, আর কাজটা পরে করি? (asynchronous processing)
- ৩ "পরে করার কাজ" টা কোথায় থাকে? (queue)
- ৪ অংশগুলো কী কী? (producer, queue, consumer)
- ৫ কাজ করার মাঝখানে একটা worker crash করলে কী হয়?
- ৬ একই message দুইবার process হলে কী হবে?
- ৭ Worker রা যত দ্রুত drain করতে পারে, তার চেয়ে দ্রুত কাজ এলে কী হয়?
- ৮ Full picture: queue কী দেয়, আর এর cost কী।
০১ Process শেষ হওয়া পর্যন্ত user কে অপেক্ষা করানো কেন সমস্যা?
একজন user একটা video upload করলো। সেটা দেখার মতো অবস্থায় আসার আগে system কে অনেকগুলো কাজ সারতে হয়: video টাকে একাধিক resolution এ encode করা (কয়েক মিনিট লাগে), thumbnail বানানো, copyright scan করা, caption বের করা, search index update করা। এই সবগুলো কাজই ধীর, সব মিলিয়ে কয়েক মিনিট সময় নিয়ে নেয়।
Synchronous model এ ঐ একটা upload request ই এই সব কাজ করে, আর ততক্ষণ user বসে বসে অপেক্ষা করতে থাকে:
চারটা গুরুতর সমস্যা:
- Terrible UX: ৫ মিনিটের spinner; user ভাবে কিছু একটা ভেঙে গেছে, তাই চলে যায়।
- Web server আটকে থাকে: ঐ thread টা পুরো ৫ মিনিট encode এর কাজেই আটকে থাকে, এই সময়ে আর কাউকে serve করতে পারে না। একসাথে ১০০টা upload এলে এভাবে ১০০টা server ই আটকে যায়।
- ভঙ্গুর (fragile): ৪ মিনিটের মাথায় একটা failure সব কাজ নষ্ট করে দেয়; user কে আবার শুরু থেকে upload করতে হয়।
- Timeout: browser, load balancer, আর proxy লম্বা request এ timeout করে ফেলে।
আসল কথা হলো, user কে process শেষ হওয়া পর্যন্ত অপেক্ষা করতে হয় না। তার শুধু এটুকু জানলেই চলে যে “আমরা আপনার video পেয়েছি”। কিন্তু synchronous model এ “এখন accept করি, ভারী কাজটা পরে সারি” বলার কোনো উপায়ই নেই।
০২ যদি সাথে সাথে “পেয়েছি” বলে দিই, আর কাজটা পরে করি?
Dry cleaner এর analogy
আপনি কাপড় জমা দিলেন। দোকানদার আপনাকে ৩ ঘণ্টা counter এ দাঁড় করিয়ে রাখে না। সে যা করে:
- আপনার কাপড় নেয়।
- একটা receipt দেয় (“ticket #47, কালকে ready”)।
- আপনি সাথে সাথে চলে যান।
- কাপড় পেছনে একটা কাজের স্তূপে চলে যায়।
- দোকানদার নিজের গতিতে স্তূপের কাজ একে একে করে।
- শেষ হলে কাপড় rack এ অপেক্ষা করে, যতক্ষণ না আপনি receipt নিয়ে ফিরে আসেন।
আপনি ১০ সেকেন্ডে receipt পেলেন; ধোয়ার আসল কাজটা হলো পরে, background এ।
Video upload এ প্রয়োগ (asynchronous processing)
Synchronous: কাজটা এখনই করা, যখন user অপেক্ষা করছে।
Asynchronous: সাথে সাথে acknowledge করা, কাজটা queue এ রেখে দেওয়া, পরে background এ process করা। User কখনো ধীর কাজের জন্য অপেক্ষা করে না।
এটা Q1 এর চারটা সমস্যাই একসাথে সমাধান করে: সাথে সাথে response (UX), web server মিলিসেকেন্ডের মধ্যে মুক্ত (আটকে থাকে না), job queue এ টিকে থাকে (ভঙ্গুর নয়), আর request দ্রুত শেষ হয় (timeout নেই)।
Queue “কাজ accept করা” আর “কাজ করা” কে decouple করে (আলাদা করে দেয়)। Web server দ্রুত accept করে; worker রা ভারী কাজটা পরে করে, নিজেদের গতিতে।
০৩ “পরে করার কাজ” টা কোথায় থাকে?
কাজটা একটা queue তে থাকে। Queue হলো একটা waiting line, যেখানে কাজ (job/message) জমা হয় আর process হওয়ার জন্য অপেক্ষা করে। Dry cleaner এর ticket এর স্তূপটাই হলো queue।
Queue টা web server এর ভেতরে থাকে না; এটা একটা আলাদা infrastructure। তাই web server কাজটা accept করে queue তে ফেলে দিয়েই সাথে সাথে মুক্ত হয়ে যায়, আর কাজটা নিরাপদে queue তে অপেক্ষা করতে থাকে।
০৪ অংশগুলো কী কী? (producer, queue, consumer)
প্রতিটা message queue system এ তিনটা ভূমিকা থাকে:
- Producer: queue তে একটা message/job রাখে (upload গ্রহণ করা web server)। সাধারণত দ্রুত, আর অনেকগুলো থাকে।
- Queue: buffer, যেটা message process না হওয়া পর্যন্ত ধরে রাখে। সাধারণত FIFO (first-in-first-out, যে আগে ঢোকে সে আগে বের হয়) order এ store করে, নিরাপদে রাখে।
- Consumer (worker): message বের করে নিয়ে আসল কাজটা করে (background এর encoder গুলো)। সাধারণত এটাই ধীর অংশ; load অনুযায়ী scale করা হয়।
Producer আর consumer decoupled: এরা সরাসরি কথা বলে না, একই সময়ে চলারও দরকার নেই। Producer একটা job ফেলে দিয়ে ভুলে যায়; একটা ফাঁকা consumer পরে সেটা তুলে নেয়।
এতে independent scalability পাওয়া যায়: processing ধীর বলে queue যদি জমে যেতে থাকে, তাহলে শুধু consumer ই যোগ করুন (producer এ হাত না দিয়ে)। এই অমিলটা queue নিজেই absorb করে নেয়। পুরনো synchronous model এ accept করা আর process করা একই machine এ হতো, তাই শুধু ধীর অংশটুকু আলাদা করে scale করার উপায় ছিলো না।
Producer হলো কাপড় জমা দেওয়া customer; queue হলো ticket এর স্তূপ; consumer হলো স্তূপের কাজ করা দোকানদার। তিনটা স্বাধীন, যার যার গতিতে চলে, শুধু queue এর মাধ্যমে যুক্ত।
Load leveling (একটা বড় সুবিধা)
এক মিনিটে ১,০০০টা upload আসে; আপনার আছে ১০টা worker।
- Synchronous: server এর সীমা (ধরুন ২০০) ছুঁয়ে যায়, বাকিগুলো reject হয় (503) বা timeout করে। System crash করে।
- Queue: সব ১,০০০টা সাথে সাথে accept হয় (প্রত্যেকে শুধু একটা job ফেলে)। ১০টা worker ধীরে ধীরে backlog টা শেষ করে। কিছুই timeout করে না; অপেক্ষমাণ job গুলো queue এ ধৈর্য ধরে অপেক্ষা করে।
Queue একটা spike absorb করে আর worker দের একটা স্থির গতিতে process করতে দেয়। এটা bursty incoming কাজ আর স্থির processing capacity এর মাঝে একটা shock absorber।
Overload এর HTTP code (পাশের কথা)
- 503 Service Unavailable: server overloaded, সাময়িকভাবে পারছে না। “capacity তে আছি, পরে retry করুন” বলার সবচেয়ে প্রচলিত উপায়।
- 429 Too Many Requests: একটা নির্দিষ্ট client rate limit ছুঁয়ে ফেলেছে।
- 500 Internal Server Error: সাধারণ “কিছু একটা ভেঙেছে”, বিশেষভাবে overload নয়।
০৫ কাজের মাঝখানে একটা worker crash করলে কী হয়?
একটা worker “process video #47” তুলে নিলো, encode শুরু করলো, আর ৩ মিনিট পর crash করলো (power, bug, deploy, hardware)। Job টা যদি হারিয়ে যায়, তাহলে video টা চুপচাপ চিরতরে হারিয়ে যায়।
ভালো queue এগুলো ঠেকায়: worker যখন message টা নেয় তখন সেটা delete হয় না; delete হয় শুধু তখনই, যখন worker নিশ্চিত করে যে কাজ শেষ।
ধাপে ধাপে: ack + visibility timeout
এটাই acknowledgment (ack) আর visibility timeout। একটা job সরানো হয় শুধু worker সফলতা নিশ্চিত করার পর। Crash হলে acknowledge না হওয়া job টা retry এর জন্য আবার ফিরে আসে।
Message টা queue এ থেকে যায় যতক্ষণ না সফলভাবে process হয়। Crash এ কাজ হারায় না; job টা আবার ফিরে আসে আর retry হয়। এটাই queue কে শুধু asynchronous নয়, reliable বানায়। Synchronous এর তুলনায় বিশাল উন্নতি, যেখানে ৪ মিনিটের মাথায় crash হলে সব হারিয়ে যেত।
০৬ একই message দুইবার process হলে কী হবে?
Duplicate সমস্যা (ack mechanism থেকে আসে)
একটা worker #47 encode সফলভাবে শেষ করলো, কিন্তু ACK পাঠানোর ঠিক আগে crash করলো। Queue কখনো ACK পেলো না, timer expire করলো, আর সে #47 আরেকটা worker কে দিয়ে দিলো। Video টা দুইবার encode হলো। কাজটা সফল হয়েছিলো, তবু আবার চললো: নষ্ট কাজ, বা আরও খারাপ (duplicate DB entry, user কে দুইবার notify, দুইবার charge)।
দুইটা সম্পর্কিত failure case
- Duplicate processing (সাধারণ): success হয়েও ACK এর আগে crash। সাধারণত একবারের duplicate; retry টা ঠিকঠাক ACK করে।
- Poison message (edge case): এমন একটা job যেটা সত্যিই শেষ হতে পারে না (যেমন corrupt file), প্রতিটা worker কে ACK এর আগে fail করায়, তাই অনন্তকাল retry হতে থাকে। সমাধান: একটা Dead Letter Queue (DLQ); N বার fail করার পর message টাকে আলাদা একটা queue তে সরিয়ে দেওয়া হয়, যাতে মানুষ পরীক্ষা করে দেখতে পারে, অনন্তকাল retry না করে।
Delivery guarantee (গুরুত্বপূর্ণ, প্রায়ই গুলিয়ে যায়)
| Guarantee | মানে | ঝুঁকি |
|---|---|---|
| At-most-once | ০ বা ১ বার deliver হয় | হারাতে পারে, কখনো duplicate হয় না |
| At-least-once | ১ বা তার বেশি বার deliver হয় | কখনো হারায় না, duplicate হতে পারে |
| Exactly-once | ঠিক ১ বার | holy grail; খুব কঠিন, infra level এ প্রায়ই myth |
বেশিরভাগ real queue at-least-once দেয়। মানে: কখনো হারায় না, কিন্তু duplicate হবেই (crash-before-ACK case)। এর সাথে লড়াই করবেন না; বরং এটা মাথায় রেখে design করবেন।
at-LEAST-once এ DUPLICATE হয় (সাধারণ default, এজন্যই idempotency দরকার)। at-MOST-once এ LOSS হয় (খুব কম ক্ষেত্রে কাম্য)। “কখনো হারায় না কিন্তু হয়তো duplicate” মানে at-least-once।
সমাধান: idempotency
Idempotency: একটা operation idempotent তখনই, যখন সেটা একাধিকবার চালালে একবার চালানোর মতোই একই result দেয়।
একটা light switch “on” এ রাখা idempotent (একবার বা পাঁচবার “on” এ দিন, তবু on ই থাকে)। কিন্তু “toggle” idempotent নয় (দুইবার মানে আবার off)।
Video processing যদি idempotent হয়, তাহলে #47 দুইবার encode করলেও একই result আসে (বা “আগেই হয়ে গেছে” বুঝে skip করে)। Duplicate টা নিরীহভাবে absorb হয়ে যায়।
Operation কে idempotent বানাবেন কীভাবে: idempotency key
unique ID কে idempotency key হিসেবে ব্যবহার করুন; কাজটা করার আগে একটা stored record check করুন:
গুরুত্বপূর্ণ অংশটা: কাজ আর record-write দুটোই atomic হতে হবে (একটাই transaction)। আপনি যদি charge করে record লেখার আগে crash করেন, তাহলে retry কোনো record দেখবে না আর আবার charge করবে। (আগের সেশনের transaction এর সাথে যুক্ত।)
বাস্তব system এ ঠিক এটাই হয়; Stripe একে বলে idempotency key। একই key দুইবার পাঠান, এটা আবার charge না করে আগের result ফেরত দেয়।
Queue at-least-once delivery দেয়, তাই duplicate অনিবার্য। Consumer কে idempotent বানান, যাতে দুইবার process হলেও কোনো ক্ষতি নেই। unique ID (idempotency key) আর একটা stored record হলো সেই হাতিয়ার যা এটা সম্ভব করে। এজন্যই Q2 এর unique ID টা এত গুরুত্বপূর্ণ ছিলো; এটা শুধু user এর receipt নয়, এটাই নিরাপদে duplicate সামলানোর চাবিকাঠি।
০৭ Worker দের drain ক্ষমতার চেয়ে দ্রুত কাজ এলে কী হয়? (sustained)
একটা queue সাময়িক spike absorb করে। কিন্তু টানা (sustained) overload আলাদা জিনিস:
সমস্যা:
- Latency বিস্ফোরিত হয়: নতুন একটা job পাঁচ লাখ job এর পেছনে অপেক্ষা করতে থাকে; “পরে process” হয়ে যায় “কখনো process না”।
- Queue এর memory/storage শেষ হয়ে যায়: এটা অসীম নয়; crash করে বা reject করে, কাজ হারিয়ে যায়।
- আসল সমস্যা লুকিয়ে রাখে: আপনি যে under-provisioned, সেটা ঢেকে রাখে, যতক্ষণ না হঠাৎ collapse করে।
“worker যোগ করুন” কথাটা তখনই কাজে দেয় যদি worker রা শেষ পর্যন্ত backlog টা ধরে ফেলতে পারে। কাজ আসার হার যদি স্থায়ীভাবে worker দের সর্বোচ্চ processing rate ছাড়িয়ে যায়, তাহলে queue শুধু collapse টাকে কিছুটা পিছিয়ে দেয়, আটকাতে পারে না।
Mechanism গুলো
- Backpressure: system overwhelmed হলে পেছনে চাপ দেয়, অসীম কাজ চুপচাপ accept না করে upstream এ “slow down” signal পাঠায়। Queue বিপজ্জনকভাবে ভরে গেলে producer রা নতুন কাজ reject করে (503, “পরে retry করুন”)। যে কাজ আপনি কখনো process করবেন না সেটা accept করার চেয়ে সৎ, নিয়ন্ত্রিত failure ভালো।
- Autoscaling consumer: queue length monitor করা হয়; বাড়লে auto worker যোগ হয়, কমলে scale back হয়। Decoupling এটা সম্ভব করে; queue depth একটা পরিষ্কার scaling signal।
- Priority queue: জরুরি কাজ (paying customer) কম-গুরুত্বের কাজের (free-tier batch) আগে process হয়। Load এর মধ্যেও গুরুত্বপূর্ণ কাজ চালু রাখে।
- Shedding: চরম overload এ ইচ্ছাকৃতভাবে কম-জরুরি কাজ (analytics event) drop করা হয়, critical কাজ (payment) বাঁচাতে।
Queue সাময়িক spike absorb করে, কিন্তু টানা overload ঠিক করতে পারে না; এটা শুধু collapse পিছিয়ে দেয় আর unbounded বাড়তে থাকে। টানা overload এর জন্য: backpressure (“slow down” signal), autoscaling (queue depth অনুযায়ী worker), priority (গুরুত্বপূর্ণ আগে), shedding (critical বাঁচাতে কম-মূল্যের কাজ drop)। Queue একটা shock absorber, অসীম capacity নয়।
০৮ Full picture: queue কী দেয়, আর এর cost কী
System এ queue কোথায় বসে
সাধারণ ব্যবহার
Video/image processing, email/SMS/push পাঠানো, order processing, analytics/logging pipeline, এমন যেকোনো ধীর third-party API call যেটার জন্য আপনি user কে অপেক্ষা করাতে চান না।
বাস্তব technology (যে নামগুলো জানা দরকার)
- RabbitMQ: classic message broker, flexible routing।
- Amazon SQS: managed AWS queue, সহজ আর scalable।
- Apache Kafka: একটা distributed log (বিশুদ্ধ queue নয়), high-throughput event streaming এর জন্য।
- Redis (streams/lists): হালকা queueing।
আপনি এগুলোর একটা ব্যবহার করবেন; queue শূন্য থেকে নিজে বানাবেন না (CDN ভাড়া নেওয়ার মতো)।
Queue আপনাকে যা দেয়
- Decoupling: producer/consumer স্বাধীন, আলাদাভাবে scale করে।
- Responsiveness: সাথে সাথে acknowledgment; ধীর কাজ background এ।
- Load leveling: spike absorb করে, স্থির গতিতে process করে।
- Reliability: crash এর পরও কাজ টিকে থাকে (at-least-once, ack + retry)।
- Resilience: consumer down থাকলেও job নিরাপদে অপেক্ষা করে, হারায় না।
Queue এর cost
- Complexity: আরেকটা infrastructure চালাতে, monitor করতে, বুঝতে হয়।
- Eventual consistency: কাজ সাথে সাথে হয় না; UX এ “processing” দেখাতে হয়। (সেশন ৪ এর সাথে যুক্ত।)
- Duplicate (at-least-once): consumer কে idempotent বানাতে হয়। সত্যিকারের কাজ।
- Ordering কঠিন: message সবসময় আসার order এ process হয় না (বিশেষত একাধিক worker থাকলে)।
- Debugging কঠিন: কাজ অন্য জায়গায়, পরে হয়; producer/queue/worker জুড়ে trace করা একটা synchronous request এর চেয়ে কঠিন।
একটা message queue কাজ accept করা কে কাজ করা থেকে decouple করে। এটা system কে responsive (সাথে সাথে ack), resilient (crash এর পরও কাজ টেকে), আর spike absorb করতে সক্ষম (load leveling) বানায়; এর বিনিময়ে আসে complexity, eventual consistency, আর idempotency এর প্রয়োজন। Queue ব্যবহার করুন যখন কাজ ধীর, পরে করা যায়, আর user কে অপেক্ষা করতে হয় না। ব্যবহার করবেন না যখন user এর সত্যিই সাথে সাথে result দরকার (তখন এটা শুধু বাড়তি ধাপসহ synchronous কাজ)।
০৯ মগজে প্রেশার দিন
আগে নিজে ভাবুন। তারপর দেখুন: সবাই যেভাবে ভাবে, কেন সেটা অসম্পূর্ণ, আর আসল insight টা কোথায়।
উত্তর দেখুন আগে নিজে ভাবুন
সবাই যেভাবে ভাবে
“Synchronous এ handler busy থাকলে request আটকে বা হারিয়ে যায়। Queue হলো post box এ চিঠি ফেলে রাখার মতো; worker free হলে খুলে উত্তর দেয়, তাই হারায় না।”
Analogy টা ভালো, কিন্তু একটা জায়গা miss হয়ে যাচ্ছে।
যে জায়গাটা যোগ করা দরকার
প্রধান সুবিধা শুধু “হারায় না” নয়, বরং sender অপেক্ষা করে না। চিঠিটা ফেলে আপনি সাথে সাথে হেঁটে চলে যান। এটাই responsiveness আর decoupling।
Synchronous এ accept করা আর process করা একসাথে বাঁধা। Queue দুটোকে আলাদা করে দেয়: producer দ্রুত accept করে চলে যায়, আর consumer পরে নিজের গতিতে process করে।
উত্তর দেখুন আগে নিজে ভাবুন
সঠিক চিন্তা
Email পাঠানো ধীর আর failure-prone, তাই এটা queue এর উপযুক্ত প্রার্থী। Synchronous এ email server fail করলে user email পায় না; queue + retry transient failure recover করে আর পরে mail টা পাঠিয়ে দেয়।
আরও যা বলা যায়
Signup নিজে দ্রুত থাকে। Email server ১০ মিনিট down থাকলেও signup এ কোনো প্রভাব পড়ে না; server recover করলে email বেরিয়ে যায়।
ধীর আর failure-prone কাজ (email, SMS, third-party call) queue তে রাখুন। মূল request দ্রুত থাকে, আর retry transient failure সামলায়।
উত্তর দেখুন আগে নিজে ভাবুন
সবাই যেভাবে ভাবে
“Exactly-once অর্জন করা কঠিন, তাই solution হলো idempotent processing; একাধিকবার process করলেও result একই থাকে।”
Solution টা ঠিক, কিন্তু guarantee এর label সহজেই উল্টে যায়।
যে জায়গাটা ঠিক করতে হয়
সাধারণ guarantee হলো at-least-once, at-most-once নয়। আর at-most-once এ LOSS হয়, at-least-once এ DUPLICATE হয়। সঠিক ধারা: exactly-once খুব কঠিন, তাই real queue at-least-once দেয়; কখনো হারায় না, কিন্তু একাধিকবার process হতে পারে (crash-before-ACK); duplicate হবেই; সমাধান idempotency।
“কখনো হারায় না কিন্তু হয়তো duplicate” মানে at-least-once, এটাই default, এজন্যই idempotency দরকার। “কখনো duplicate হয় না কিন্তু হয়তো হারায়” মানে at-most-once।
১০ যে টার্মগুলো শিখলাম
| টার্ম | মানে |
|---|---|
| Synchronous | কাজটা এখনই করা, যখন requester result এর জন্য অপেক্ষা করছে। |
| Asynchronous | এখন acknowledge করা, কাজটা পরে background এ করা। |
| Message queue | একটা buffer, যেটা job/message ধরে রাখে যতক্ষণ না worker process করে। |
| Producer | queue তে message রাখে। |
| Consumer / Worker | message বের করে এনে কাজটা করে। |
| Decoupling | producer আর consumer স্বাধীনভাবে চলে, আলাদাভাবে scale করে। |
| Load leveling | queue spike absorb করে, যাতে worker স্থির গতিতে process করে। |
| Acknowledgment (ACK) | worker এর নিশ্চিতকরণ যে message টা process হয়েছে; তবেই সেটা delete হয়। |
| Visibility timeout | process হওয়ার সময় message কতক্ষণ লুকানো থাকে; সময়ের মধ্যে ACK না এলে আবার ফিরে আসে। |
| At-most-once | ০ বা ১ বার deliver হয়। হারাতে পারে, কখনো duplicate হয় না। |
| At-least-once | ১+ বার deliver হয়। কখনো হারায় না, duplicate হতে পারে। সাধারণ default। |
| Exactly-once | ঠিক একবার deliver হয়। খুব কঠিন; infra level এ প্রায়ই myth। |
| Idempotency | একটা operation একাধিকবার চালালে একবার চালানোর মতোই একই result দেয়। |
| Idempotency key | duplicate processing শনাক্ত করে skip করার জন্য একটা unique ID। |
| Dead Letter Queue (DLQ) | N বার চেষ্টার পর বারবার fail করা (poison) message যেখানে যায়, পরীক্ষার জন্য। |
| Poison message | এমন message যেটা বারবার fail করে আর তার consumer কে crash করায়। |
| Backpressure | overwhelmed হলে upstream এ “slow down” signal পাঠানো, অসীম কাজ accept না করে। |
| RabbitMQ / SQS / Kafka / Redis | প্রচলিত queue/streaming technology। |
১১ সর্ট সামারী
- একটা message queue কাজ accept করা কে কাজ করা থেকে decouple করে; producer একটা job ফেলে দেয় আর user সাথে সাথে একটা acknowledgment পায়, এদিকে consumer রা ধীর কাজটা পরে background এ process করে।
- Queue ack + visibility timeout এর মাধ্যমে crash এর পরও টিকে থাকে (message delete হয় শুধু worker সফলতা নিশ্চিত করার পর), যা at-least-once delivery দেয়; তাই duplicate হবেই আর consumer কে idempotent বানাতে হবে।
- Queue সাময়িক spike absorb করে, কিন্তু টানা overload ঠিক করতে পারে না; তার জন্য দরকার backpressure, autoscaling, priority, আর shedding; queue একটা shock absorber, অসীম capacity নয়।
১২ মনে রাখুন
- কাজ accept করা কে কাজ করা থেকে decouple করুন। User এর result সাথে সাথে দরকার না হলে, queue তে রাখুন।
- Message crash এর পরও টেকে কারণ ACK এর পরই কেবল delete হয়। শুধু async নয়, reliability।
- At-least-once হলো default; duplicate অনিবার্য। এর সাথে লড়বেন না; consumer কে idempotent বানান।
- At-least-once মানে duplicate। At-most-once মানে loss। উল্টে ফেলবেন না।
- Idempotency মানে নিরাপদে আবার করা যায়। Duplicate শনাক্ত করে skip করতে unique ID আর stored record আর atomic write ব্যবহার করুন।
- Queue spike absorb করে, কিন্তু টানা overload নয়। Backpressure, autoscaling, priority, আর shedding ব্যবহার করুন।
- Queue complexity আর eventual consistency যোগ করে। কাজ ধীর আর পরে করার মতো হলে ব্যবহার করুন; এখনই result দরকার হলে নয়।