Course-এর সূচি

13.3

SQS FIFO Queue

message group, deduplication, exactly-once processing আর throughput-এর সীমা।

20 মিনিট পড়া + Animation

টিপস: ডটেড-আন্ডারলাইন করা যেকোনো শব্দে ট্যাপ বা Hover করলে তার অর্থ দেখবে।

এই লেসন শেষে তুমি পারবে

  • Standard queue কোন কথা দেয় না (ক্রম, duplicate না হওয়া), আর সেটা কখন একটা আসল system ভেঙে দেয়, যেমন wallet-এর ledger বা stock-এর order book, তা বোঝাতে।
  • ঠিকভাবে FIFO queue বানাতে: নামের শেষে .fifo, type ঠিক হয় তৈরির সময়েই, আর প্রতিটা message-এ message group ID থাকতেই হবে।
  • Message group দিয়ে message কীভাবে চলে আগেই বলে দিতে: group-এর ভেতরে কড়া ক্রম, আলাদা group একসাথে, আর কোনো group-এর message in flight থাকলে সেই group কেন আটকে থাকে।
  • Message deduplication ID আর content-based deduplication ব্যবহার করতে, আর ৫ মিনিটের deduplication interval ঠিক কী ধরে আর কী ধরে না, তা বলতে।
  • “Exactly-once processing” আসলে কী নিশ্চয়তা দেয়, আর consumer-কে কেন তবুও সময়মতো delete করতে আর idempotent থাকতে হয়, তা বোঝাতে।
  • FIFO-র throughput হিসাব করতে: প্রতি API action-এ সেকেন্ডে ৩০০ call, batch দিয়ে ৩,০০০ message, আর high-throughput mode-এ Region ভেদে অনেক বেশি।
  • FIFO queue-র সাথে FIFO dead-letter queue আর redrive জুড়তে, আর এর জন্য ক্রমের কতটা দাম দিতে হয় তা জানতে।
  • কখন শেষ পর্যন্ত standard queue-ই ঠিক উত্তর, তা ঠিক করতে।

#ক্রম আর duplicate কেন গুরুত্বপূর্ণ

#Standard queue কী কথা দেয়

লেসন ১৩.১-এ (Sync বনাম Async, আর Amazon SQS) আমরা দেখেছি standard queue, SQS-এর আদি queue type। প্রায় সীমাহীন throughput দিতে আর কোনো message না হারাতে SQS প্রতিটা message-এর copy অনেকগুলো server-এ রাখে। এই design-এর কারণে দুটো প্রতিশ্রুতি তুমি যতটা ভাবো তার চেয়ে দুর্বল:

  • Best-effort ordering। Message সাধারণত যে ক্রমে পাঠানো হয়েছে সেই ক্রমেই আসে, কিন্তু সবসময় না। দুজন consumer একসাথে poll করলে message ১-এর আগেই message ২ চলে যেতে পারে।
  • At-least-once delivery। প্রতিটা message অন্তত একবার পৌঁছায়, আর মাঝে মাঝে একাধিকবার, যেমন delete-এর সময় যে server-এ একটা copy ছিল সেটা নাগালে না থাকলে।

বেশিরভাগ কাজে এতে সমস্যা নেই। ছবি ছোট করা, newsletter পাঠানো, document index করা: ক্রমে কিছু যায় আসে না, আর একটা কাজ দুবার হলেও ক্ষতি নেই (কাজটা idempotent)। কিন্তু কিছু কাজ এই দুটো নিয়মেই ভেঙে পড়ে।

#যখন এতে চলে না

SQS-এর উত্তর একটা দ্বিতীয় queue type, FIFO (First In, First Out): যে আগে আসে সে আগে বের হয়, আর duplicate ঢোকে না। Play চেপে দুটো পাশাপাশি দেখো:

একটা wallet-এর top-up আর payment: standard queue বনাম FIFO queue

ঢাকার একটা mobile wallet-এর গ্রাহক ৫০০ টাকা top-up করল, ৩০০ টাকার একটা bill দিল, তারপর balance দেখল। Wallet API তিনটা message queue-তে পাঠায়; worker instance-গুলো সেগুলো ledger-এ বসায়। ক্রম আর একটা duplicate balance-এর কী দশা করে, দেখো।

পরিস্থিতি

ক্রম মোটামুটি, আর message অন্তত একবার পৌঁছায়: অনেক কাজে চলে, ledger-এর জন্য ভুল।

Wallet APIproducer
Queuewallet-events
Worker 1ledger
Worker 2ledger
#1 #2 #3

পাঠানোর ক্রম

1st2nd3rd
#1 top-up ৫০০#2 pay ৩০০#3 balance
ধাপ 1 / 4
1

API ক্রম মেনে পাঠায় #1 top-up ৫০০, #2 pay ৩০০, #3 balance দেখা। Standard queue দ্রুত থাকতে আর কোনো message না হারাতে একেকটা message-এর copy অনেক server-এ রাখে।

#FIFO queue জিনিসটা কী

FIFO queue এমন দুটো কথা রাখে, যা standard queue রাখে না:

  • ক্রম। Message যে ক্রমে পাঠানো হয়েছে, সেই ক্রমেই পৌঁছায় আর process হয়, তবে একটা message group-এর ভেতরে (পরের অংশ)। Slide-এ ছবিটা এরকম: producer পাঠাচ্ছে ৪ ৩ ২ ১, consumer poll করে পাচ্ছে ৪ ৩ ২ ১, ঠিক একই ক্রমে।
  • Exactly-once processing। SQS নিজে duplicate ঢোকায় না: একই deduplication ID দিয়ে ৫ মিনিটের মধ্যে আবার পাঠানো message গ্রহণ করা হয়, কিন্তু দ্বিতীয়বার পৌঁছানো হয় না।

এর দাম সীমিত throughput (প্রতি action-এ সেকেন্ডে ৩০০ API call, batch দিয়ে ৩,০০০ message, high-throughput mode-এ আরও বেশি), আর প্রতি request-এ একটু বেশি দাম।

