15.4
DynamoDB: Key, Capacity আর Consistency
table আর item, partition key আর sort key, RCU/WCU, on-demand বনাম provisioned, consistency আর hot partition।
30 মিনিট পড়া + Animation
টিপস: ডটেড-আন্ডারলাইন করা যেকোনো শব্দে ট্যাপ বা Hover করলে তার অর্থ দেখবে।
এই লেসন শেষে তুমি পারবে
- Amazon DynamoDB কী, সেটা বলতে (serverless NoSQL key-value আর document database, তিনটা AZ-এ replicate করা, IAM দিয়ে সুরক্ষিত), আর কখন এটা relational database-এর চেয়ে ভালো বা খারাপ মানায়, সেটা বুঝতে।
- Table, item আর attribute, ৪০০ KB-র item limit আর data type-গুলো বোঝাতে, আর primary key নকশা করতে: শুধু partition key, নাকি one-to-many data আর range query-র জন্য partition key সাথে sort key।
- Partition key কীভাবে item-কে partition-এ বসায়, কম cardinality-র key কেন hot partition বানায়, আর প্রতি partition-এ ৩,০০০ RCU আর ১,০০০ WCU-র ছাদ মানে কী, সেটা ব্যাখ্যা করতে।
- Eventually consistent আর strongly consistent read আলাদা করতে (তিনটা replica-তে কীভাবে কাজ করে, কোনটার দাম কত, কোথায় strong read পাওয়া যায় না), আর ঠিকটা বাছতে।
- যেকোনো item size, read-এর ধরন আর write-এর ধরনের জন্য RCU আর WCU হিসাব করতে, ৪ KB / ১ KB রাউন্ডিং আর transaction-এর দ্বিগুণ খরচসহ, আর সেখান থেকে মাসের bill বের করতে।
- Scan-এর বদলে Query ব্যবহার করতে, filter expression কী বাঁচায় আর কী বাঁচায় না জানতে, আর বড় scan যাতে live traffic-এর ক্ষতি না করে, সেটা সামলাতে।
- Provisioned capacity (auto scaling সহ) আর on-demand capacity-র মধ্যে বাছতে, আর এদের সীমাগুলো জানতে: auto scaling-এর দেরি, burst capacity, আগের peak-এর দ্বিগুণের নিয়ম, pre-warming, mode বদলের নিয়ম।
ProvisionedThroughputExceededExceptionআর পরীক্ষার সেই চেনা hot-partition প্রশ্নের কারণ ধরতে, আর দরকারমতো DAX, key-এর নকশা, write sharding, on-demand বা backoff দিয়ে সারাতে; adaptive capacity, transaction,PartiQLআর Standard-IA table class কোথায় বসে, তাও জানতে।
#DynamoDB আসলে কী
Chapter 7-এ আমরা relational database শিখেছি: RDS আর Aurora, যেখানে table, join, SQL আছে, আর একটা instance তুমি বাছো, মাপ ঠিক করো। অনেক serverless application-এর কিন্তু অন্য কিছু দরকার: এমন একটা database, যেখানে বাছার, patch করার বা scale করার মতো কোনো server নেই, এক হাজার item থাকুক বা একশো কোটি, কয়েক millisecond-এ উত্তর দেয়, আর bill হয় প্রতি request ধরে। সেটাই Amazon DynamoDB।
- NoSQL, key-value আর document। তুমি item রাখো, আর key দিয়ে ফেরত পড়ো। Join নেই, table জুড়ে ইচ্ছেমতো SQL query-ও নেই; application কী কী প্রশ্ন করবে, সেই হিসাবে key নকশা করতে হয়।
- Fully managed আর serverless। কোনো instance নেই, storage আগে থেকে বরাদ্দ করার ব্যাপার নেই, maintenance window নেই, patch নেই। Table বানাও, ব্যবহার শুরু করো।
- Highly available। প্রতিটা write acknowledge হওয়ার আগে Region-এর তিনটা Availability Zone-এ তিনবার জমা হয় (নিচে বিস্তারিত)। একটা AZ হারালেও acknowledge হওয়া কোনো data হারায় না।
- বিশাল workload সামলায়। প্রতি সেকেন্ডে লাখ লাখ request, লক্ষ কোটি item, এক table-এই শত শত terabyte, আর সবসময় এক অঙ্কের millisecond latency। Table-এর size-এর কার্যত কোনো সীমা নেই।
- IAM দিয়ে নিরাপত্তা। Database-এর আলাদা user বা password নেই: প্রতিটা request একটা AWS API call, IAM credential দিয়ে sign করা, তাই কে কোন table পড়বে বা লিখবে, ঠিক করে IAM policy (বা Lambda function-এর execution role)। Data সবসময় at rest encrypted থাকে।
- খরচ। হয় প্রতি request-এ দাম (on-demand), নয়তো যত capacity provision করো তার ঘণ্টা ধরে দাম, সাথে storage। প্রতি Region-এ ২৫ RCU, ২৫ WCU আর ২৫ GB-র free tier (provisioned, Standard table class) ছোট app-কে চিরকাল বিনা পয়সায় চালায়।
Database chapter-এর notes-এর এক লাইনের সারকথাটাই পরীক্ষারও: “serverless key-value store with massive scale” → DynamoDB, millisecond latency; microsecond latency চাইলে সেটা হয় DynamoDB + DAX (lesson 15.5)।
RDS / Aurora (lesson 7.1–7.4)DynamoDB
- Relational: নির্দিষ্ট schema, SQL, join, ইচ্ছেমতো query, জটিল report।
- Instance class তুমি বাছো; বড় করতে size বদলাও, পড়ার চাপ ভাগ করতে read replica।
- Connection, user আর password (বা IAM auth); থাকে তোমার VPC-র ভেতরে।
- সবচেয়ে ভালো যখন কী কী প্রশ্ন করা হবে আগে থেকে সব জানা নেই, বা data-গুলো একটা আরেকটার সাথে গভীরভাবে জড়ানো।
- Key-value আর document: শুধু key নির্দিষ্ট; প্রতিটা item-এর attribute আলাদা হতে পারে; join নেই।
- কোনো instance নেই: capacity একটা সংখ্যা মাত্র (বা প্রতি request-এ দাম), storage নিজে নিজে বাড়ে।
- IAM দিয়ে sign করা HTTPS API call; একটা public AWS endpoint (বা VPC gateway endpoint, lesson 15.5)।
- সবচেয়ে ভালো যখন access pattern জানা (ID দিয়ে user আনো, একজন driver-এর trip সময় ধরে দেখাও) আর যেকোনো scale-এ দ্রুত থাকতেই হবে।
#Table, item আর attribute
| ধারণা | এটা কী | Relational-এ যেটার সমান |
|---|---|---|
| Table | এক Region-এ item-এর একটা নামওয়ালা সংগ্রহ। এর primary key ঠিক হয় বানানোর সময়, পরে আর কখনো বদলানো যায় না। | Table |
| Item | একটা record, তার primary key দিয়ে চেনা যায়। একটা table-এ যত খুশি item থাকতে পারে। | Row |
| Attribute | Item-এর ভেতরে একটা নাম আর একটা value। Key ছাড়া কিছুই আগে থেকে ঘোষণা করতে হয় না: সময়ের সাথে attribute যোগ করা যায়, আর একই table-এর দুটো item-এর attribute পুরো আলাদা হতে পারে। | Column |
শুধু key নির্দিষ্ট বলেই DynamoDB-কে বলে schema-less: কাল থেকে নতুন item-এ একটা loyalty_points attribute যোগ করতে পারো, কোনো migration ছাড়াই; পুরোনো item-এ সেটা থাকবে না, ব্যস (না-থাকা attribute null হিসেবেও জমা হয় না)।
Data type। একটা attribute-এর value এগুলোর কোনো একটা:
- Scalar: String, Number, Binary, Boolean, Null।
- Document: List (যেকোনো value-র ক্রমানুসারে তালিকা) আর Map (ভেতরে ভেতরে নাম-value জোড়া, JSON object-এর মতো), ৩২ স্তর পর্যন্ত।
- Set: String Set, Number Set, Binary Set (একই ধরনের অনন্য value)।
৪০০ KB-র সীমা। একটা item, attribute-এর নাম আর value মিলিয়ে, সর্বোচ্চ ৪০০ KB। তাই লম্বা attribute নাম প্রতিটা item-এ জায়গা খায়। বড় জিনিস (ছবি, PDF, লম্বা log) যায় S3-এ, আর item-এ থাকে শুধু object-এর key আর অল্প কিছু metadata। ছোট item সস্তাও, কারণ capacity-র দাম ধরা হয় item-এর size দেখে।
#একটা উদাহরণ table
ঢাকার একটা quiz-game app প্রতি খেলোয়াড়ের প্রতি খেলার জন্য একটা করে item রাখে:
user_id (partition key) | game_id (sort key) | score | result | অন্য attribute |
|---|---|---|---|---|
| u-7791 | g-4421 | 92 | win | streak: 3 |
| u-7791 | g-5180 | 14 | lose | |
| u-8730 | g-1894 | 77 | win | badge: “Eid champion” |
| u-8730 | g-4521 | (খেলা শুরু হয়েছে, শেষ হয়নি: এখনো score নেই) |
দুটো row-তে u-7791, দুটোতে u-8730: তবু এরা আলাদা item, কারণ জোড়াটা (user_id, game_id) অনন্য। শেষ item-এ score-ই নেই, আর সেটা চলে। Network-এ item যায় type-সহ JSON হয়ে:
{ "user_id": {"S": "u-7791"}, "game_id": {"S": "g-4421"},
"score": {"N": "92"}, "result": {"S": "win"}, "streak": {"N": "3"} }
#Primary key: partition key আর sort key
প্রতিটা table-এর primary key দুই রকমের যেকোনো একটা, আর এই বাছাই-ই ঠিক করে কোন প্রশ্ন দ্রুত করা যাবে।
#শুধু partition key (simple primary key)
একটা attribute, যেমন user_id। Table-এ এর value অনন্য হতেই হবে: একই user_id দিয়ে দ্বিতীয়বার PutItem করলে আগের item বদলে যায়। DynamoDB value-টাকে ভেতরের একটা hash function-এ চালায়, আর ফল দেখে ঠিক হয় item কোন partition-এ (physical storage) থাকবে; এই কারণেই API এটাকে বলে HASH key। Item পড়তে হয় GetItem দিয়ে, ঠিক key দিয়ে।
#Partition key সাথে sort key (composite primary key)
দুটো attribute, যেমন driver_id + trip_time। অনেক item একই partition key ভাগ করতে পারে, যতক্ষণ জোড়াটা অনন্য। একই partition key-র সব item এক partition-এ একসাথে থাকে, একটা item collection হয়ে, sort key অনুযায়ী সাজানো (এটাই RANGE key)। এতে দুটো ক্ষমতা আসে, যা simple key-তে নেই:
- One-to-many: একজন driver, হাজারটা trip, সব একটা Query-তে।
- Sort key-র ওপর range query: দুই সময়ের
between, একটা তারিখ দিয়েbegins_with,<,>, নতুনটা আগে বা পুরোনোটা আগে।
Notes-এর পরীক্ষার কৌশল: “1-to-many relationship” বা “range query” (এক তারিখ থেকে আরেক তারিখের data) → composite primary key। আর সবসময় high cardinality-র partition key বাছো (অনেক আলাদা value, যেমন user_id), যাতে চাপ ছড়িয়ে পড়ে আর কোনো partition hot না হয়।
#Partition key কীভাবে item বসায়
একটা table অনেকগুলো partition-এ ভাগ করা, প্রতিটার হাতে hash value-এর একটা অংশ, SSD-তে রাখা আর তিনবার replicate করা। Table বড় হলে (একেকটা partition-এ মোটামুটি ১০ GB ধরে) বা throughput বাড়লে DynamoDB নিজেই partition যোগ করে, data সরিয়ে নেয়। তুমি এগুলো কখনো দেখো না, সামলাওও না, কিন্তু দুটো সংখ্যা জানতেই হবে, কারণ table-এর মোট capacity যতই হোক, এগুলো বদলায় না:
- একটা partition প্রতি সেকেন্ডে সর্বোচ্চ ৩,০০০ read unit আর ১,০০০ write unit দেয়;
- একটা item-ও তাই: একটা key কখনো এই সংখ্যা ছাড়াতে পারে না।
Item কোথায় থাকবে: ঠিক করে partition key
ঢাকার একটা ride-sharing app তার user আর trip রাখে DynamoDB-তে। Request router প্রতিটা item-এর partition key hash করে সেটাকে একটা partition-এ পাঠায়। দেখো একটা simple key, range query সহ একটা composite key, ভুল করে বাছা একটা key, আর একটা অতিরিক্ত বড় item-এর কী হয়।
পরিস্থিতি
Users table, key হলো user_id: প্রতি key-তে একটাই item, এক লাফেই খুঁজে পাওয়া যায়।
Item
user_id
u-1001
name
Hasan
phone
+880 1700-000000
App PutItem দিয়ে একজন নতুন যাত্রীকে save করে। Users table-এর primary key simple: শুধু partition key user_id। বাকি attribute-এর কোনো schema নেই; এই item-এ ঘটনাচক্রে নাম আর ফোন নম্বর আছে।
#ভালো partition key কীভাবে বাছবে
| Partition key | Cardinality | রায় |
|---|---|---|
user_id, order_id, device_id | লাখ লাখ value, request সমানভাবে ছড়ানো | ভালো |
driver_id + sort key trip_time | অনেক driver; প্রতি driver-এর trip একসাথে | ভালো, “একজন driver-এর trip সময় ধরে”-এর জন্য |
status (৩টা value), country (প্রায় সবাই বাংলাদেশে) | হাতে-গোনা কয়েকটা value | খারাপ: hot partition |
date (আজকের তারিখ) | আজকের সব write এক key-তে | খারাপ: আজকের দিনটা সবসময় hot |
Sale-এর সময় product_id | অনেক value, কিন্তু একটা product-ই বেশিরভাগ read পায় | Key ভালো, কিন্তু item hot: cache লাগবে (নিচে) |
#Item লেখা আর পড়া
রোজকার API (সবই IAM দিয়ে sign করা HTTPS call):
PutItemপুরো একটা item লেখে (নতুন বানায় বা বদলে দেয়)। Overwrite আটকাতেattribute_not_exists(user_id)-এর মতো একটা condition expression দাও; শর্ত না মিললেConditionalCheckFailedExceptionআসে, আর write capacity তবুও খরচ হয়।GetItemপুরো primary key দিয়ে একটা item পড়ে।UpdateItemকিছু attribute বদলায় (বা item বানায়), atomic counter-সহ (SET views = views + 1)। একটাversionattribute-এর ওপর শর্ত দিলে পাওয়া যায় optimistic locking: “version এখনো ৭ থাকলে তবেই update করো”।DeleteItemএকটা item মুছে দেয়।BatchGetItem(১০০টা পর্যন্ত item, ১৬ MB) আরBatchWriteItem(২৫টা পর্যন্ত put বা delete) round trip বাঁচায়, কিন্তু সব-অথবা-কিছুই-না না: যেগুলো হয়নি সেগুলো ফেরত আসে, আবার চেষ্টা করতে হয় তোমাকেই।QueryআরScanঅনেক item পড়ে (নিচে আলাদা অংশ)।
#Consistency: eventually নাকি strongly consistent read
দুই রকম read বুঝতে হলে আগে জানতে হবে DynamoDB data রাখে কীভাবে। AWS-এর documentation বলে প্রতিটা item জমা থাকে তিনটা Availability Zone-এ; নিচের খুঁটিনাটি এসেছে DynamoDB-র ভেতরের গঠন নিয়ে AWS-এর engineer-দের ২০২২ সালে প্রকাশ করা একটা research paper থেকে, তাই এটাকে ভেতরে কীভাবে কাজ করে তার একটা ছবি হিসেবে নাও, API-র প্রতিশ্রুতি হিসেবে না। প্রতিটা partition-এর তিনটা replica, তিনটা AZ-এ একটা করে, আর তার মধ্যে একটা replica ওই partition-এর leader। Write যায় leader-এর কাছে, leader বাকি দুটোতে কপি করে, আর একটা quorum, মানে তিনটার মধ্যে দুটো, নিজের log-এ টেকসইভাবে লিখে ফেললেই write acknowledge হয় (200 OK)। তৃতীয়টা কয়েক millisecond পরে ধরে ফেলে। পুরো গল্পটা এই ছোট্ট ফাঁকটুকু:
- Eventually consistent read (
GetItem,QueryআরScan-এর default): তিনটা replica-র যেকোনোটা উত্তর দিতে পারে। যে replica কয়েক millisecond পিছিয়ে, সে উত্তর দিলে তুমি আগের value পাবে। একটু পরে (সাধারণত এক সেকেন্ডের মধ্যে) আবার পড়লে নতুনটা পাবে। খরচ অর্ধেক: একটা RCU দিয়ে ৪ KB পর্যন্ত item-এর প্রতি সেকেন্ডে দুটো eventually consistent read। Latency সবচেয়ে কম, আর একটা replica না পাওয়া গেলেও কাজ চলে। - Strongly consistent read (request-এ
ConsistentRead = true): উত্তর দেয় leader, তাই read-এর আগে acknowledge হওয়া প্রতিটা write সে দেখায়। খরচ প্রতি ৪ KB-তে পুরো এক RCU, latency একটু বেশি, আর leader-কে মুহূর্তের জন্য না পাওয়া গেলে (network-এর গোলমাল, replica বদল) read একটা server error (HTTP 500) দিয়ে fail করতে পারে, যেটা SDK আবার চেষ্টা করে; অথচ eventual read তখনো চলে।
Strongly consistent read আছে শুধু table আর local secondary index-এ। Global secondary index, DynamoDB Streams, DAX-এর item cache আর (default-এ) global table-এর অন্য Region সবসময় eventually consistent (সবই lesson 15.5-এ)।
Notes বলে strong read-এ “DynamoDB আগে চেক করে ৩টি নোডেই ডেটা কপি হয়েছে কি না”। ফলটা ঠিক (সবসময় সর্বশেষ acknowledge হওয়া write দেখবে), কিন্তু ভেতরের কৌশলটা leader replica, তিনটাই চেক করা না: এই কারণেই strong read সবচেয়ে ধীর replica-র জন্য অপেক্ষা করে না।
তিনটা কপি, দুই রকম read
প্রতিটা partition তিনবার রাখা হয়, তিনটা Availability Zone-এ। একটা replica হলো leader, write সে-ই নেয়। Hasan তার profile-এর নাম Ali থেকে বদলে Hasan করল; দেখো কোন read কোন নাম দেখে।
পরিস্থিতি
Write নেয় leader; 200 OK মানে সেটা টেকসইভাবে জমা হয়েছে।
বদলানোর আগে তিনটা replica-তেই আছে name = Ali।
#Capacity unit: RCU আর WCU
DynamoDB throughput মাপে unit দিয়ে, আর দুই capacity mode-এই হিসাব একই (provisioned mode এদের বলে capacity unit, on-demand বলে request unit)।
- ১ RCU (read capacity unit) = ৪ KB পর্যন্ত একটা item-এর প্রতি সেকেন্ডে একটা strongly consistent read, বা দুটো eventually consistent read। Transactional read-এ প্রতি ৪ KB-তে লাগে দুটো RCU।
- ১ WCU (write capacity unit) = ১ KB পর্যন্ত একটা item-এর প্রতি সেকেন্ডে একটা write। Transactional write-এ প্রতি ১ KB-তে লাগে দুটো WCU।
#রাউন্ডিংয়ের নিয়ম
- Item-এর size ওপরের দিকে রাউন্ড করো: read-এ পরের ৪ KB-তে, write-এ পরের ১ KB-তে। ৪.১ KB-র item পড়তে ৮ KB-র সমান খরচ; ২.৫ KB-র item লিখতে ৩ WCU।
- Read-এর ধরন দিয়ে গুণ করো: eventual × ০.৫, strong × ১, transactional × ২। Write: সাধারণ × ১, transactional × ২।
- প্রতি সেকেন্ডের request সংখ্যা দিয়ে গুণ করো।
প্রশ্নে যে খুঁটিনাটি আসে:
GetItemআরBatchGetItemপ্রতিটা item আলাদা করে রাউন্ড করে।QueryআরScanপড়া সব item-এর size যোগ করে, তারপর মোটটা একবার রাউন্ড করে; তাই অনেকগুলো ছোট item একটা Query দিয়ে পড়া একটা একটা করে আনার চেয়ে অনেক সস্তা।UpdateItem-এর দাম ধরা হয় update-এর আগের আর পরের item-এর size-এর মধ্যে যেটা বড়, বদলের size না: ৩ KB-র item-এ একটা counter এক বাড়াতেও ৩ WCU।- কয়েকটা attribute চাইলেই (projection) read unit কমে না: পুরো item-টাই পড়া হয়।
- শর্ত না মেলা write-এও write unit খরচ হয়।
#হাতে-কলমে হিসাব
| Workload | প্রতি request-এ | প্রতি সেকেন্ডে unit |
|---|---|---|
| ৬ KB item-এর প্রতি সেকেন্ডে ১০টা strongly consistent read | ৬ → ৮ KB = ২ block × ১ = ২ RCU | ২০ RCU |
| ৬ KB item-এর প্রতি সেকেন্ডে ৮০টা eventually consistent read | ২ block × ০.৫ = ১ RCU | ৮০ RCU |
| ৩ KB item-এর প্রতি সেকেন্ডে ৫০টা transactional read | ১ block × ২ = ২ RCU | ১০০ RCU |
| ২.৫ KB item-এর প্রতি সেকেন্ডে ১২টা write | ২.৫ → ৩ KB = ৩ WCU | ৩৬ WCU |
| ১.৫ KB item-এর প্রতি সেকেন্ডে ১০টা transactional write | ২ KB × ২ = ৪ WCU | ৪০ WCU |
| ০.৫ KB-র ১২টা item ফেরত দেওয়া একটা Query, eventual | মোট ৬ KB → ৮ KB = ২ block × ০.৫ | পুরো Query-তে ১ RCU |
Unit থেকে টাকায় যেতে (US East, Standard table class): provisioned capacity-র দাম প্রতি RCU-ঘণ্টায় ০.০০০১৩ USD আর প্রতি WCU-ঘণ্টায় ০.০০০৬৫ USD; on-demand-এ প্রতি দশ লাখ read request unit-এ ০.১২৫ USD আর প্রতি দশ লাখ write request unit-এ ০.৬২৫ USD। নিচের calculator ঢাকার shop-এর Orders table-এর জন্য দুটোই হিসাব করে দেয়।
RCU আর WCU-র হিসাব
ঢাকার একটা shop-এর Orders table। Item-এর size, traffic আর read ও write-এর ধরন বেছে নাও, তারপর হিসাব করো capacity unit কত লাগবে, আর দুই capacity mode-এ ৩০ দিনের bill কত (US East-এর দাম, Standard table class)।
Item-এর size
দিনে কত ঘণ্টা ব্যস্ত
প্রতি সেকেন্ডে read
Read-এর ধরন
প্রতি সেকেন্ডে write
Write-এর ধরন
ফল দেখতে “হিসাব করো” চাপো।
Default setting-এ (৬ KB item, প্রতি সেকেন্ডে ১০০টা strongly consistent read আর ৫টা write, সারাদিন) table-এর লাগে ২০০ RCU আর ৩০ WCU। ৩০ দিনে সেটা provisioned-এ প্রায় ৩২.৭৬ USD, on-demand-এ ১১৩.৪০ USD: স্থির, পুরোপুরি ব্যবহৃত capacity provisioned-এ মোটামুটি সাড়ে তিন গুণ সস্তা। এবার busy hour ২ করে দাও, ছবিটা উল্টে যায়: on-demand নেমে আসে প্রায় ৯.৪৫ USD-তে, অথচ স্থির provisioned table তখনো ৩২.৭৬ USD দিচ্ছে এমন capacity-র জন্য, যা দিনে ২২ ঘণ্টা বসে থাকে।
#Query আর Scan
অনেক item পড়ার আগে নিজেকে জিজ্ঞেস করো: partition key কি আমি জানি?
Query পড়ে একটা partition key value-র item। তুমি দাও partition key = value (বাধ্যতামূলক, ঠিক একটা value), আর চাইলে একটা sort key-র শর্ত (=, <, <=, >, >=, between, begins_with)। DynamoDB একটা partition-এ যায়, একটা টানা, সাজানো অংশ পড়ে, আর sort key-র ক্রমে ফেরত দেয় (উল্টো ক্রম চাইলে ScanIndexForward = false)। দ্রুত, আর টাকা দিতে হয় শুধু ওই অংশটুকুর।
Scan পড়ে table-এর (বা index-এর) প্রতিটা item, একটার পর একটা partition, আর ফেরত দেয় কোনো কাজের ক্রম ছাড়াই। তুমি যা-ই ফেরত পাও, খরচ পুরো table-এর size-এর।
দুটোই প্রতি call-এ সর্বোচ্চ ১ MB পড়া data ফেরত দেয় (filter-এর আগের হিসাবে)। আরও থাকলে response-এ আসে LastEvaluatedKey, সেটাকে শুরুর key বানিয়ে আবার call করো; CLI আর SDK-র paginator এটা নিজেই করে। Limit প্রতি call-এ কতগুলো item পড়া হবে, তার সীমা বাঁধে।
Filter expression (fare > 500, city = Sylhet) লাগানো হয় item পড়ার পরে। এতে network-এ কম data ফেরত আসে, কিন্তু খরচ হওয়া capacity কমে না: ৩০০টা ফেরত দিতে যে Scan ২০ লাখ item পড়ে, তার bill হয় ২০ লাখ item-এর। Query-তে filter দিলে সস্তা পড়ে শুধু এই কারণে যে Query শুরুতেই কম পড়েছিল।
Parallel scan table-কে segment-এ ভাগ করে (TotalSegments N-এর মধ্যে Segment 0 থেকে N-1) আর N-টা worker-কে একসাথে scan করতে দেয়: একই item, একই খরচ, N গুণ দ্রুত শেষ, আর প্রতি সেকেন্ডে N গুণ capacity টানে। বড় scan চালাও peak-এর বাইরে, প্রতিটা worker-কে Limit দিয়ে বাঁধো, নয়তো table S3-এ export করে Athena দিয়ে query করো (lesson 15.5 আর lesson 17.1), যাতে কোনো read capacity-ই লাগে না।
Query নাকি Scan: একটা তাক, নাকি পুরো গুদাম
Trips table-এ ২০ লাখ trip (প্রায় ২ GB), চারটা partition-এ। দেখো কোন ধরনের read কতটা জায়গা ছোঁয়, আর টাকা দিতে হয় কিসের।
পরিস্থিতি
Partition key দেওয়া আছে: একটা partition, শুধু মেলা item।
Driver d-17-এর আজকের trip দেখাও: Query, যেখানে driver_id = d-17 আর trip_time শুরু হয় 2026-10-28 দিয়ে। Query-তে ঠিক একটা partition key value দিতেই হবে; sort key-র শর্ত ঐচ্ছিক।
Animation-এর সংখ্যাগুলো: ০.৫ KB-র ১২টা item একটা Query-তে পড়া মানে ৬ KB, রাউন্ড করে ৮ KB, তাই strongly consistent হলে ২ RCU, eventually consistent হলে ১ RCU। ২ GB-র একটা table-এর eventually consistent Scan হলো ২ GB ÷ ৪ KB = ৫,২৪,২৮৮ block × ০.৫ ≈ ২,৬২,০০০ RCU। ১,০০০ RCU-তে provisioned একটা table-এর জন্য সেটা তার পুরো read capacity-র চার মিনিটেরও বেশি, scan চলাকালীন প্রতিটা live request throttle করানোর জন্য যথেষ্ট।
#Capacity mode: provisioned নাকি on-demand
#Capacity কেন বাড়ে আর কমে
Notes-এ দুটো কারণ: traffic সামলানো আর টাকা বাঁচানো। Flash sale-এর সময় লাখো ক্রেতা একসাথে product পড়ে আর order দেয়; table-এর capacity traffic-এর চেয়ে কম হলে request throttle হয় (ProvisionedThroughputExceededException দিয়ে ফিরিয়ে দেওয়া হয়), তাই capacity বাড়াতে হয়। রাত ২টায় প্রায় কেউই কেনাকাটা করে না; সন্ধ্যার capacity রেখে দেওয়া মানে এমন capacity-র দাম দেওয়া, যা কেউ ব্যবহার করছে না, তাই সেটা কমা উচিত। এটা সামলানোর জন্য DynamoDB দুটো পথ দেয়, এদেরই বলে capacity mode।
#Provisioned capacity (auto scaling সহ)
Table (আর প্রতিটা GSI) প্রতি সেকেন্ডে কত RCU আর WCU ব্যবহার করতে পারবে, সেটা তুমি ঠিক করো, আর তার দাম দাও প্রতি ঘণ্টায়, ব্যবহার হোক বা না হোক। এর ওপরের request throttle হয়।
Traffic-এর সাথে বারবার হাতে সংখ্যা বদলানো ঝামেলা, তাই যোগ করো auto scaling (target tracking policy সহ Application Auto Scaling): একটা minimum (ধরো ১০০), একটা maximum (ধরো ৪,০০০) আর একটা target utilization (ধরো ৭০%, ২০ থেকে ৯০%-এর মধ্যে রাখা যায়)।
- ব্যবহৃত capacity পরপর দুই মিনিট target-এর ওপরে থাকলে (DynamoDB এক মিনিট করে data point পাঠায়, আর alarm বাজতে আরও কয়েক মিনিট পর্যন্ত দেরি হতে পারে) একটা CloudWatch alarm বাজে, আর Application Auto Scaling
UpdateTablecall করে capacity বাড়ায়, যাতে utilization আবার target-এ ফেরে: ৭০% target-এ ৮৪০ ব্যবহৃত RCU হয়ে যায় ৮৪০ ÷ ০.৭ = ১,২০০ RCU। বদলাতে কয়েক মিনিট লাগে, downtime ছাড়াই। - Utilization পরপর ১৫টা data point (মোটামুটি ১৫ মিনিট) target-এর নিচে থাকলে কমায়, তবে minimum-এর নিচে কখনো না। কমানোর সংখ্যা বাঁধা: প্রতিটা UTC দিনের শুরুতে ৪টা, তারপর প্রতি ঘণ্টায় আরও একটা, দিনে সর্বোচ্চ ২৭টা। বাড়ানোর কোনো সীমা নেই।
- Burst capacity: অব্যবহৃত capacity-র সর্বোচ্চ ৩০০ সেকেন্ড DynamoDB জমিয়ে রাখে, আর ছোট spike-এ সেটা খরচ করে। এটা কয়েক সেকেন্ড সামলায়, কয়েক মিনিট না।
- তাই auto scaling চলে আন্দাজযোগ্য বা ধীরে বদলানো traffic-এর পেছনে পেছনে; খাড়া, হঠাৎ spike তাকে পেছনে ফেলে দেয়, আর মাঝের ফাঁকে throttle হয়।
স্থির আর ভালোভাবে ব্যবহৃত traffic-এ provisioned mode-ই সবচেয়ে সস্তা throughput, আর reserved capacity (১ বা ৩ বছরের commitment, Standard table class) আরও কমায়। চিরস্থায়ী free tier-ও (২৫ RCU, ২৫ WCU) শুধু provisioned mode-এ খাটে।
#On-demand capacity
RCU বা WCU ঠিক করার কিছু নেই, scale করারও কিছু নেই: আসলে যতগুলো read request unit আর write request unit খরচ হলো (হিসাব RCU আর WCU-র মতোই), তার দাম দাও, আর traffic না থাকলে throughput-এর কোনো দাম নেই। ২০২৪-এর নভেম্বর-এ AWS on-demand-এর দাম ৫০% কমিয়েছে, আর তখন থেকে AWS on-demand-কে বলে বেশিরভাগ workload-এর default আর সুপারিশ করা mode; console-এও এটাই আগে থেকে বাছা থাকে।
“Capacity planning লাগে না” মানে “কোনো সীমা নেই” না। On-demand আসলে যা কথা দেয়:
- নতুন on-demand table প্রথম থেকেই প্রতি সেকেন্ডে ৪,০০০ write আর ১২,০০০ read পর্যন্ত চালাতে পারে।
- সে সাথে সাথে আগের peak-এর দ্বিগুণ পর্যন্ত সামলায়। তার ওপরের traffic-ও DynamoDB capacity যোগ করতে করতে সামলে নেয়, কিন্তু ৩০ মিনিটের ভেতরে আগের peak-এর দ্বিগুণের বেশি বাড়লে throttle হতে পারে।
- জানা কোনো event-এর জন্য (ঈদের launch, ticket sale) table pre-warm করো: ২০২৪-এর নভেম্বর থেকে
UpdateTableদিয়ে তার warm throughput প্রত্যাশিত মাত্রায় তুলে রাখা যায়, নয়তো traffic অন্তত ৩০ মিনিট ধরে বাড়াও। - Default table quota প্রতি সেকেন্ডে ৪০,০০০ read আর ৪০,০০০ write request unit (বাড়ানো যায়)। খরচ সামলাতে প্রতিটা on-demand table-এ একটা maximum throughput-ও বেঁধে দিতে পারো।
- প্রতি partition আর প্রতি item-এর ছাদ (৩,০০০ / ১,০০০) তখনো খাটে: on-demand hot key সারায় না।
#এক mode থেকে আরেক mode-এ যাওয়া
Notes বলে mode বদলানো যায় প্রতি ২৪ ঘণ্টায় একবার। নিয়মটা এখন ঢিলে হয়েছে: আজ একটা table provisioned থেকে on-demand-এ যেকোনো ২৪ ঘণ্টায় চারবার পর্যন্ত নেওয়া যায়, আর on-demand থেকে provisioned-এ যখন খুশি। পুরোনো প্রশ্নে এখনো “২৪ ঘণ্টায় একবার” থাকতে পারে; কোনো বিকল্প যদি প্রতিদিন একবার এদিক-ওদিক করার ওপর দাঁড়িয়ে থাকে, দুই নিয়মেই সেটা চলে।
Provisioned (+ auto scaling)On-demand
- RCU / WCU তুমি ঠিক করো (min, max, target ৭০%); যা ঠিক করা আছে তার ঘণ্টা ধরে দাম।
- স্থির, আন্দাজযোগ্য, বেশি ব্যবহৃত traffic-এ সবচেয়ে সস্তা; reserved capacity; free tier।
- Auto scaling সাড়া দেয় কয়েক মিনিটে; burst capacity কয়েক সেকেন্ড সামলায়; হঠাৎ spike-এ throttle।
- ঠিক করা সংখ্যার ওপরে throttle (
ProvisionedThroughputExceededException)।
- ঠিক করার কিছু নেই; দাম প্রতি request-এ; traffic শূন্য হলে দাম শুধু storage-এর।
- আন্দাজের বাইরে, হঠাৎ লাফানো বা অজানা traffic, নতুন app, dev আর test, দিনের বেশিরভাগ সময় বসে থাকা table-এর জন্য সেরা। ২০২৪ থেকে default আর সুপারিশ করা।
- আগের peak-এর ২ গুণ পর্যন্ত সাথে সাথে; ৩০ মিনিটের ভেতরে তার বেশি বাড়লে throttle হতে পারে; জানা event-এর আগে pre-warm।
- প্রতি unit-এ পুরোপুরি ব্যবহৃত provisioned capacity-র প্রায় সাড়ে তিন গুণ দাম, তাই provisioned capacity মোটামুটি ৩০%-এর কম ব্যবহার হলে on-demand-ই সস্তা।
Auto scaling সহ provisioned, নাকি on-demand
একটা online shop-এর Products table: একটা সাধারণ দিন, হঠাৎ flash sale, নিরিবিলি রাত আর ঈদের launch। Stage-এর নিচের table-এ দেখো প্রতি সেকেন্ডে কত read চাওয়া হলো, আর ওই মুহূর্তে table-এর capacity কত ছিল।
পরিস্থিতি
Target tracking ব্যবহৃত capacity-কে ৭০%-এর কাছে ধরে রাখে।
Products table
| সময় | Traffic | Capacity | ফল |
|---|---|---|---|
| 09:00 | 300 | 500 | ৬০% ব্যবহৃত, ঠিক আছে |
Provisioned mode: RCU আর WCU তুমি ঠিক করো, আর প্রতি ঘণ্টায় তার দাম দাও, ব্যবহার হোক বা না হোক। Auto scaling চালু: সর্বনিম্ন ১০০, সর্বোচ্চ ৪,০০০ RCU, target utilization ৭০%। সকাল ৯টায় table-এর আছে ৫০০ RCU, ক্রেতারা ব্যবহার করছে ৩০০।
#Throttling আর hot partition
#Throttling দেখতে কেমন
কোনো request-এর যতটা capacity দরকার ততটা না থাকলে DynamoDB তাকে HTTP 400 আর ProvisionedThroughputExceededException দিয়ে ফিরিয়ে দেয় (নামটা পুরোনো আমলের: on-demand table-ও কোনো partition বা table-এর maximum ছাড়ালে এটাই দেয়)। AWS SDK throttle হওয়া request নিজে থেকেই exponential backoff আর jitter দিয়ে আবার চেষ্টা করে (প্রায় ৫০ ms অপেক্ষা, তারপর ১০০, তারপর ২০০, প্রতিবার তার একটা random অংশ, যাতে হাজারটা client একই তালে retry না করে)। ছোট burst এভাবেই হজম হয়ে যায়; কিন্তু throttling থামেই না যদি, তাহলে retry শুধু চাপ বাড়ায়, আসল সমাধান capacity বা key-এর নকশা। CloudWatch-এ এটা দেখা যায় ReadThrottleEvents / WriteThrottleEvents হিসেবে, আর DynamoDB-র জন্য CloudWatch Contributor Insights দেখায় কোন key সবচেয়ে বেশি পড়া হচ্ছে আর সবচেয়ে বেশি throttle হচ্ছে।
কারণ দুই রকম, আর সমাধানও আলাদা:
| কারণ | লক্ষণ | কীসে সারে |
|---|---|---|
| Table-এ capacity কম পড়েছে: মোট traffic provisioned RCU/WCU ছাড়িয়েছে | সব key throttle হয়; ব্যবহৃত capacity ১০০% | Auto scaling, বেশি maximum, on-demand, pre-warming |
| Hot partition / hot key: অল্প কয়েকটা key বেশিরভাগ traffic পাচ্ছে | Throttle হচ্ছে, অথচ table-এর মোট capacity-র বেশিরভাগ অব্যবহৃত | Key-এর নকশা, hot read-এর জন্য cache (DAX), hot write-এর জন্য write sharding বা queue |
#Burst আর adaptive capacity
Adaptive capacity সবসময় চালু, বিনা খরচে। Access অসমান হলে সে সাথে সাথে ব্যস্ত partition-কে table-এর বাকি অংশের অব্যবহৃত capacity ব্যবহার করতে দেয়, আর কয়েকটা item টানা hot থাকলে সেগুলোকে আলাদা partition-এ সরিয়ে দেয়, যাতে প্রতিবেশীর সাথে সীমা ভাগ করতে না হয়। যেটা সে পারে না, তা হলো ছাদ তোলা: একটা partition, আর তাই একটা item, প্রতি সেকেন্ডে সর্বোচ্চ ৩,০০০ RCU আর ১,০০০ WCU-ই পায়। Burst capacity-র সাথে মিলে এই কারণেই মাঝারি অসমতা খুব কমই ক্ষতি করে, আর চরম অসমতা তবুও করে।
#ঈদের sale-এর প্রশ্ন
Notes-এর সেই চেনা পরীক্ষার প্রশ্ন, ঢাকার প্রেক্ষাপটে: একটা e-commerce site DynamoDB ব্যবহার করে। গত বছর ঈদের sale-এ (মূল প্রশ্নে Christmas) কয়েকটা খুব জনপ্রিয় item বারবার পড়া হচ্ছিল, আর table ProvisionedThroughputExceededException দিচ্ছিল। এ বছর এটা কীভাবে ঠেকাবে?
আসল কারণ। সবাই একই কয়েকটা product item পড়ছিল। প্রতিটা item থাকে একটা partition-এ, তাই সেই partition-গুলোতে যতটা read আসছিল, তারা তার চেয়ে অনেক কম দিতে পারে (hot partition, বা hot key), অথচ পুরো table-এ capacity বাড়তি পড়ে ছিল। সংখ্যায়: ২ KB-র একটা product item-এর প্রতি সেকেন্ডে ৮,০০০টা eventually consistent view মানে এক key-তে ৪,০০০ RCU; ছাদ ৩,০০০, তাই প্রায় এক-চতুর্থাংশ read fail করে।
উত্তরগুলো, পরীক্ষা যে ক্রমে চায়:
- DynamoDB Accelerator (DAX)। DynamoDB-র জন্যই বানানো in-memory, write-through cache, একই API বোঝে: app শুধু client আর endpoint বদলায়, আর কিছু না। Item-এর প্রথম read একটা miss, DAX সেটা table থেকে আনে; পরের হাজারটা hit, memory থেকে microsecond-এ উত্তর। Hot key আর table পর্যন্ত পৌঁছায় না, throttling থামে, RCU-র bill কমে। “Read often”, “popular item”, “read-এ hot partition”, “microsecond latency”, “minimal code changes” → DAX। (ElastiCache-ও cache করত, কিন্তু প্রতিটা cache read আর invalidation-এর জন্য application-এ code লিখতে হয়। DAX বিস্তারিত: lesson 15.5।)
- On-demand mode, বা বেশি maximum সহ auto scaling (notes-এর দ্বিতীয় আর তৃতীয় উত্তর)। এগুলো সারায় পুরো table-এর capacity-র ঘাটতি, আর কোনো প্রশ্ন যদি শুধু এগুলোই বিকল্প হিসেবে দেয়, তাহলে এদের একটাই উত্তর। কিন্তু প্রতি item-এর ৩,০০০ RCU-র ছাদ এরা তোলে না, তাই সত্যিকারের hot item-এর জন্য শুধু এগুলো যথেষ্ট না। Notes-এর “on-demand-এ কখনো throttle হয় না” কথাটা বাড়াবাড়ি।
- নিজের তৈরি অসমতার জন্য (
statusবাdatekey) key-এর নকশা ঠিক করা: high cardinality-র partition key। - Client-এ exponential backoff: ক্ষণিকের spike-এর জন্য ঠিক, রোগ সারানোর ওষুধ না।
Hot traffic যদি write হয়, DAX কাজে আসে না: সে write সোজা table-এ পাঠিয়ে দেয়, তাই প্রতিটা vote বা counter-এর update তবুও একই key-তে পড়ে। একটা reality show-তে প্রতি সেকেন্ডে ২,৫০০ দর্শক প্রতিযোগী ৭-কে vote দিলে, ব্যবহার করো write sharding (key-এর শেষে ১ থেকে ১০-এর একটা random suffix: votes#7#1 … votes#7#10, তাহলে প্রতিটা shard-এ প্রতি সেকেন্ডে প্রায় ২৫০ write, আর পড়ার সময় দশটা shard যোগ করো), নয়তো vote-গুলো একটা SQS queue-তে রাখো (lesson 13.1) আর একটা consumer সমান হারে লিখুক, বা memory-তে জমিয়ে শুধু মোট সংখ্যা লেখো।
ঈদের sale-এর hot partition, আর কীসে সারে
গত ঈদে shop-এর table ProvisionedThroughputExceededException দিয়েছিল, অথচ মোট capacity ছিল যথেষ্ট। কয়েকটা খুব জনপ্রিয় product বারবার পড়া হচ্ছিল। কেন হলো দেখো, আর সমাধানগুলো তুলনা করো।
পরিস্থিতি
একটা item এত read পায়, যা একটা partition দিতে পারে না।
Table-এ provisioned আছে ১২,০০০ RCU। মাঝরাতে একটা ফোনের, মানে item p-501-এর, ঈদ অফার চালু হলো, আর প্রতি সেকেন্ডে ৮,০০০ ক্রেতা তার ২ KB-র page খুলছে।
#পাশের কথা: transaction, SQL syntax আর table class
#Transaction
একই account আর Region-এর item আর table জুড়ে DynamoDB ACID transaction দেয়। TransactWriteItems সর্বোচ্চ ১০০টা put, update, delete আর condition-check (৪ MB পর্যন্ত) এমনভাবে বাঁধে যে সব একসাথে সফল হয়, নয়তো একসাথে fail; TransactGetItems ১০০টা পর্যন্ত item একটা consistent snapshot হিসেবে পড়ে। উদাহরণ: একটা order, যেটা Products-এ stock কমায়, Orders-এ order ঢোকায় আর Wallets-এ টাকা কাটে, সব-অথবা-কিছুই-না। খরচ দ্বিগুণ (প্রতি ১ KB লেখায় ২ WCU, প্রতি ৪ KB পড়ায় ২ RCU), কারণ প্রতিটা item আগে prepare হয়, তারপর commit; বাতিল হওয়া transaction-এরও দাম কাটে। টাকা বা stock যেখানে জড়িত, সেখানে ব্যবহার করো, প্রতিটা write-এ না।
#PartiQL দিয়ে SQL-এর মতো লেখা
DynamoDB একটা SQL-compatible query language-ও বোঝে, PartiQL (ExecuteStatement, BatchExecuteStatement, ExecuteTransaction, আর console-এ একটা query editor):
SELECT * FROM "Trips" WHERE driver_id = 'd-17' AND trip_time BETWEEN '2026-10-28T08:00' AND '2026-10-28T12:00'
এটা একই operation-এর শুধু আলাদা লেখার ঢং: partition key-এর ওপর WHERE দিলে সেটা Query হয়ে যায়, আর সেটা ছাড়া SELECT হয়ে যায় একটা পুরো Scan, একই খরচে। Join তখনো নেই।
#Table class: Standard আর Standard-IA
প্রতিটা table-এর একটা table class থাকে। বেশিরভাগ table-এর জন্য Standard (default)-ই ঠিক। Standard-Infrequent Access (Standard-IA) data রাখে ৬০% কম দামে (US East-এ প্রতি GB-মাসে ০.২৫-এর বদলে ০.১০ USD), কিন্তু প্রতিটা read আর write-এ প্রায় ২৫% বেশি নেয়। লাভ হয় যখন storage-ই খরচের বড় অংশ, মোটামুটি যখন storage-এর খরচ throughput-এর খরচের অর্ধেক ছাড়ায়: order-এর ইতিহাস, পুরোনো post, log, পুরোনো খেলার অর্জন। Performance, durability আর feature একই, API বদলায় না, আর যেকোনো ৩০ দিনে একটা table-এর class দুবার বদলানো যায়। Standard-IA-তে free tier বা reserved capacity খাটে না।
#কোথায় গোলমাল হয়
| লক্ষণ | সম্ভাব্য কারণ | সমাধান |
|---|---|---|
প্রতিটা key-তে ProvisionedThroughputExceededException, ব্যবহৃত capacity ১০০% | Table-এ capacity কম | বেশি maximum সহ auto scaling, on-demand, event-এর আগে pre-warm |
| Throttling চলছে, অথচ table-এর capacity-র বেশিরভাগ অব্যবহৃত | Hot partition বা hot item | বেশি cardinality-র key; hot read-এর জন্য DAX; hot write-এর জন্য write sharding বা SQS |
| প্রতিটা flash sale-এর শুরুতে কয়েক মিনিট throttling | খাড়া spike-এর পেছনে auto scaling পিছিয়ে; burst capacity শেষ | Sale-এর আগে minimum বাড়াও, scheduled scaling, on-demand + pre-warm |
| Launch-এর সময় on-demand table throttle করে | ৩০ মিনিটের ভেতরে traffic আগের peak-এর দ্বিগুণ ছাড়িয়েছে, বা ৪০,০০০ unit-এর table quota ছুঁয়েছে | Pre-warm (warm throughput), ধীরে বাড়াও, quota বাড়ানোর অনুরোধ |
| Save করার ঠিক পরেই app পুরোনো value দেখায় | Write-এর পরে eventually consistent read | যেখানে জরুরি সেখানে ConsistentRead = true, বা নিজের write-এর response থেকেই value নাও |
Index-এ ConsistentRead প্রত্যাখ্যান | GSI-তে strong read চাওয়া হয়েছে | GSI শুধু eventual; table পড়ো বা LSI ব্যবহার করো |
PutItem-এ ValidationException | Item ৪০০ KB-র বড় (নামও গোনা হয়) | বড় জিনিস S3-এ রাখো, item-এ তার key; attribute-এর নাম ছোট করো |
দ্বিতীয় PutItem চুপচাপ data বদলে দিল | একই primary key, কোনো শর্ত নেই | attribute_not_exists শর্ত; version attribute দিয়ে optimistic locking |
| একটা report job চালালেই live app ধীর হয়ে যায় | Scan বা parallel scan table-এর capacity খেয়ে ফেলছে | Peak-এর বাইরে Limit দিয়ে চালাও; S3-এ export করে Athena; ওই access pattern-এর জন্য GSI |
| Bill আশার চেয়ে অনেক বেশি | Filter সহ Scan, বড় item, যেখানে eventual চলত সেখানে strong read, অলস provisioned capacity | Scan-এর বদলে Query, ছোট item, eventual read, on-demand বা scale-down |
| Batch call “সফল”, কিন্তু কিছু item নেই | Throttling-এর মধ্যে BatchWriteItem unprocessed item ফেরত দিয়েছে | UnprocessedItems backoff দিয়ে আবার পাঠাও (SDK-র helper এটা করে) |
#System design-এ DynamoDB
- Default serverless database। API Gateway → Lambda → DynamoDB (lesson 15.6)-তে কোথাও কোনো server নেই, আর শূন্য থেকে scale করে; table-এ ঢোকার অনুমতি দেয় Lambda-র execution role (lesson 15.1)। RDS-এর মতো connection pool ফুরিয়ে যাওয়ার ভয় নেই (lesson 15.3)।
- Stateless EC2 বা container বহরের জন্য session state আর cart (chapter 9-এর stateless-app pattern): key
session_id, মেয়াদ শেষে মুছতে TTL (lesson 15.5)। - Access pattern থেকে key নকশা করো। আগে প্রশ্নগুলোর তালিকা বানাও (“user আনো”, “একজন driver-এর trip সময় ধরে”, “status ধরে order”), তারপর এমন partition key, sort key আর index বাছো, যাতে প্রতিটার উত্তর একটা Query-তে আসে। তালিকাটাই লিখতে না পারলে হয়তো relational database বেশি মানাবে।
- চাপ ছড়াও। High cardinality-র key; hot read-এর জন্য cache; hot write-এর জন্য sharding বা queue; অজানা traffic-এ on-demand।
- Consistency বাছো প্রতিটা read ধরে, পুরো table ধরে না: balance আর stock-এ strong, feed আর counter-এ eventual।
- বড় জিনিস S3-এ, DynamoDB-তে শুধু তার ঠিকানা; analytics চালাও S3 export-এর ওপর, Scan দিয়ে না।
- Multi-Region, stream, backup আর index পরের lesson-এ (lesson 15.5); এগুলো দিয়ে বানানো পুরো একটা serverless app আছে lesson 15.8-এ।
#নিজে করে দেখো
একটা on-demand Trips table বানাও, item লেখো আর পড়ো, আর খরচ হওয়া capacity দেখো। Output ছোট করা; নাম আর সংখ্যা উদাহরণ।
১. Composite key সহ একটা table বানাও
aws dynamodb create-table --table-name Trips-example \ --attribute-definitions AttributeName=driver_id,AttributeType=S AttributeName=trip_time,AttributeType=S \ --key-schema AttributeName=driver_id,KeyType=HASH AttributeName=trip_time,KeyType=RANGE \ --billing-mode PAY_PER_REQUEST --region ap-southeast-1"TableStatus": "CREATING", "TableArn": "arn:aws:dynamodb:ap-southeast-1:111122223333:table/Trips-example", "BillingModeSummary": { "BillingMode": "PAY_PER_REQUEST" }Table
ACTIVEহলেaws dynamodb wait table-exists --table-name Trips-exampleফিরে আসে।২. Duplicate আটকে একটা item লেখো
aws dynamodb put-item --table-name Trips-example \ --item '{"driver_id":{"S":"d-17"},"trip_time":{"S":"2026-10-28T08:05"},"from":{"S":"Mirpur"},"to":{"S":"Banani"},"fare":{"N":"320"}}' \ --condition-expression "attribute_not_exists(trip_time)" \ --return-consumed-capacity TOTAL"ConsumedCapacity": { "TableName": "Trips-example", "CapacityUnits": 1.0 }আবার চালাও, trip-টা overwrite না করে
ConditionalCheckFailedExceptionদিয়ে fail করবে। একইভাবেd-17-এর আরও দুটো trip যোগ করো,2026-10-28T10:40-এ (বনানী থেকে গুলশান) আর2026-10-28T13:15-এ (গুলশান থেকে মতিঝিল)।৩. পড়ো, eventually আর strongly consistent দুইভাবে
aws dynamodb get-item --table-name Trips-example \ --key '{"driver_id":{"S":"d-17"},"trip_time":{"S":"2026-10-28T08:05"}}' \ --return-consumed-capacity TOTAL # "CapacityUnits": 0.5 aws dynamodb get-item --table-name Trips-example \ --key '{"driver_id":{"S":"d-17"},"trip_time":{"S":"2026-10-28T08:05"}}' \ --consistent-read --return-consumed-capacity TOTAL # "CapacityUnits": 1.0একই item, default read-এ অর্ধেক দাম।
৪. একটা range Query করো, তারপর Scan-এর সাথে মেলাও
aws dynamodb query --table-name Trips-example \ --key-condition-expression "driver_id = :d AND trip_time BETWEEN :a AND :b" \ --expression-attribute-values '{":d":{"S":"d-17"},":a":{"S":"2026-10-28T08:00"},":b":{"S":"2026-10-28T12:00"}}' \ --return-consumed-capacity TOTAL"Count": 2, "ScannedCount": 2, "ConsumedCapacity": { "CapacityUnits": 0.5 }aws dynamodb scan --table-name Trips-example \ --filter-expression "#t = :c" --expression-attribute-names '{"#t":"to"}' \ --expression-attribute-values '{":c":{"S":"Sylhet"}}' --return-consumed-capacity TOTAL"Count": 0, "ScannedCount": 3, "ConsumedCapacity": { "CapacityUnits": 0.5 }তুমি টাকা দিয়েছ
ScannedCount-এর;Countহলো filter যতগুলো পার হতে দিয়েছে। লাখ লাখ item-এর table-এ এই ফারাকটাই bill।৫. Auto scaling সহ provisioned-এ যাও
aws dynamodb update-table --table-name Trips-example --billing-mode PROVISIONED \ --provisioned-throughput ReadCapacityUnits=100,WriteCapacityUnits=20 aws application-autoscaling register-scalable-target --service-namespace dynamodb \ --resource-id table/Trips-example --scalable-dimension dynamodb:table:ReadCapacityUnits \ --min-capacity 100 --max-capacity 4000 aws application-autoscaling put-scaling-policy --service-namespace dynamodb \ --resource-id table/Trips-example --scalable-dimension dynamodb:table:ReadCapacityUnits \ --policy-name trips-read-70 --policy-type TargetTrackingScaling \ --target-tracking-scaling-policy-configuration \ '{"TargetValue":70.0,"PredefinedMetricSpecification":{"PredefinedMetricType":"DynamoDBReadCapacityUtilization"}}'Policy নিজেই সেই দুটো CloudWatch alarm (scale out, scale in) বানায়, যা animation-এ দেখেছ।
৬. Event-এর জন্য pre-warm করো, তারপর গুছিয়ে ফেলো
aws dynamodb update-table --table-name Trips-example \ --warm-throughput ReadUnitsPerSecond=40000,WriteUnitsPerSecond=10000 aws dynamodb describe-table --table-name Trips-example --query "Table.WarmThroughput" # { "ReadUnitsPerSecond": 40000, "WriteUnitsPerSecond": 10000, "Status": "UPDATING" } aws dynamodb delete-table --table-name Trips-examplePre-warming-এর bill হয় বাড়ানো অংশের জন্য একবার; কাজ শেষে table মুছে দাও।
#সারসংক্ষেপ
মূল কথাগুলো
- DynamoDB = serverless NoSQL key-value আর document database: fully managed, ৩টা AZ-এ ৩টা কপি, প্রতি সেকেন্ডে লাখ লাখ request, এক অঙ্কের ms, access-এর জন্য IAM, join নেই। বড় জিনিস যায় S3-এ; একটা item সর্বোচ্চ ৪০০ KB (নাম + value)।
- Table → item → attribute, key ছাড়া schema নেই। Primary key = partition key (অনন্য, hash হয়ে একটা partition-এ যায়) বা partition key + sort key (sort key অনুযায়ী সাজানো item collection: one-to-many আর range query)। Partition key বাছো high cardinality-র।
- একটা partition, আর একটা item, সর্বোচ্চ ৩,০০০ RCU আর ১,০০০ WCU দেয়; table-এর মোট capacity একটা hot key-কে বাঁচাতে পারে না।
- Eventually consistent read (default) কয়েক millisecond আগের write মিস করতে পারে, খরচ অর্ধেক; strongly consistent (
ConsistentRead = true) পড়ে leader থেকে, পুরো দাম, বিভ্রাটের সময় ক্ষণিকের জন্য fail করতে পারে, আর GSI-তে পাওয়া যায় না। - ১ RCU = ৪ KB পর্যন্ত item-এর প্রতি সেকেন্ডে ১টা strong বা ২টা eventual read; ১ WCU = ১ KB পর্যন্ত item-এর প্রতি সেকেন্ডে ১টা write; size ওপরের দিকে রাউন্ড; transaction-এ দ্বিগুণ; Query আর Scan মোটটা রাউন্ড করে, Get প্রতিটা item।
- Query = একটা partition key value, সাজানো অংশ, সস্তা। Scan = পুরো table, ১ MB করে page, দামি; filter capacity কমায় না; parallel scan দ্রুত, সস্তা না। অন্য attribute দিয়ে খোঁজা → GSI (15.5)।
- স্থির traffic-এ provisioned + auto scaling (target ~৭০%, সাড়া দেয় কয়েক মিনিটে, দিনে ২৭বার কমানো, ৩০০ সেকেন্ডের burst); হঠাৎ লাফানো বা অজানা traffic-এ on-demand (প্রতি request-এ দাম, সাথে সাথে আগের peak-এর ২ গুণ, pre-warm, ৪০,০০০ unit-এর table quota, ২০২৪ থেকে default আর সুপারিশ করা)। On-demand-এ যাওয়া যায় ২৪ ঘণ্টায় ৪বার পর্যন্ত, ফেরা যখন খুশি।
ProvisionedThroughputExceededException: table-এ ঘাটতি → auto scaling / on-demand; hot read key → DAX; hot write key → write sharding বা SQS; সবসময় exponential backoff। Adaptive capacity প্রতি partition-এর ছাদ পর্যন্ত অসমতা সামলায়।- পাশের কথা: transaction (১০০টা item, সব-অথবা-কিছুই-না, দ্বিগুণ খরচ),
PartiQL(SQL-এর মতো লেখা, ভেতরে সেই একই Query/Scan), Standard-IA table class (storage ৬০% সস্তা, request দামি)।
আগে নিজে উত্তর দাও, তারপর ব্যাখ্যাটা পড়ো। ঠিক হলেও পড়ো, কারণ ভুল Option-গুলো কেন ভুল, সেটাও ওখানে আছে।
নিজেকে যাচাই করোপ্রশ্ন
Amazon DynamoDB-র কোন বর্ণনাটা ঠিক?
নিজেকে যাচাই করোপ্রশ্ন
DynamoDB table-এর একটা item সর্বোচ্চ কত বড় হতে পারে, আর সীমার মধ্যে কী কী গোনা হয়?
নিজেকে যাচাই করোপ্রশ্ন
একটা ride-sharing app-কে প্রতি driver-এর দুই সময়ের মাঝের trip দেখাতে হবে, নতুনটা আগে। কোন primary key সবচেয়ে মানানসই?
নিজেকে যাচাই করোপ্রশ্ন
বাংলাদেশের ৫ কোটি user-এর একটা app একটা table-এ প্রচুর write করে। কোন partition key সবচেয়ে বেশি hot partition বানানোর সম্ভাবনা রাখে?
নিজেকে যাচাই করোপ্রশ্ন
DynamoDB-র eventually consistent read সম্পর্কে কোন দুটো কথা ঠিক?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
একজন user wallet থেকে ১,০০০ টাকা তোলার পর app-কে নতুন balance দেখাতেই হবে, পুরোনোটা দেখানোর কোনো সুযোগ রাখা যাবে না। Read-টা কেমন হওয়া উচিত?
নিজেকে যাচাই করোপ্রশ্ন
৬ KB item-এর প্রতি সেকেন্ডে ১০টা strongly consistent read-এর জন্য table-এর কত RCU লাগবে?
নিজেকে যাচাই করোপ্রশ্ন
একই ৬ KB item প্রতি সেকেন্ডে ৮০বার পড়া হয়, eventually consistent। কত RCU?
নিজেকে যাচাই করোপ্রশ্ন
একটা app সাধারণ PutItem দিয়ে প্রতি সেকেন্ডে ১২টা item লেখে, প্রতিটা ২.৫ KB। কত WCU লাগবে?
নিজেকে যাচাই করোপ্রশ্ন
একটা order service প্রতি সেকেন্ডে ১০টা transactional write করে (TransactWriteItems), প্রতিটা ১.৫ KB-র একটা item ছোঁয়। প্রতি সেকেন্ডে কতগুলো write unit খরচ হয়?
নিজেকে যাচাই করোপ্রশ্ন
একটা Query ০.৫ KB-র ১২টা item ফেরত দেয়, eventually consistent। একই ১২টা item একটা BatchGetItem দিয়ে আনলে, সেটাও eventually consistent, Query-র তুলনায় খরচ কত?
নিজেকে যাচাই করোপ্রশ্ন
একটা table-এ ১ KB-র ১০,০০,০০০টা item। Filter expression city = Sylhet দিয়ে একটা Scan, eventually consistent, ৫০০টা item ফেরত দেয়। মোটামুটি কত খরচ হয়?
নিজেকে যাচাই করোপ্রশ্ন
একটা Orders table-এর partition key order_id। Support-এর লোকদের দিনে অনেকবার একজন customer-এর সব order লাগে, সবচেয়ে কম খরচে আর latency-তে। Team-এর কী করা উচিত?
নিজেকে যাচাই করোপ্রশ্ন
Scan সম্পর্কে কোন দুটো কথা ঠিক?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
একটা startup নতুন mobile app চালু করছে, কতটা traffic আসবে তার কোনো ধারণা নেই। এর DynamoDB table-এর জন্য কোন capacity setting সবচেয়ে মানানসই?
নিজেকে যাচাই করোপ্রশ্ন
একটা table দিনরাত, প্রতিদিন, প্রতি সেকেন্ডে স্থির ১,০০০টা read সামলায়, আর company সবচেয়ে কম খরচ চায়। কী ব্যবহার করা উচিত?
নিজেকে যাচাই করোপ্রশ্ন
একটা provisioned table-এর auto scaling ৭০% read utilization target করে। কয়েক মিনিট ধরে ব্যবহৃত capacity স্থির ৮৪০ RCU। Auto scaling read capacity কত করবে?
নিজেকে যাচাই করোপ্রশ্ন
একটা shop auto scaling সহ provisioned capacity ব্যবহার করে। এক তারকা তার link post করার পর দশ সেকেন্ডে read ছয় গুণ লাফায়, আর app কয়েক মিনিট throttle হয়ে তারপর সামলে ওঠে। কেন?
নিজেকে যাচাই করোপ্রশ্ন
একটা on-demand table-এর এখন পর্যন্ত সর্বোচ্চ traffic প্রতি সেকেন্ডে ৬,০০০ read। কাল মাঝরাতে একটা ঈদ campaign এক মিনিটের মধ্যে প্রতি সেকেন্ডে ৪০,০০০ read পাঠাবে। Team-এর কী করা উচিত?
নিজেকে যাচাই করোপ্রশ্ন
পড়ার notes বলে একটা DynamoDB table provisioned আর on-demand-এর মধ্যে ২৪ ঘণ্টায় মাত্র একবার বদলানো যায়। এখনকার নিয়ম কী?
নিজেকে যাচাই করোপ্রশ্ন
DynamoDB-র ওপর চলা একটা e-commerce site গত ঈদে ProvisionedThroughputExceededException পেয়েছিল, কারণ কয়েকটা খুব জনপ্রিয় product অনবরত পড়া হচ্ছিল। এ বছর এটা ঠেকানোর সবচেয়ে ভালো উপায় কী?
নিজেকে যাচাই করোপ্রশ্ন
একটা product item-এ এত read আসছে যে প্রতি সেকেন্ডে ৪,০০০ RCU লাগে। কোন দুটো পদক্ষেপ সত্যিই ওই item-এর throttling থামায়?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
একটা live television show-তে প্রতি সেকেন্ডে ২,৫০০ দর্শক প্রতিযোগী ৭-কে vote দেয়, প্রতিটা vote item votes#7-কে এক বাড়ায়। Write throttle হচ্ছে। সবচেয়ে ভালো সমাধান কী?
নিজেকে যাচাই করোপ্রশ্ন
একটা table ব্যস্ত মুহূর্তে মাঝে মাঝে এক-দুই সেকেন্ডের জন্য throttle হয়। Client application-এর কেমন আচরণ করা উচিত?
নিজেকে যাচাই করোপ্রশ্ন
DynamoDB-র adaptive capacity সম্পর্কে কোন কথাটা ঠিক?
নিজেকে যাচাই করোপ্রশ্ন
১০,০০০ WCU-র একটা table write-এ throttle হচ্ছে, অথচ CloudWatch বলছে write capacity-র মাত্র প্রায় ১৫% ব্যবহার হচ্ছে। Partition key হলো status (pending, paid, delivered)। কীসে সমস্যা মিটবে?
নিজেকে যাচাই করোপ্রশ্ন
DynamoDB transaction সম্পর্কে কোন দুটো কথা ঠিক?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
একটা table-এ ২ TB order-এর ইতিহাস, খুব কমই পড়া হয়, আর এর storage-এর খরচ read আর write-এর খরচের চেয়ে অনেক বেশি। কোন বদল bill সবচেয়ে বেশি কমাবে?
নিজেকে যাচাই করোপ্রশ্ন
পড়ার notes-এ প্রায়ই পাওয়া যায়, এমন কোন দুটো কথা ভুল বা পুরোনো?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
একটা replica-র ক্ষণিকের বিভ্রাটের সময় একটা strongly consistent GetItem HTTP 500 ফেরত দেয়, অথচ একই item-এর eventually consistent read সফল হয়। এর ব্যাখ্যা কী?
নিজেকে যাচাই করোপ্রশ্ন
একটা table ৩০ দিন দিনরাত ৬ KB item-এর প্রতি সেকেন্ডে ১০০টা strongly consistent read সামলায়। On-demand-এ প্রতি দশ লাখ read request unit-এ ০.১২৫ USD। On-demand-এ মাসের read bill কত?
নিজেকে যাচাই করোপ্রশ্ন
একই workload provisioned capacity-তে ২০০ RCU চায়। প্রতি RCU-ঘণ্টায় ০.০০০১৩ USD হলে ৩০ দিনে খরচ কত, আর তা থেকে কী বোঝা যায়?
নিজেকে যাচাই করোপ্রশ্ন
DynamoDB-র SQL-compatible query language দিয়ে একজন developer Trips table (partition key driver_id) থেকে ৫০০ টাকার বেশি ভাড়ার সব trip select করল, driver_id-এর কোনো শর্ত ছাড়া। কী হবে?