#নামের শেষে .fifo, আর তৈরির অন্য নিয়ম

  • Queue-এর নাম অবশ্যই .fifo দিয়ে শেষ হবে, যেমন orders.fifo। এই suffix-টাও queue নামের ৮০ অক্ষরের সীমার মধ্যে গোনা হয়। শুধু নাম দেখেই FIFO queue চেনা যায়।
  • Type ঠিক হয় তৈরির সময়েই, FifoQueue=true attribute দিয়ে, পরে আর বদলানো যায় না। Standard queue-কে FIFO-তে (বা উল্টো) রূপান্তর করা যায় না: নতুন queue বানিয়ে producer আর consumer-দের সেখানে সরাতে হয়।
  • বাকি যা শিখেছ সব একই থাকে: visibility timeout, long polling, retention (default ৪ দিন, ১ মিনিট থেকে ১৪ দিন), message size (১ MiB পর্যন্ত) আর encryption (লেসন ১৩.১ আর ১৩.২, Visibility Timeout, Long Polling আর Dead-Letter Queue)।
  • FIFO queue-তে পাঠানো প্রতিটা message-এ অবশ্যই একটা message group ID থাকবে, আর হয় একটা message deduplication ID, নয়তো queue-তে content-based deduplication চালু থাকতে হবে। এগুলো না থাকলে SendMessage ব্যর্থ হয়।

#এক নজরে standard বনাম FIFO

Note বলছে, এই table থেকে পরীক্ষায় একটা প্রশ্ন প্রায় নিশ্চিত। নিচে সেটাই, note-এ যে খুঁটিনাটি নেই সেগুলো সহ:

Standard queueFIFO queue
ক্রমBest effort: message আগে-পিছে হতে পারেকড়া, প্রতি message group-এ: প্রতিটা group-এর ভেতরে যে আগে আসে সে আগে যায়; আলাদা group-এর মধ্যে কোনো ক্রম নেই
DeliveryAt least once: মাঝে মাঝে duplicateExactly-once processing: ৫ মিনিটের deduplication interval-এর মধ্যে কোনো duplicate ঢোকে না
Throughputপ্রায় সীমাহীনপ্রতি action-এ (send, receive, delete) সেকেন্ডে ৩০০ API call, ১০-এর batch দিয়ে সেকেন্ডে ৩,০০০ message; high-throughput mode-এ বড় Region-গুলোতে সেকেন্ডে ৭০,০০০ call (৭,০০,০০০ message) পর্যন্ত
নামযেকোনো নামশেষে .fifo লাগবেই, যেমন my-queue.fifo
Message group IDঐচ্ছিক (এতে fair queue চালু হয়, নিচে পাশের কথা)প্রতিটা message-এ বাধ্যতামূলক
প্রতি message-এ delayআছে (প্রতি message-এ DelaySeconds)নেই, শুধু পুরো queue-র delay
In-flight messageপ্রায় ১,২০,০০০১,২০,০০০
Dead-letter queueStandard queue হতে হবেFIFO queue হতে হবে
S3 event notificationগন্তব্য হিসেবে চলেচলে না (EventBridge দিয়ে ঘুরিয়ে নাও)
দাম (us-east-1)প্রতি ১০ লাখ request-এ প্রায় $0.40প্রতি ১০ লাখ request-এ প্রায় $0.50

#Message group

#Message group ID কী

FIFO queue-র ক্রম পুরো queue-র জন্য একটাই লাইন না। প্রতিটা message বয়ে নেয় একটা message group ID (MessageGroupId, ১২৮ অক্ষর পর্যন্ত), আর SQS প্রতিটা group-এর জন্য আলাদা একটা ক্রমের লাইন রাখে:

  • একটা group-এর ভেতরে message ঠিক যে ক্রমে পাঠানো হয়েছে, সেই ক্রমেই জমা থাকে আর পৌঁছায়।
  • আলাদা group-এর মধ্যে কোনো ক্রম নেই: group A-র পুরনো একটা message-এর আগেই group B-র message process হয়ে যেতে পারে।
  • পুরো queue যদি একটাই কড়া ক্রমে চাও, প্রতিটা message-এ একই group ID দাও। কয়েকজন producer একই group-এ পাঠালে SQS আসার ক্রমে সাজায়; প্রত্যেক producer-এর নিজের ক্রম রাখতে চাইলে প্রত্যেককে আলাদা group দাও।
  • একটা queue-তে কতগুলো group থাকতে পারে, তার কোনো সীমা নেই।

Group ID আসলে এই প্রশ্নের উত্তর: “কোনটার ক্রম ঠিক রাখতেই হবে?” একটা wallet, একটা order, একটা bank account, একটা share-এর symbol, একটা device। আলাদা wallet-এর মধ্যে কোনো সম্পর্ক নেই, তাই সেগুলো একসাথে process হতে পারে।

#একটা group-এর একসময়ে একটাই message in flight

এই নিয়মটাই FIFO-কে চালায়, আর অনেককে অবাক করে:

  • কোনো consumer একটা group-এর message receive করলে, সেগুলো delete না হওয়া পর্যন্ত, অথবা তাদের visibility timeout শেষ হয়ে আবার দেখা না যাওয়া পর্যন্ত, SQS ওই group-এর আর কোনো message দেয় না।
  • একটা ReceiveMessage call একই group-এর ১০টা পর্যন্ত message একসাথে দিতে পারে (ক্রম মেনেই), আর batch-এর বাকি জায়গা অন্য group-এর message দিয়ে ভরতে পারে।
  • ঠিক তখন অন্য যে consumer-রা poll করছে, তারা পায় অন্য group-এর message, ব্যস্ত group-এর পরেরটা কখনো না। নির্দিষ্ট কোনো group চাওয়া যায় না; SQS-ই বেছে দেয়।
  • তাই FIFO queue-তে একসাথে কতটা কাজ চলবে, তা ঠিক করে কতগুলো group-এ message অপেক্ষা করছে। দুজন consumer আর একটা group: একজন কাজ করে, আরেকজন খালি উত্তর পায়। হাজারটা group: হাজারজন consumer একসাথে কাজ করতে পারে।
  • কোনো consumer crash করলে অসমাপ্ত message-টা visibility timeout-এর পর আবার দেখা যায়, আর সে তখনো তার group-এর সামনে, তাই পরেরটার আগে সেটাই আবার যায়। Crash-এও ক্রম টেকে; শুধু ওই একটা group কিছুক্ষণ থেমে থাকে।

AWS Lambda-ও একই নিয়ম মানে: FIFO queue event source হলে function-এর concurrency-র সীমা হয় চালু message group-এর সংখ্যা (অথবা maximum concurrency setting, যেটা কম), আর কোনো batch ব্যর্থ হলে Lambda একই group থেকে নতুন message নেওয়ার আগে আগে সেটাই আবার চেষ্টা করে। Lambda আর event source mapping বিস্তারিত আসবে অধ্যায় ১৫-তে (Lambda concurrency)।

#Group-এর key বেছে নেওয়া

ভালো আর খারাপ group key:

  • ভালো: wallet ID, account নম্বর, order ID, device ID, share-এর symbol, chat conversation ID। অনেক আলাদা মান, আর ক্রম লাগে শুধু প্রতিটার ভেতরে।
  • বেশি মোটা: একটা স্থির মান ("all"), দোকান, restaurant, Region। একটা গরম মানই বোতলের মুখ হয়ে যায়; একটা group একসময়ে একটাই message process করতে পারে।
  • বেশি সরু: প্রতি message-এ একটা random UUID। প্রতিটা message নিজেই একটা group, ফলে কোনো ক্রমই থাকে না; FIFO-র দাম দিলে, পেলে সীমাওয়ালা একটা standard queue।

Message group: group-এর ভেতরে ক্রম, আলাদা group-এ একসাথে

একটা food-delivery app order-এর status event (placed, cooking, picked up, delivered) পাঠায় orders.fifo-তে। Group ID ঠিক করে কোনগুলোর ক্রম ঠিক রাখতেই হবে, আর তাই একসাথে কতটা কাজ চলতে পারবে।

পরিস্থিতি

Group ID = order ID: প্রতিটা order-এর event ক্রমে থাকে, আলাদা order পাশাপাশি চলে।

Order serviceproducer
orders.fifoFIFO queue
Consumer 1
Consumer 2
A1 B1 A2 B2

orders.fifo-র ভেতরে

group Agroup B
A1 placed → A2 cookingB1 placed → B2 cooking
ধাপ 1 / 3
1

Order A আর order B দুটোই আগে placed, তারপর cooking পাঠায়। প্রতিটা message-এ message group ID থাকতেই হবে; এখানে সেটা order ID, তাই একটা queue-র ভেতরেই A আর B দুটো আলাদা ক্রমের লাইন।

নিজেকে যাচাই করোপ্রশ্ন

একটা FIFO queue-তে order event আসে, message group ID হলো order ID। পাঁচজন consumer poll করছে। Order ৭-এর পাঁচটা event অপেক্ষায়, আর তার প্রথম event consumer ১ process করছে। Consumer ২ poll করলে কী পায়?

#Deduplication

FIFO queue duplicate সরায় send-এর দিকেই। প্রতিটা message-এর একটা message deduplication ID থাকে; গত ৫ মিনিটে (এটাই deduplication interval) একই ID-র একটা message গ্রহণ করা হয়ে থাকলে নতুনটা গ্রহণ করা হয় (producer স্বাভাবিক success উত্তর পায়), কিন্তু পৌঁছানো হয় না। SQS-কে এই ID দুইভাবে দিতে পারো।

#Message deduplication ID

Producer প্রতিটা message-এ MessageDeduplicationId (১২৮ অক্ষর পর্যন্ত) দেয়, সাধারণত এমন একটা ID যা তার কাছে আগে থেকেই আছে: transaction ID, order ID আর event-এর ধরন মিলিয়ে, file-এর নাম আর version-এর hash।

  • এটাই producer-এর retry-কে নিরাপদ করে। দুর্বল connection-এ একটা phone payment পাঠাল, উত্তর হারিয়ে গেল, app জানে না কাজ হয়েছে কিনা, তাই একই ID দিয়ে আবার পাঠাল। SQS ID-টা চিনে ফেলে, দ্বিতীয় copy যোগ করে না, আর group-এর ক্রমও নড়ে না।
  • Message receive আর delete হয়ে যাওয়ার পরেও SQS ID-টা মনে রাখে, ৫ মিনিট শেষ না হওয়া পর্যন্ত।
  • নিজের দেওয়া ID সবসময় জেতে: queue-তে content-based deduplication চালু থাকলেও তোমার ID বানানো ID-র জায়গা নেয়।
  • সফলভাবে পাঠানোর পর SQS ফেরত দেয় একটা sequence number: একটা বড়, ধারাবাহিক নয় এমন সংখ্যা, যেটা একটা message group-এর ভেতরে বাড়তেই থাকে। SQS কোন ক্রমে রেখেছে, সেটা এতে বোঝা যায়।

#Content-based deduplication

Producer-এর কাছে ভালো কোনো ID না থাকলে queue-তে ContentBasedDeduplication চালু করা যায়। তখন SQS message body-র SHA-256 hash বের করে সেটাকেই deduplication ID বানায়।

  • Hash হয় শুধু body-র, message attribute-এর না। একই body আর আলাদা attribute-এর দুটো message duplicate।
  • এটা তখনই নিরাপদ, যখন একই body মানে সবসময় একই ঘটনা। কোনো গ্রাহক যদি সত্যিই ৫ মিনিটের মধ্যে একই নম্বরে দুবার ১০০ টাকা recharge করে, আর দুবারই body হয় {"phone":"01711…","amount":100}, তাহলে দ্বিতীয় recharge চুপচাপ বাদ পড়ে। Body-তে একটা অনন্য request ID বা timestamp রাখো, অথবা নিজে ID পাঠাও।
  • নিজের ID বা content-based deduplication, কোনোটাই না থাকলে send একটা error দিয়ে ব্যর্থ হয়।

#৫ মিনিটের window, আর deduplication scope

  • Interval স্থির, ৫ মিনিট। Window-এর পরে আসা retry নতুন message, আর duplicate ঢুকে পড়ে। Producer-এর retry (তার exponential backoff সহ) ৫ মিনিটের মধ্যে রাখো, আর consumer-এ তবুও একটা idempotency check রাখো।
  • Deduplication scope হতে পারে পুরো queue (default), অথবা প্রতিটা message group। Message-group scope-এ দুটো আলাদা group-এ একই deduplication ID মানে দুটো আলাদা message। High-throughput mode-এ message-group scope লাগবেই।

Deduplication: producer যতবারই আবার পাঠাক, payment একটাই

একটা payment API payments.fifo-তে পাঠায় “বিদ্যুৎ বিলে ১,২০০ টাকা দাও”। Mobile network-এ উত্তর হারায়, তাই producer আবার পাঠায়। Deduplication ID কোনটা ধরে, আর কোনটা ধরতে পারে না, দেখো।

পরিস্থিতি

৫ মিনিটের মধ্যে একই deduplication ID: গ্রহণ করে, কিন্তু আবার পৌঁছায় না।

Payment APIproducer
payments.fifo১টা message
Workerconsumer
send, dedup ID txn-7781
ধাপ 1 / 5
1

Producer message deduplication ID দেয় নিজের transaction ID, txn-7781। SQS message-টা রাখে, আর ওই ID-র জন্য ৫ মিনিটের deduplication interval শুরু করে।

#Exactly-once processing আসলে কী বোঝায়

Note-এর table বলছে FIFO দেয় “exactly-once processing (কখনো duplicate হবে না)”। পরীক্ষার উত্তর এটাই, আর মোটামুটি সত্যিও, কিন্তু প্রতিশ্রুতিটা ঠিক কোথায় শেষ, জেনে রাখা ভালো:

  • SQS যা নিশ্চিত করে: সে নিজে duplicate ঢোকায় না। একই deduplication ID দিয়ে ৫ মিনিটের মধ্যে producer-এর retry দ্বিতীয় message বানায় না, আর message in flight থাকলে group আটকে থাকে বলে দুজন consumer কখনো একই message একসাথে process করে না।
  • Receive-এর retry: network-এ কোনো ReceiveMessage call ব্যর্থ হলে consumer একই receive request attempt ID (ReceiveRequestAttemptId) দিয়ে আবার চেষ্টা করে একই message-গুলো ফেরত পায়, ক্রম না ভেঙেই।
  • তোমার যা দায়: consumer কাজটা করল কিন্তু visibility timeout শেষ হওয়ার আগে message delete করল না (কাজটা ধীর ছিল, বা database-এ লেখার পরে crash করল), তাহলে message আবার দেখা যায় আর আবার process হয়। কোনো duplicate পাঠানো হয়নি, তবুও কাজটা দুবার হলো। Visibility timeout সবচেয়ে ধীর কাজের সময়ের অনেক ওপরে রাখো (Lambda হলে AWS বলে function timeout-এর অন্তত ছয় গুণ), লম্বা কাজে ChangeMessageVisibility দিয়ে বাড়িয়ে নাও (লেসন ১৩.২), আর কাজের ফলটা idempotent করো (যেমন, “এই transaction ID processed table-এ না থাকলে তবেই insert করো”)।
  • Window-এর বাইরে: ৫ মিনিট পরে producer-এর retry নতুন message (আগের অংশ)।

#Throughput

#সেকেন্ডে ৩০০, batch দিয়ে ৩,০০০

FIFO queue-র সীমা গোনা হয় প্রতি API action-এ সেকেন্ডে কতগুলো API call (transaction) তা দিয়ে, message দিয়ে না:

  • SendMessage-এর জন্য ৩০০ TPS, ReceiveMessage-এর জন্য ৩০০, DeleteMessage-এর জন্য ৩০০, প্রতিটা আলাদা করে গোনা।
  • Batch দিয়ে (SendMessageBatch, DeleteMessageBatch, আর যে receive ১০টা পর্যন্ত message ফেরত দেয়) একটা call-এ ১০টা পর্যন্ত message যায়, তাই ৩০০ × ১০ = সেকেন্ডে ৩,০০০ message। Slide-এর “batch ছাড়া সেকেন্ডে ৩০০ message, batch দিয়ে ৩০০০”, এটাই ঠিকঠাক ভাষায়।
  • প্রতিটা message-এর জন্য লাগে একটা send, একটা receive আর একটা delete, তাই প্রতিটা action-কেই সীমার ভেতরে থাকতে হবে। সেকেন্ডে ১,০০০ message-এর চাপে batch ছাড়া প্রতিটা ধরনের ১,০০০ call লাগবে (অনেক বেশি), আর ১০-এর batch-এ প্রতিটা ধরনের ১০০ call (ঠিক আছে)।

#High-throughput mode

২০২১ থেকে FIFO queue-কে high-throughput mode-এ নেওয়া যায়, আর তারপর থেকে সীমা কয়েকবার বাড়ানো হয়েছে। Console-এর একটা option, Enable high throughput FIFO, চালু করলেই হয়; এটা দুটো attribute ঠিক করে দেয়:

  • DeduplicationScope = messageGroup (deduplication প্রতি group-এ, ওপরে দেখো);
  • FifoThroughputLimit = perMessageGroupId (throughput-এর quota খাটে প্রতি group-এ, পুরো queue-তে না)।

এর যেকোনো একটা আগের মতো করে দিলে আবার সাধারণ throughput খাটে। তখন প্রতি API action-এর সীমা Region-এর ওপর নির্ভর করে (অক্টোবর ২০২৬-এ যাচাই করা):

Regionসেকেন্ডে call (batch ছাড়া)সেকেন্ডে message (১০-এর batch)
US East (N. Virginia), US West (Oregon), Europe (Ireland)৭০,০০০৭,০০,০০০
US East (Ohio), Europe (Frankfurt)১৯,০০০১,৯০,০০০
Asia Pacific (Mumbai, Singapore, Sydney, Tokyo), Europe (Spain)৯,০০০৯০,০০০
Europe (London), South America (São Paulo)৪,৫০০৪৫,০০০
বাকি সব Region২,৪০০২৪,০০০

Service Quotas console থেকে আরও বাড়ানোর অনুরোধ করা যায়। Inventory-র “৭০,০০০ পর্যন্ত” বড় Region-গুলোর জন্য ঠিক; Mumbai বা Singapore-এ deploy করা বাংলাদেশি team-এর জন্য মনে রাখার সংখ্যা ৯,০০০।

#Partition, আর কেন group ID অনেক হতে হবে

FIFO queue ৩০০ থেকে ৭০,০০০-এ যায় কীভাবে? সে message রাখে partition-এ, যেগুলোর প্রতিটা কয়েকটা Availability Zone-এ copy হয়ে থাকে, আর পুরোটাই SQS সামলায়। কোন partition-এ যাবে তা ঠিক হয় message group ID-র hash দিয়ে, আর প্রতিটা partition সেকেন্ডে মোটামুটি ৩০০ call নেয় (batch দিয়ে ৩,০০০ message)। Traffic বাড়লে SQS partition যোগ করে, কমলে সরায়।

ফল: high-throughput mode তখনই কাজে লাগে, যখন message অনেকগুলো আলাদা group ID-তে ছড়ানো। Group একটা হলে সব একটা partition-এ পড়ে, আর Region যতই দিক, তুমি আবার সেকেন্ডে ৩০০ call-এ ফিরে এলে। AWS বলে অনেক আলাদা মানের group ID রাখতে, আর সম্ভব হলে একই group-এর message একসাথে batch করতে।

নিজে সংখ্যাগুলো বসিয়ে দেখো:

FIFO throughput যাচাই

একটা payment company তাদের transaction event SQS FIFO queue-তে নিচ্ছে। সবচেয়ে ব্যস্ত সময়ের চাপ আর design বেছে নাও, তারপর দেখো queue আর ক্রম মেনে চলা consumer-রা তাল রাখতে পারে কিনা।

ব্যস্ত সময়ে সেকেন্ডে কতগুলো message

প্রতি API call-এ message (batch)

High-throughput mode

Region

চালু message group

প্রতি message process করতে সময়

ফল দেখতে “Design যাচাই করো” চাপো।

দুটো ছাদ আছে, আর নিচেরটাই জেতে: queue-র ছাদ (সেকেন্ডে call × batch size), আর ক্রম মেনে process-এর ছাদ, কারণ একটা group একসময়ে একটাই message process করে: প্রতি message-এ ১০০ ms লাগলে একটা group সেকেন্ডে বড়জোর ১০টা message করে, তাই সেকেন্ডে ২,৫০০ message-এর জন্য অন্তত ২৫০টা চালু group লাগবে।

#FIFO queue আর dead-letter queue

Dead-letter queue (DLQ) এসেছে লেসন ১৩.২-এ। FIFO-তে এটা একইভাবে কাজ করে, তবে নিজের কয়েকটা নিয়ম আছে:

  • FIFO queue-র DLQ-কে FIFO queue-ই হতে হবে (আর standard queue-র DLQ standard)। একই account আর একই Region-এ থাকতে হবে।
  • একটা poison message (যেটা সবসময় ব্যর্থ হয়) FIFO queue-তে বেশি ক্ষতিকর: সে সবসময় তার group-এর সামনে, তাই বারবার ফিরে আসে আর ওই group-এর পরের সব message আটকে রাখে। একে বলে head-of-line blocking। অন্য group-এর কিছু হয় না।
  • maxReceiveCount সহ redrive policy অতবার receive-এর পরে message-টাকে DLQ-তে সরিয়ে দেয়, তাতে group খুলে যায়। কিন্তু group-এর পরের message-গুলো এখন তাকে ছাড়াই process হয়, ফলে ওই group-এর ভেতরের ক্রম ভেঙে যায়। AWS-এর নিজের পরামর্শ: message বা কাজের ঠিক ক্রম ভাঙা যদি থেমে থাকার চেয়েও খারাপ হয়, তাহলে FIFO queue-র সাথে DLQ ব্যবহার কোরো না (ওদের উদাহরণ video editing software-এর edit list, যেখানে প্রতিটা edit আগেরটার ওপর নির্ভর করে)। সেক্ষেত্রে আটকে যাওয়া group-এর ওপর alarm রাখো আর সমস্যাটা ঠিক করো।
  • Retention: FIFO DLQ-তে message সরানোর সময় তার enqueue timestamp নতুন করে শুরু হয়, তাই সে DLQ-এর পুরো retention সময় পায়। (Standard DLQ-তে আসল timestamp-ই থাকে, এজন্যই standard DLQ-এর retention source-এর চেয়ে লম্বা রাখতে হয়।)
  • Redrive: ২০২৩-এর নভেম্বর থেকে FIFO DLQ থেকে message আবার FIFO source queue-তে বা অন্য কোনো FIFO queue-তে পাঠানো যায় (StartMessageMoveTask, বা console-এর “Start DLQ redrive”)। Redrive হওয়া message নতুন message ID পায় আর group-এর একদম পেছনে যায়।

একটা poison message নিজের group আটকে দেয়, তারপর যায় FIFO DLQ-তে

একটা e-commerce order queue, orders.fifo, তার একটা redrive policy আছে: ৫ বার receive হওয়ার পর message চলে যায় orders-dlq.fifo-তে। Group A-র একটা message-এর address ভাঙাচোরা, worker সেটা পড়তে পারে না।

পরিস্থিতি

Head-of-line blocking: খারাপ message-টাই বারবার আগে ফিরে আসে।

Shop APIproducer
orders.fifosource
Worker
orders-dlq.fifodead-letter
A1 A2 A3 B1 B2

orders.fifo

group Agroup B
A1 (ভাঙা) → A2 → A3B1 → B2
ধাপ 1 / 4
1

Group A-তে আছে A1 (ভাঙা address), A2 আর A3। Group B-তে B1 আর B2।

#FIFO-র আরও কিছু নিয়ম

  • Delay। FIFO queue-তে পুরো queue-র একটা delay (০ থেকে ১৫ মিনিট) দেওয়া যায়, কিন্তু প্রতি message-এ delay না: আলাদা message-এ DelaySeconds চলে না, কারণ দেরি করানো message ক্রম টপকে যেত।
  • S3 event notification FIFO queue-তে পাঠাতে পারে না (লেসন ১০.৭, S3 event)। S3 event EventBridge-এ পাঠাও, সেখান থেকে FIFO queue-তে (EventBridge আসবে অধ্যায় ১৯-এ, EventBridge)।
  • SNS FIFO topic ক্রম মানা, duplicate-ছাড়া message কয়েকটা SQS queue-তে ছড়িয়ে দিতে পারে; এটা পড়বে লেসন ১৩.৪-এ (SNS, Fan-out আর Message Filtering)।
  • In-flight-এর সীমা: receive হয়েছে কিন্তু delete হয়নি এমন message ১,২০,০০০ পর্যন্ত (AWS ২০২৪-এ ২০,০০০ থেকে বাড়িয়েছে); তার বেশি হলে SQS কোনো error দেয় না, কিন্তু process ধীর হয়ে যায়।
  • Elastic Beanstalk worker environment FIFO queue নিতে পারে, কিন্তু periodic task (cron.yaml) FIFO-তে চলে না (লেসন ৯.৪, Elastic Beanstalk)।
  • দাম: FIFO request একটু বেশি দামি (us-east-1-এ প্রতি ১০ লাখে প্রায় $0.50, standard-এ প্রায় $0.40), আর payload-এর প্রতিটা ৬৪ KB টুকরো একটা request হিসেবে গোনা হয়। FIFO-র হারে দাম লাগে শুধু send, receive, delete আর visibility বদলানোর call-এ।
  • পাশের কথা, fair queue (জুলাই ২০২৫): এখন standard queue-তেও MessageGroupId দেখতে পারো। সেখানে এর মানে ক্রম না: এটা tenant চিহ্নিত করে, আর SQS-এর fair queue একজন হইচই করা tenant-কে বাকি সবার দেরি করাতে দেয় না, standard-এর throughput ঠিক রেখেই। পরীক্ষার জন্য “message group ID” মানে এখনো FIFO queue।

#কখন standard-ই ঠিক উত্তর

FIFO “ভালো” queue না; এটা বেশি নিশ্চয়তা আর কম সীমার queue। Standard বেছে নাও যখন:

  • ক্রমে কিছু যায় আসে না, অথবা consumer নিজেই ক্রম ঠিক করে নিতে পারে (প্রতিটা message-এ timestamp বা version থাকে, আর consumer পুরনো version উপেক্ষা করে)।
  • কাজটা idempotent, তাই মাঝে মধ্যে duplicate এলেও ক্ষতি নেই (thumbnail বানানো, cache invalidation পাঠানো, document index করা)।
  • Throughput খুব বেশি বা হঠাৎ লাফায়, আর তুমি message group-এর design নিয়ে মাথা ঘামাতে চাও না।
  • উৎস শুধু standard queue চেনে, যেমন S3 event notification।

FIFO বেছে নাও যখন একই জিনিসের ওপর কাজের ক্রমটাই সঠিকতার অংশ (টাকা, stock, state machine, device-এ command), বা duplicate একেবারেই চলবে না, আর চাপটা সীমার মধ্যে আঁটে (batch বা high-throughput mode দিয়ে)। যদি key ধরে ক্রম, অনেক বেশি volume, আর কয়েকজন consumer-কে একই ডেটা আবার পড়তে দেওয়ার (replay) সুবিধা লাগে, তাহলে লেসন ১৩.৫-এর Kinesis Data Streams দেখো (Kinesis Data Streams); লেসন ১৩.৭ সবগুলো পাশাপাশি তুলনা করে।

Standard নাকি FIFO?

একটা scenario বেছে নাও, আন্দাজ করো, তারপর কারণটা পড়ো। পরীক্ষার শব্দগুলো: “ক্রম জরুরি”, “duplicate চলবে না” → FIFO; “সর্বোচ্চ throughput”, “ক্রমে কিছু যায় আসে না” → standard; ক্রম লাগবে আর সেকেন্ডে ৩,০০০-এর বেশি → high-throughput FIFO।

১. একটা scenario বেছে নাও(প্রথমবারেই ঠিক: 0/8)

ঢাকার একটা mobile wallet top-up, transfer আর bill payment পাঠায় একটা ledger service-এ। যে top-up দিয়ে টাকা আসবে, তার আগেই payment বসলে সেটা বাতিল হয়, আর একটা top-up দুবার বসলে টাকা আকাশ থেকে আসে। সবচেয়ে ব্যস্ত সময়ে সেকেন্ডে মোটামুটি ১৫০টা event।

২. তোমার উত্তর

#কোথায় গোলমাল হয়

লক্ষণসম্ভাব্য কারণসমাধান
SendMessage parameter নেই বলে ব্যর্থMessageGroupId নেই, অথবা content-based deduplication বন্ধ অথচ deduplication ID নেইসবসময় group ID পাঠাও; deduplication ID পাঠাও বা content-based deduplication চালু করো
Queue বানানো ব্যর্থ, বা “FIFO” queue standard-এর মতো আচরণ করছেনামে .fifo নেই, অথবা FifoQueue দেওয়া হয়নি (পরে রূপান্তর করা যায় না)FifoQueue=true দিয়ে ….fifo নামের নতুন queue বানাও, traffic সেখানে সরাও
অনেক consumer, কিন্তু ব্যস্ত মাত্র একজনপ্রতিটা message-এ একই group IDআরও সরু group key নাও: যে এককে সত্যিই ক্রম লাগে
একজন গ্রাহকের message কিছুক্ষণ থেমে থাকে, বাকিরা চলেওই group-এর একটা message in flight: ধীর consumer বা crash, visibility timeout-এর অপেক্ষাVisibility timeout ঠিক করো; লম্বা কাজে বাড়িয়ে নাও
একটা group কখনো এগোয় না; একই message বারবার ব্যর্থPoison message, head-of-line blockingFIFO DLQ-তে redrive policy, অথবা ক্রম বেশি জরুরি হলে alarm দিয়ে ঠিক করো
একটা সত্যিকারের দ্বিতীয় message কোনো error ছাড়াই হারিয়ে গেলContent-based deduplication চালু, ৫ মিনিটের মধ্যে হুবহু একই bodyBody-তে অনন্য ID রাখো, বা নিজে deduplication ID পাঠাও
Producer একই ID দিলেও duplicate এলRetry এসেছে ৫ মিনিটের পরে, অথবা দুটো আলাদা deduplication scope বা group-এRetry ৫ মিনিটের মধ্যে রাখো; consumer idempotent করো
Duplicate পাঠানো হয়নি, তবু কাজ দুবার হলোConsumer visibility timeout-এর আগে delete করেনিলম্বা timeout, ChangeMessageVisibility, idempotent processing
সেকেন্ডে ৩০০ request-এর কাছে throttling errorসাধারণ mode-এ প্রতি API action-এর সীমাপ্রতি call-এ ১০টা পর্যন্ত message batch করো; high-throughput mode চালু করো
High-throughput mode চালু, তবু সেকেন্ডে ৩০০ call-এর মতোআলাদা group ID খুব কম, তাই এক-দুটো partition-ই ব্যবহার হচ্ছেMessage অনেক group ID-তে ছড়াও
কোনো message-এ DelaySeconds দিলে বাতিল হয়FIFO-তে প্রতি message-এ delay চলে নাQueue-র delay নাও, বা অন্য কোথাও schedule করো
S3 bucket FIFO queue-কে notification-এর গন্তব্য হিসেবে নেয় নাS3 event FIFO queue-তে যেতে পারে নাEventBridge দিয়ে ঘুরিয়ে নাও, বা standard queue নাও
Standard queue-তে redrive বাতিল হলোFIFO DLQ শুধু FIFO queue-তেই redrive করতে পারেFIFO source বা অন্য কোনো FIFO queue-তে redrive করো

#System design-এ FIFO queue

  • Ledger আর payment। Group ID হিসেবে wallet বা account ID, deduplication ID হিসেবে transaction ID, idempotent consumer, আর DLQ শুধু তখন, যখন আটকে থাকা account ক্রম-ভাঙা account-এর চেয়েও খারাপ। প্রতি account-এ চাপ কম, account অনেক: একদম FIFO-র জায়গা।
  • Order আর workflow-এর অবস্থা। Group ID হিসেবে order ID “created → paid → shipped” ক্রমে রাখে, আর হাজার হাজার order একসাথে চলে। Ticket booking বা loan application-এর workflow-তেও একই ধরন খাটে।
  • Inventory আর catalogue sync। Group ID হিসেবে item ID, যাতে “stock ৫ করো, তারপর ৩” ঠিক সেই ক্রমেই বসে; শেষের লেখাটাই ঠিকভাবে জেতে।
  • Device-এ command। চা বাগানের সেচ controller-কে “valve ৩ খোলো” পেতে হবে “valve ৩ বন্ধ করো”-র আগে: group ID হিসেবে device ID।
  • ক্রম মেনে fan-out। কয়েকটা FIFO queue-র সামনে একটা SNS FIFO topic একই ক্রমের stream billing, notification আর analytics-এ পৌঁছে দেয় (লেসন ১৩.৪)।
  • অনেক বেশি volume-এর ক্রমের stream। সেকেন্ডে ৩,০০০ message-এর বেশি হলে অনেক group সহ high-throughput mode; replay বা একই ডেটার অনেক স্বাধীন পাঠক লাগলে Kinesis (লেসন ১৩.৫)।
  • FIFO ছোট রাখো। অনেক system শুধু যে অংশে ক্রম লাগে (ledger) সেখানেই FIFO নেয়, আর তার চারপাশের সবকিছুর জন্য (email, thumbnail, analytics) standard queue। সব জায়গায় FIFO দিলে অকারণে throughput-এর দাম দিতে হয়।

#নিজে করে দেখো

Account ID আর নামগুলো উদাহরণ। FIFO queue-র নামে .fifo suffix আর FifoQueue=true লাগে।

# 1. Content-based deduplication বন্ধ রেখে FIFO queue বানাও (আমরা নিজে ID পাঠাব)
aws sqs create-queue --queue-name payments.fifo \
  --attributes FifoQueue=true,ContentBasedDeduplication=false,VisibilityTimeout=60
# {
#     "QueueUrl": "https://sqs.ap-southeast-1.amazonaws.com/111122223333/payments.fifo"
# }
Q=https://sqs.ap-southeast-1.amazonaws.com/111122223333/payments.fifo

# 2. Group ID ছাড়া পাঠাও: ব্যর্থ হবে
aws sqs send-message --queue-url $Q --message-body '{"txn":"txn-7781","amount":1200}'
# An error occurred (MissingParameter) when calling the SendMessage operation:
# The request must contain the parameter MessageGroupId.

# 3. ঠিকভাবে পাঠাও: group = wallet, deduplication ID = transaction
aws sqs send-message --queue-url $Q --message-body '{"txn":"txn-7781","amount":1200}' \
  --message-group-id wallet-0171 --message-deduplication-id txn-7781
# {
#     "MD5OfMessageBody": "3f0e8a8b2c5d4e6f7a8b9c0d1e2f3a4b",
#     "MessageId": "5fea7756-0ea4-451a-a703-a558b933e274",
#     "SequenceNumber": "18849496460467696128"
# }

# 4. ৫ মিনিটের মধ্যে একই message "retry" করো: সফল, একই MessageId, দ্বিতীয় copy নেই
aws sqs send-message --queue-url $Q --message-body '{"txn":"txn-7781","amount":1200}' \
  --message-group-id wallet-0171 --message-deduplication-id txn-7781
aws sqs get-queue-attributes --queue-url $Q --attribute-names ApproximateNumberOfMessages
# { "Attributes": { "ApproximateNumberOfMessages": "1" } }

# 5. Attempt ID দিয়ে receive করো (call ব্যর্থ হলে আবার চেষ্টা নিরাপদ), group আর sequence দেখো
aws sqs receive-message --queue-url $Q --max-number-of-messages 10 --wait-time-seconds 20 \
  --receive-request-attempt-id try-001 \
  --message-system-attribute-names MessageGroupId SequenceNumber MessageDeduplicationId
#   "Attributes": { "MessageGroupId": "wallet-0171", "SequenceNumber": "18849496460467696128",
#                   "MessageDeduplicationId": "txn-7781" }, "ReceiptHandle": "AQEB…"

# 6. ওই message in flight থাকতে দ্বিতীয় একজন consumer wallet-0171 থেকে কিছুই পায় না
aws sqs receive-message --queue-url $Q --wait-time-seconds 5
# (কোনো output নেই: ৫ সেকেন্ড পর খালি উত্তর)

aws sqs delete-message --queue-url $Q --receipt-handle "AQEB…"

# 7. একটা FIFO dead-letter queue, তারপর source-এ redrive policy
aws sqs create-queue --queue-name payments-dlq.fifo --attributes FifoQueue=true
aws sqs set-queue-attributes --queue-url $Q --attributes '{
  "RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:ap-southeast-1:111122223333:payments-dlq.fifo\",\"maxReceiveCount\":\"5\"}"
}'

# 8. High-throughput mode চালু করো
aws sqs set-queue-attributes --queue-url $Q \
  --attributes DeduplicationScope=messageGroup,FifoThroughputLimit=perMessageGroupId

# 9. Bug ঠিক করার পর DLQ থেকে message আবার source-এ সরাও
aws sqs start-message-move-task \
  --source-arn arn:aws:sqs:ap-southeast-1:111122223333:payments-dlq.fifo \
  --destination-arn arn:aws:sqs:ap-southeast-1:111122223333:payments.fifo
# { "TaskHandle": "eyJ0YXNrSWQiOiJk…" }

কী খেয়াল করবে: ধাপ ২ দেখায় group ID বাধ্যতামূলক; ধাপ ৪ দেখায় deduplication (retry একই MessageId ফেরত দেয়, আর queue-তে তখনো একটাই message); ধাপ ৬ দেখায় group আটকে থাকা। ৬ মিনিট পরে ধাপ ৪ আবার চালাও: তখন queue-তে দুটো message। কাজ শেষে queue-গুলো মুছে ফেলো।

#সারসংক্ষেপ

মূল কথা

  • Standard queue দেয় best-effort ordering আর at-least-once delivery, সাথে প্রায় সীমাহীন throughput। FIFO queue দেয় প্রতি message group-এ কড়া ক্রম আর exactly-once processing, তবে throughput সীমিত।
  • FIFO queue-র নাম .fifo দিয়ে শেষ; type ঠিক হয় তৈরির সময় (রূপান্তর হয় না)। Visibility timeout, long polling, retention, message size আর encryption standard queue-র মতোই।
  • প্রতিটা message-এ message group ID লাগে। ক্রম থাকে group-এর ভেতরে; group-গুলো একসাথে চলে; কোনো group-এর একটা message in flight থাকলে পরেরটা অপেক্ষা করে। একসাথে কতটা চলবে = চালু group-এর সংখ্যা। যে সবচেয়ে ছোট key-তে ক্রম লাগে, সেটাই নাও।
  • Deduplication: নিজে দেওয়া message deduplication ID, অথবা content-based deduplication (শুধু body-র SHA-256)। ৫ মিনিটের interval-এর মধ্যে duplicate গ্রহণ হয়, পৌঁছায় না। নিজের ID content-based-এর ওপরে জেতে। Scope: queue বা message group।
  • Exactly-once মানে SQS duplicate যোগ করে না, আর একটা message কখনো একসাথে দুজন consumer পায় না। Visibility timeout পেরিয়ে যাওয়া consumer তবুও দুবার process করে: idempotent থাকো।
  • Throughput: প্রতি API action-এ সেকেন্ডে ৩০০ call, ১০-এর batch দিয়ে সেকেন্ডে ৩,০০০ message। High-throughput mode (deduplication scope = message group, throughput limit = প্রতি message group ID): বড় Region-এ সেকেন্ডে ৭০,০০০ call পর্যন্ত, Mumbai আর Singapore-এ ৯,০০০, partition-এ ছড়ায় group ID-র hash দিয়ে, তাই অনেক group রাখো।
  • FIFO queue-র DLQ-কে FIFO হতে হয়। একটা poison message তার group আটকে দেয় (head-of-line); DLQ-তে সরালে group খোলে, কিন্তু ওই group-এর ক্রম ভাঙে। FIFO DLQ redrive আছে ২০২৩-এর নভেম্বর থেকে।
  • FIFO-তে প্রতি message-এ delay নেই; S3 event FIFO-তে যেতে পারে না (EventBridge নাও); SNS FIFO topic আছে লেসন ১৩.৪-এ।
  • পরীক্ষার শব্দ: ক্রম জরুরি / duplicate চলবে না → FIFO; সর্বোচ্চ throughput / ক্রমে কিছু যায় আসে না → standard।