Course-এর সূচি

15.8

Serverless Architecture

মোবাইল অ্যাপের একটা to-do API, email আর thumbnail সহ সারা পৃথিবীর জন্য একটা blog, microservice, আর download-এর চাপ edge-এ সরিয়ে দেওয়া।

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

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

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

  • ধাপে ধাপে একটা serverless mobile back end দাঁড় করাতে: API Gateway, Lambda আর DynamoDB দিয়ে HTTPS-এর ওপর REST API, Cognito user pool দিয়ে sign in, identity pool দিয়ে প্রত্যেক user-এর নিজের S3 folder, ঘন ঘন read-এর জন্য DAX, আর API Gateway caching।
  • একটা global serverless website বানাতে: OAC সহ CloudFront দিয়ে S3 থেকে static file, একটা public REST API, DynamoDB global table, DynamoDB Streams, Lambda আর SES দিয়ে welcome email, আর S3 event দিয়ে thumbnail।
  • Microservice-গুলোর মধ্যে synchronous আর asynchronous pattern, service discovery, আর microservice-এর সুবিধা-অসুবিধা বুঝিয়ে বলতে, আর serverless কোন সমস্যাগুলো মেটায় সেটা দেখাতে।
  • Application একটুও না বদলে, সামনে CloudFront বসিয়ে EC2 Auto Scaling group-এর ঘাড় থেকে ভারী static download নামিয়ে দিতে।
  • পুরো chapter জুড়ে সিদ্ধান্ত নিতে: Lambda নাকি Fargate নাকি EC2, DynamoDB নাকি RDS, API Gateway নাকি ALB, Step Functions নাকি SQS দিয়ে function জোড়া; আর Well-Architected serverless প্রশ্নগুলো দিয়ে একটা design যাচাই করতে।

#পুরো architecture কেন শিখব

Lesson 15.1 থেকে 15.7-এ আমরা একবারে একটা করে service শিখেছি। কিন্তু বাস্তব system, আর পরীক্ষার বেশিরভাগ প্রশ্ন, পাঁচ-ছয়টা service একসাথে জোড়ে। প্রশ্নে একটা চাহিদার তালিকা আসে (“বেশিরভাগ সময় read”, “user file upload করবে”, “সারা পৃথিবীর reader”, “welcome email পাঠাতে হবে”), আর প্রতিটা লাইনের জন্য ঠিক টুকরোটা তোমাকে বেছে নিতে হয়। এই লেসনে চারটা পরিচিত design দেখব, প্রতিটা একটা একটা চাহিদা ধরে গড়ে তুলব, তারপর একটা chooser আর একটা checklist দিয়ে chapter শেষ করব।

প্রতিটা চাহিদাকে একটা keyword হিসেবে পড়ো, যেটা একটা service-এর দিকে আঙুল তোলে:

প্রশ্নে যে চাহিদা থাকেকোন টুকরো যোগ করবেকোথায় শিখেছ
HTTPS-এর ওপর REST API, কোনো server নাAPI Gateway + Lambda15.6, 15.1
লাখ লাখ request সামলাতে পারে এমন databaseDynamoDB15.4
Managed, serverless sign inCognito user pool15.7
User সরাসরি AWS resource ব্যবহার করবে (নিজের S3 folder)Cognito identity pool + IAM policy variable15.7
বেশিরভাগ read, DynamoDB-তে অনেক read throughputDAX15.5
একই API response বারবারAPI Gateway caching15.6
সারা পৃথিবীর জন্য static fileS3 + OAC সহ CloudFront11.1
কয়েকটা Region-এ user-এর কাছাকাছি dataDynamoDB global table (বা Aurora Global Database)15.5, 7.3
“X save হলে Y করো”DynamoDB Streams বা S3 event → Lambda15.5, 10.7
হঠাৎ চাপ সামলাও, ব্যর্থ হলে retrySQS (সাথে dead-letter queue)13.1, 13.2
একটা event, অনেক consumerSNS থেকে SQS-এ fan-out13.4
অপেক্ষা আর retry সহ অনেক ধাপের workflowStep Functions15.7

#প্রথম ঘটনা: MyTodoList mobile app

ঢাকার একটা university-র ছাত্রছাত্রীদের জন্য একটা to-do app। চাহিদাগুলো আমাদের নিজের ভাষায়:

  1. HTTPS-এর ওপর একটা REST API।
  2. Serverless architecture: patch বা scale করার মতো কোনো instance থাকবে না।
  3. User নিজের S3 folder-এ সরাসরি file পড়বে আর লিখবে।
  4. User sign in করবে একটা managed, serverless authentication service দিয়ে।
  5. User to-do লেখে, কিন্তু বেশিরভাগ সময় পড়ে।
  6. Database-কে scale করতে হবে, আর অনেক বেশি read throughput দিতে হবে।

#REST layer

মূল কাঠামোটা serverless-এর সবচেয়ে চেনা চেহারা: client → API Gateway → Lambda → DynamoDB।

  • API Gateway দেয় HTTPS endpoint, request যাচাই করে, throttle করে, আর অন্য কিছু চলার আগেই authentication যাচাই করে।
  • Lambda-তে থাকে business logic। Request এলেই শুধু চলে, bill হয় request আর millisecond ধরে।
  • DynamoDB-তে to-do থাকে userId-কে partition key করে, তাই “রিয়ার সব to-do” মানে একটা সস্তা Query, কখনো Scan না।

Sign in-এর জন্য app কথা বলে একটা Cognito user pool-এর সাথে। সে password যাচাই করে (MFA চালু থাকলে সেটাও), আর ফেরত দেয় JWT token: একটা ID token আর একটা access token, default মেয়াদ এক ঘণ্টা, সাথে একটা refresh token (default ৩০ দিন)। App token-টা Authorization header-এ পাঠায়। API Gateway method-এ বসানো একটা Cognito authorizer token-এর signature আর মেয়াদ যাচাই করে; মেয়াদ ফুরানো বা জাল token পায় 401, আর Lambda invoke-ও হয় না, bill-ও হয় না। Function user-এর ID নেয় যাচাই করা token থেকে (sub claim), request body থেকে কখনো না।

#প্রত্যেক user-কে তার নিজের S3 folder

৩ নম্বর চাহিদা বলছে user S3-এর সাথে কাজ করবে সরাসরি, Lambda হয়ে না। প্রতিটা ছবি Lambda দিয়ে পাঠালে compute-এর খরচ হতো, আর API Gateway (১০ MB) আর Lambda-র (synchronous invoke-এ ৬ MB) payload সীমায় আটকে যেত।

চিরাচরিত ভুল উত্তর হলো app-এর ভেতরে একটা IAM user-এর access key বসিয়ে দেওয়া। যে কেউ mobile app খুলে key বের করে নিতে পারে, আর সেই key দিয়ে চিরকালের জন্য সব user-এর folder খোলা যায়।

ঠিক উত্তর হলো একটা Cognito identity pool:

  1. App তার user pool token-টা identity pool-কে দেয়।
  2. Identity pool STS-কে call করে, আর তার authenticated IAM role-এর অস্থায়ী AWS credential (ঘণ্টাখানেক মেয়াদের) ফেরত দেয়।
  3. সেই role-এর policy-তে থাকে একটা policy variable, যাতে প্রত্যেক user শুধু নিজের prefix-এ পৌঁছায়:
{
  "Effect": "Allow",
  "Action": ["s3:GetObject", "s3:PutObject"],
  "Resource": "arn:aws:s3:::todo-files-example/users/${cognito-identity.amazonaws.com:sub}/*"
}

Request-এর সময় IAM সেখানে caller-এর identity ID বসিয়ে দেয়। একটাই role সব user-এর জন্য, তবু আরেক ছাত্রের folder চাইলে উত্তর আসে 403 AccessDenied। অন্য service-এও একই কৌশল চলে: dynamodb:LeadingKeys condition key দিয়ে প্রত্যেক user শুধু সেই DynamoDB item-গুলোই query করতে পারে, যাদের partition key তার নিজের ID (lesson 15.7)।

#অনেক read throughput: DAX

User বেশিরভাগ সময় পড়ে, আর পরীক্ষার সপ্তাহে হাজার হাজার জন একই list বারবার খোলে। Lambda আর table-এর মাঝে বসাও DAX (DynamoDB Accelerator):

  • এটা DynamoDB-র জন্য বানানো একটা in-memory, write-through cache, API-ও একই: code-এ শুধু client বদলায়।
  • Cache hit ফেরত আসে microsecond-এ; spike-এর সময়ও table-এর read capacity প্রায় নড়ে না।
  • Item cache-এর TTL default ৫ মিনিট।
  • DAX দেয় eventually consistent read। Strongly consistent read সরাসরি table-এ চলে যায়।
  • DAX cluster থাকে তোমার VPC-তে, তাই Lambda function-কেও সেই VPC-তে যুক্ত করতে হয় (lesson 15.3)।

#API Gateway-তে caching

যে response অনেক caller-এর জন্য একই, সেটা আরও এক ধাপ আগেই cache করো। একটা REST API stage response রেখে দিতে পারে একটা TTL পর্যন্ত (default ৩০০ সেকেন্ড, ০ থেকে ৩,৬০০)। Cache hit হলে Lambda আর DynamoDB পুরোপুরি বাদ। HTTP API-তে cache নেই; দরকার হলে REST API নাও, নয়তো সামনে CloudFront বসাও।

দুটো ফাঁদ:

  • Cache key হলো resource path আর তুমি যে parameter বেছে দাও। User-ভিত্তিক response cache করার সময় key-তে Authorization header (বা user ID) না থাকলে, এক user আরেকজনের list পেয়ে যায়।
  • Write করলে cache মোছে না। একটা POST-এর পরেও cache-এ থাকা GET TTL শেষ না হওয়া পর্যন্ত পুরনো থাকে। বদলাতে থাকা data-র জন্য ছোট TTL দাও, নয়তো client-কে Cache-Control: max-age=0 পাঠাতে দাও (তাদের execute-api:InvalidateCache অনুমতি লাগবে)।

MyTodoList: একটা serverless mobile back end, এক টুকরো এক টুকরো করে

ঢাকার একটা university-র ছাত্রছাত্রীদের জন্য একটা to-do app। User sign in করে, বেশিরভাগ সময় নিজের list পড়ে, মাঝে মাঝে লেখে, আর নিজের S3 folder-এ file রাখে। REST পথ, মেয়াদ ফুরানো token, user-এর নিজের S3 folder, DAX আর API Gateway cache, সবগুলো দেখো, প্রতিটা কোথায় ভুল হতে পারে সেটাসহ।

পরিস্থিতি

তুমি কে, সেটা প্রমাণ করে Cognito; কোনো code চলার আগেই API Gateway সেটা যাচাই করে।

Mobile app
Cognitouser + id pools
API GatewayREST · HTTPS
Lambdatodo API
DynamoDBtodos
sign in
ধাপ 1 / 6
1

চাহিদা: HTTPS-এর ওপর একটা REST API, কোনো server না, আর একটা managed sign-in service। রিয়া app খুলে email আর password দিয়ে sign in করে। App কথা বলে একটা Cognito user pool-এর সাথে, আমাদের code-এর সাথে না: password আমরা নিজেরা কোথাও রাখি না।

#Mobile ঘটনা থেকে যা শিখলাম

  • একটা serverless REST API: HTTPS, API Gateway, Lambda, DynamoDB।
  • Authentication সামলায় Cognito; কোনো code চলার আগেই API Gateway সেটা যাচাই করে।
  • Cognito identity pool app-এর user-দের অস্থায়ী, কড়াভাবে সীমিত credential দেয়, যাতে তারা সরাসরি AWS call করতে পারে (এখানে S3; DynamoDB বা Lambda-ও একইভাবে)।
  • দুই স্তরের caching: database read-এর জন্য DAX, পুরো response-এর জন্য API Gateway caching।

#দ্বিতীয় ঘটনা: MyBlog.com website

ঢাকা, লন্ডন আর টরন্টো থেকে পড়া একটা বাংলাদেশি travel blog। চাহিদাগুলো:

  1. Website-কে সারা পৃথিবীতে scale করতে হবে।
  2. Post লেখা হয় কম, পড়া হয় বেশি।
  3. Site-এর একটা অংশ শুধুই static file; বাকিটা একটা dynamic REST API।
  4. যেখানে সম্ভব cache করতে হবে।
  5. প্রত্যেক নতুন subscriber একটা welcome email পাবে।
  6. Upload করা প্রতিটা ছবির একটা thumbnail তৈরি হবে।

#Static content, সারা পৃথিবীতে আর নিরাপদে

HTML, CSS, JavaScript আর ছবি থাকে একটা S3 bucket-এ, আর CloudFront সেগুলো দেয় প্রত্যেক reader-এর কাছের edge location থেকে। একটা edge-এর কাছের প্রথম reader-এর জন্য S3 থেকে একবার আনা হয়; তারপর সবাই পায় edge cache থেকে। “কম লেখা, বেশি পড়া”, ঠিক এই চেহারার কাজের জন্যই CDN বানানো।

Bucket private রাখতে Origin Access Control (OAC) ব্যবহার করো:

  • CloudFront S3-এ পাঠানো request SigV4 দিয়ে sign করে।
  • Bucket policy s3:GetObject দেয় শুধু cloudfront.amazonaws.com principal-কে, AWS:SourceArn condition এই distribution-এর সমান হলে।
  • Block Public Access চালুই থাকে। সরাসরি S3 URL পায় 403, তাই কেউ CloudFront-এর geo restriction, WAF নিয়ম বা caching এড়িয়ে যেতে পারে না।

ফাঁদ: OAC কাজ করে bucket-এর REST endpoint-এর সাথে। CloudFront-কে S3 static website endpoint-এ পাঠালে সেটা custom origin, OAC আর চলে না, তখন bucket public করতেই হয় (lesson 10.3 আর 11.1)। OAC এসেছে পুরনো origin access identity (OAI)-এর জায়গায়।

#একটা public REST API

Comment আর like-এর সংখ্যা বদলায়, তাই এগুলো আসে API Gateway → Lambda → DynamoDB থেকে (read খুব বেশি হলে সাথে DAX)। Post যে কেউ পড়তে পারে, তাই এই API public: Cognito লাগে না। Public API-কে রক্ষা করো throttling, usage-এর সীমা আর AWS WAF দিয়ে (lesson 21.6)।

#DynamoDB global table

Reader তিন মহাদেশে। Table-টাকে global table বানাও: বেছে নেওয়া প্রতিটা Region-এ একটা replica, প্রতিটা replica read আর write দুটোই নেয়, আর পরিবর্তন asynchronously ছড়িয়ে যায়, সাধারণত এক সেকেন্ডের মধ্যে। প্রতিটা Region-এ API stack deploy করো, আর Route 53-এর latency routing আর health check দিয়ে reader-কে পাঠাও (lesson 8.3, 8.4)।

  • Default-এ Region-গুলোর মধ্যে replica eventually consistent। একই মুহূর্তে দুই Region-এ একই item-এ দুটো write হলে মীমাংসা হয় last writer wins নিয়মে, তাই একটা edit চুপচাপ হারিয়ে যায়। এটা জরুরি হলে একটা item-এর সব write একটা home Region-এ পাঠাও।
  • পাশের কথা: ২০২৫ থেকে global table-এ multi-Region strong consistency-ও আছে (তিনটা Region, বা দুটো replica আর একটা witness), data একটুও না হারানোর জন্য, বিনিময়ে write latency বেশি। তবে “global, কম latency-র read আর write” প্রশ্নে পরীক্ষার default উত্তর এখনো সাধারণ global table।
  • Relational বিকল্প হলো Aurora Global Database: একটা writer Region, বাকি secondary Region-গুলো read-only, replication সাধারণত এক সেকেন্ডের কম, আর দুর্যোগে একটা secondary-কে promote করা যায় (lesson 7.3)।

MyBlog.com: static file edge-এ, একটা public API, data দুটো Region-এ

ঢাকা, লন্ডন আর টরন্টো থেকে পড়া একটা বাংলাদেশি travel blog। Post লেখা হয় কালেভদ্রে, পড়া হয় সারাক্ষণ। দেখো CloudFront থেকে static page যাচ্ছে, এক reader CloudFront এড়িয়ে যেতে চাইছে, একটা public API read, global table দিয়ে একটা write ছড়িয়ে পড়ছে, আর একটা Region বিকল হচ্ছে।

পরিস্থিতি

একটা edge-এর কাছের প্রথম reader cache ভরে দেয়; পরের সবাই কাছ থেকেই পায়।

ap-southeast-1
eu-central-1
Reader
CloudFront
S3static file
API GatewayREST
Lambda
Global table
Replica
GET /index.html
ধাপ 1 / 3
1

HTML, CSS, JavaScript আর ছবি থাকে একটা private S3 bucket-এ। লন্ডনের এক reader home page খোলে; DNS তাকে পাঠায় সবচেয়ে কাছের CloudFront edge location-এ, সিঙ্গাপুরে না।

#Welcome email-এর পথ

Sign-up function শুধু subscriber-এর row save করে সাথে সাথে উত্তর দেয়। Email পাঠায় আলাদা একটা পথ:

  1. Users table-এ DynamoDB Streams চালু। প্রতিটা নতুন item একটা INSERT record হয়ে আসে, থাকে ২৪ ঘণ্টা, প্রতিটা item-এর ক্রম ঠিক রেখে।
  2. একটা event source mapping stream poll করে, আর record-এর একটা batch দিয়ে Welcome function-কে invoke করে। Poll করে Lambda নিজেই; তুমি দাও শুধু invocation-এর দাম।
  3. Function-এর execution role-এ ses:SendEmail অনুমতি আছে, তাই সে SDK দিয়ে Amazon SES-কে call করে। Email পাঠানোর serverless উপায় হলো SES: কোনো mail server চালাতে হয় না (lesson 25.2)।

Sign-up function-এর ভেতরেই email পাঠালে সমস্যা কী? Mail service ধীর হলে sign-up ধীর হতো, ব্যর্থ হলে sign-up-ও ব্যর্থ হতো। Stream থাকায় sign-up দ্রুত, আর email নিজে নিজেই retry হয়।

যে ব্যর্থতাটা জানা দরকার: stream-এর বেলায় Lambda default-এ ব্যর্থ batch-কে record-এর মেয়াদ ফুরানো পর্যন্ত retry করে, আর তার পেছনে shard আটকে থাকে। Retry-র সর্বোচ্চ সংখ্যা আর record-এর বয়স বেঁধে দাও, bisect batch on function error চালু করো, আর ব্যর্থগুলো পাঠাও একটা on-failure destination-এ (SQS, SNS বা S3)। নতুন AWS account-ও শুরু হয় SES sandbox-এ (প্রতিটা Region-এ আলাদা করে): production access চাওয়ার আগ পর্যন্ত শুধু verified address-এ mail যায়, ২৪ ঘণ্টায় সর্বোচ্চ ২০০টা, আর সেকেন্ডে সর্বোচ্চ ১টা।

#Thumbnail-এর পথ

লেখক ছবি upload করেন হয় CloudFront হয়ে bucket-এ (OAC upload-ও sign করে), নয়তো S3 Transfer Acceleration দিয়ে; দুই ক্ষেত্রেই byte-গুলো AWS network-এ ঢোকে কাছের একটা edge দিয়ে (lesson 10.6)।

একটা S3 event notification (s3:ObjectCreated:*) Thumbnail function-কে asynchronously invoke করে। Function ছবিটা পড়ে, ছোট একটা copy লেখে আলাদা একটা thumbnails bucket-এ, আর CloudFront দুটোই দেয়। ব্যর্থ async event দুবার আবার চেষ্টা হয়, তারপর যায় DLQ বা on-failure destination-এ।

S3 চাইলে event-গুলো SQS বা SNS-এও পাঠাতে পারে (diagram-এর ঐচ্ছিক ধাপ):

  • S3 → SQS → Lambda হঠাৎ চাপ (ভ্রমণের পর ৫০০ ছবি) ধরে রাখে, visibility timeout দিয়ে প্রতিটা ব্যর্থ ছবি আবার চেষ্টা করে, আর বিষাক্ত message রেখে দেয় dead-letter queue-তে। S3 event-এর destination হতে হবে standard queue আর topic, FIFO না।
  • S3 → SNS → কয়েকটা SQS queue একটা upload-কে অনেক consumer-এর কাছে ছড়িয়ে দেয় (thumbnail, virus scan, search index)।
  • S3 → EventBridge দেয় content দেখে filter আর অনেক target (lesson 19.5)।

যে bucket (বা prefix) function-কে চালায়, output কখনো সেখানেই লিখো না: প্রতিটা thumbnail আরেকটা thumbnail চালাবে। S3, SQS, SNS আর EventBridge custom bus-এর বেলায় Lambda-র recursive loop detection প্রায় ১৬টা invocation-এর পর শিকলটা থামায়, তবু আলাদা bucket বা prefix filter ব্যবহার করো।

MyBlog.com-এর event: একটা welcome email আর একটা thumbnail, কেউ বসে খোঁজ না নিয়েই

ওপরের সারি: নতুন subscriber save হয়, table-এর stream একটা function চালায়, আর SES welcome email পাঠায়। নিচের সারি: একটা ছবি upload হলে thumbnail function চলে, সরাসরি বা একটা SQS buffer হয়ে। তারপর দেখো email function ব্যর্থ হলে, একসাথে অনেক upload এলে, আর একটা function নিজেকেই বারবার চালালে কী হয়।

পরিস্থিতি

Sign-up code শুধু একটা row save করে; বাকিটা করে stream।

Reader
API Gateway
Sign-up
Users
Stream24 h
Welcome
SES
CloudFrontOAC
Uploads
Thumbnail
Thumbnails
POST /subscribePutItem
ধাপ 1 / 4
1

নুসরাত blog-এ subscribe করে। Sign-up function Users table-এ তার row save করে সাথে সাথে উত্তর দেয়। Email সে নিজে পাঠায় না, তাই mail service ধীর হলেও sign-up কখনো ধীর হয় না।

#এক ছবিতে পুরো website

  • Static content: S3 + CloudFront, OAC দিয়ে bucket private।
  • Dynamic content: একটা public serverless REST API (API Gateway, Lambda), Cognito নেই, কারণ পড়তে কাউকে sign in করতে হয় না।
  • Global data: DynamoDB global table (relational data হলে Aurora Global Database)।
  • Event: welcome email-এর জন্য DynamoDB Streams → Lambda (SES অনুমতিসহ role) → SES; thumbnail-এর জন্য S3 event → Lambda (সরাসরি, বা SQS কিংবা SNS হয়ে)।

#তৃতীয় ঘটনা: microservice

ঢাকার একটা online shop তার monolith ভেঙে microservice বানাতে চায়: অনেকগুলো service, যারা API দিয়ে একে অপরের সাথে কথা বলে, আর প্রত্যেকটা বানানো যার যেমন দরকার তেমন করে। উদ্দেশ্য, প্রতিটা team-এর হালকা development lifecycle: নিজের service নিজের সময়ে deploy, scale আর ঠিক করা।

একটা সাধারণ পরিবেশ দেখতে এমন, প্রতিটা service-এর Route 53-এ নিজের DNS নাম:

Serviceসামনের দরজাComputeData
catalog.example.comALBECS containerRDS
orders.example.comAPI Gateway (HTTPS)LambdaDynamoDB
search.example.comALBEC2 Auto Scaling groupElastiCache

এই স্বাধীনতাই আসল কথা: দুটো service-কে একই compute বা একই database নিতে কেউ বাধ্য করে না।

#Synchronous আর asynchronous pattern

SynchronousAsynchronous

Caller request পাঠায় আর উত্তরের জন্য অপেক্ষা করে।

  • প্রতিটা service-এর সামনে API Gateway বা একটা load balancer (ALB, NLB); REST বা gRPC call।
  • বোঝা সহজ; caller সাথে সাথে উত্তর পায়।
  • শিকল ধরে latency যোগ হতে থাকে, আর শিকলের প্রতিটা service-কে একই মুহূর্তে চালু থাকতে হয়। একটা service ধীর হলে তার সব caller আটকে যায় (cascading failure)।

Caller একটা message হাতে দিয়ে নিজের কাজে চলে যায়।

  • SQS queue, SNS topic (fan-out), Kinesis stream, EventBridge, আর S3 event-এর মতো Lambda trigger।
  • Producer আর consumer আলাদাভাবে scale করে, আলাদাভাবে ব্যর্থ হয়; consumer বন্ধ থাকলে message queue-তে অপেক্ষা করে।
  • ফলাফল eventually consistent: app কিছুক্ষণ “processing” দেখায়, আর retry, duplicate আর dead letter সামলাতে হয়।

সোজা নিয়ম: synchronous call তখনই, যখন caller-এর এই মুহূর্তেই উত্তর লাগে (checkout-এর সময় একটা item-এর দাম)। বাকি সব (shipping, invoice, loyalty point, email) হোক event। Synchronous call এড়ানো না গেলে ছোট timeout, backoff সহ retry, circuit breaker আর cache করা বিকল্প উত্তর দিয়ে সেটাকে রক্ষা করো।

#একে অপরকে খুঁজে পাওয়া: service discovery

Service-গুলোকে hard-code করা IP address ছাড়াই একে অপরকে খুঁজে পেতে হয়, কারণ container আর function আসে-যায়:

  • প্রতিটা service-এর সামনের দরজার জন্য Route 53 নাম (ALB বা API Gateway custom domain-এ alias record), ওপরের table-এর মতো।
  • AWS Cloud Map: service instance-গুলোর একটা registry, DNS বা API দিয়ে জিজ্ঞেস করা যায়; ECS task-গুলো নিজে থেকেই এতে নাম লেখায়।
  • ECS Service Connect: ECS namespace-এর ভেতরে http://catalog-এর মতো একটা নাম, সাথে একটা managed proxy যে retry আর metric যোগ করে (lesson 14.2)।
  • পাশের কথা: Amazon VPC Lattice built-in auth সহ VPC আর account পেরিয়ে service জোড়ে; পরীক্ষায় কমই আসে।

Microservice: synchronous call ব্যর্থতাকে জুড়ে দেয়, queue সেটা শুষে নেয়

ঢাকার একটা online shop তার monolith ভেঙে ফেলছে। Orders চলে API Gateway আর Lambda-তে, Catalog চলে ALB-র পেছনে ECS-এ, সাথে RDS, আর Shipping হলো একটা queue থেকে খাওয়া Lambda। প্রতিটা service-এর নিজের DNS নাম। Routing, একটা synchronous call, Catalog বন্ধ থাকলে কী হয়, আর Shipping বন্ধ থাকলে asynchronous পথে কী হয়, দেখো।

পরিস্থিতি

DNS নাম প্রতিটা service-এর সামনের দরজা দেখায়; প্রতিটা team নিজের stack বেছে নেয়।

Route 53
User
API Gatewayorders
Orders
SNSorder-placed
SQS
ALBcatalog
CatalogECS
RDS
Shipping
catalog.?ALB
ধাপ 1 / 3
1

App Route 53-কে catalog.example.com জিজ্ঞেস করে আর ALB-র ঠিকানা পায় (একটা alias record)। orders.example.com একইভাবে API Gateway-র custom domain দেখায়।

#Microservice-এর দাম, আর serverless যা মেটায়

Microservice বিনা খরচে আসে না। সাধারণ সমস্যাগুলো:

  • প্রতিটা নতুন service-এর জন্য একই খাটুনি বারবার: একটা pipeline, monitoring, একটা load balancer, একটা cluster, security setup।
  • Server ভালোভাবে ভরে না: অনেক ছোট service, প্রত্যেকের নিজের অর্ধেক-অলস instance।
  • একসাথে অনেক service-এর অনেক version চলে, তাতে test আর rollback জটিল হয়।
  • Client-এর code বাড়ে: প্রতিটা client-কে অনেক আলাদা endpoint-এর সাথে জুড়তে হয়।

Serverless pattern এই কষ্টের একটা অংশ দূর করে:

  • API Gateway আর Lambda নিজে থেকেই scale করে, আর দাম দাও যতটুকু ব্যবহার ততটুকু, তাই অলস অবস্থায় ছোট একটা service-এর খরচ প্রায় শূন্য, server density নিয়ে কাউকে মাথা ঘামাতে হয় না।
  • একটা template থেকে API clone করা যায়, পুরো environment আবার বানানো যায় (AWS Serverless Application Model, CloudFormation, CDK)।
  • API-র OpenAPI (Swagger) definition থেকে API Gateway client SDK বানিয়ে দিতে পারে, তাই client-কে হাতে integration code লিখতে হয় না।

#চতুর্থ ঘটনা: software update-এর বোঝা নামানো

বাংলাদেশের একটা accounting software কোম্পানি update file দেয় তিনটা AZ জুড়ে একটা Auto Scaling group-এর EC2 instance থেকে, একটা load balancer-এর পেছনে, file-গুলো পড়ে EFS থেকে। বছরের বেশিরভাগ সময় সব শান্ত। Release-এর দিন হাজার হাজার installation একসাথে একই ৩০০ MB file নামায়: ASG বাড়তে থাকে, EC2 থেকে network transfer আকাশ ছোঁয়, bill-ও তার পেছনে। শর্ত: application বদলানো যাবে না, কিন্তু খরচ আর CPU কমাতে হবে।

উত্তর: আগের load balancer-এর সামনে CloudFront বসাও:

  • Architecture-এ কোনো পরিবর্তন নেই: ALB হয়ে যায় CloudFront-এর origin, আর download hostname distribution-এর দিকে দেখায়।
  • Update file static: একবার একটা version publish হলে আর কখনো বদলায় না, edge-এ cache করার জন্য একদম আদর্শ।
  • EC2 instance serverless না, কিন্তু CloudFront serverless, আর আমাদের হয়ে সে-ই scale করে। প্রতিটা file origin থেকে আসে মোটামুটি প্রতি edge-এ একবার (বা regional edge cache প্রতি একবার), প্রতি customer-এ একবার না।
  • ASG প্রায় বাড়েই না, তাই EC2-ঘণ্টা, EFS throughput আর origin bandwidth-এ সাশ্রয়, আর spike edge-এ শুষে যাওয়ায় availability-ও বাড়ে।

যে দুটো বিশেষ ক্ষেত্রের জন্য design করবে:

  • নাম একই, ভেতরটা নতুন: latest.zip বদলে দিলে edge-গুলো TTL পর্যন্ত (default ২৪ ঘণ্টা) পুরনো file-ই রাখে। File-এর নামে version রাখো (update-7.2.1.zip), তাহলে প্রতিটা release একটা নতুন cache key; জরুরি অবস্থায় একটা invalidation বানাও (মাসে প্রথম ১,০০০টা path বিনা খরচে)।
  • CloudFront এড়িয়ে যাওয়া: ALB-র security group-এ শুধু CloudFront-এর managed prefix list allow করো, নয়তো CloudFront VPC origin ব্যবহার করো, যাতে ALB internal থাকতে পারে (lesson 11.2)।

Global Accelerator কেন না? সে তোমার instance পর্যন্ত network পথটা দ্রুত করে, কিন্তু cache করে না: প্রতিটা byte তখনো EC2 থেকেই আসত। File-গুলো S3-এ সরালে কেন না? সেটা কাজ করত, আরও সস্তাও হতো, কিন্তু তাতে application বদলায়, যেটা প্রশ্নে নিষেধ।

Software update: সামনে CloudFront বসাও, আর কিছু বদলাতে হবে না

বাংলাদেশের একটা accounting software কোম্পানি ALB-র পেছনে একটা Auto Scaling group-এর EC2 instance থেকে update file দেয়, file-গুলো পড়ে EFS থেকে। Release-এর দিনে হাজার হাজার মানুষ একই ৩০০ MB file নামায়। CloudFront ছাড়া আর CloudFront সহ দিনটা মিলিয়ে দেখো, তারপর দুটো বিশেষ ক্ষেত্র।

পরিস্থিতি

প্রতিটা download দেয় একটা instance; group বাড়তে থাকে, bill-ও তার পেছনে।

ASG
Customer
ALB
EC2
EC2
EFSupdate file
GET update-7.2.zipGETGET
ধাপ 1 / 3
1

সকাল ১০টায় version 7.2-এর ঘোষণা। প্রত্যেক customer-এর software একই সময়ে ALB থেকে update-7.2.zip চায়, আর দুটো instance সেটা EFS থেকে পড়ে পাঠাতে থাকে।

#পুরো chapter জুড়ে বেছে নেওয়া

ওপরের প্রতিটা ঘটনায় ঘুরেফিরে একই কয়েকটা সিদ্ধান্ত নিতে হয়েছে। এখানে সেগুলো পাশাপাশি।

#Compute: Lambda, Fargate নাকি EC2

LambdaFargate-এ ECS / EKSEC2 (বা EC2-এর ওপর ECS / EKS)
এককপ্রতি event-এ একটা functionএকটা container task বা podএকটা instance
সর্বোচ্চ চলার সময়১৫ মিনিটসীমা নেইসীমা নেই
আকার১০,২৪০ MB memory পর্যন্ত, ৬ vCPU পর্যন্ত১৬ vCPU, ১২০ GB পর্যন্তযেকোনো instance type, GPU
শূন্যে নামাহ্যাঁ, নিজে থেকেইশুধু desired count ০ করলেনা
BillRequest + GB-second ধরেঠিক করে দেওয়া vCPU আর memory-র সেকেন্ড ধরেInstance-এর সেকেন্ড ধরে, সাথে Reserved Instance, Savings Plan, Spot
কোথায় সবচেয়ে ভালোছোট, থেমে থেমে আসা, event-driven কাজসারাক্ষণ চলা service আর job, container, server ছাড়াএকটানা ২৪/৭ চাপ, GPU, বিশেষ OS বা host access

#Data: DynamoDB নাকি RDS / Aurora

DynamoDBRDS / Aurora
ModelKey-value আর document; access pattern আগে থেকেই key আর index-এ ভেবে বানানোRelational; join আর ad-hoc SQL
Scaleসেকেন্ডে লাখ লাখ request, on-demand modeVertical, সাথে read replica; Aurora Serverless v2 capacity বাড়ায়-কমায়
Lambda থেকে connectionHTTPS API, connection pool লাগে নাConnection storm: RDS Proxy ব্যবহার করো (lesson 15.3)
GlobalGlobal table, active-activeAurora Global Database, একটা writer Region
কখন নেবেAccess pattern জানা, বিশাল বা হঠাৎ-ওঠা scale, serverless stackসম্পর্কিত data, অনেক table জুড়ে transaction, report, আগের SQL code

সব ধরনের database পাশাপাশি তুলনা আছে chapter 16-এ (16.1)।

#সামনের দরজা: API Gateway নাকি ALB

API GatewayApplication Load Balancer
কীসের জন্য বানানোAPI: key, usage plan, quota, request validation, transformation, caching (REST), WebSocketEC2, container, IP বা Lambda-তে HTTP routing
AuthIAM, Cognito, Lambda authorizer, resource policyListener rule-এ Cognito বা OIDC authentication
TimeoutDefault ২৯ সেকেন্ডের integration timeout (Regional আর private REST API-তে বাড়ানো যায়)Idle timeout ৪,০০০ সেকেন্ড পর্যন্ত
দামRequest ধরে (সাথে cache-এর ঘণ্টা)ঘণ্টা আর capacity unit ধরে
কখন নেবেথেমে থেমে বা অল্প traffic-এর API, API management feature, Lambda back endএকটানা অনেক traffic, লম্বা request, container আর instance-এর বহর

#Workflow: Step Functions নাকি function-এর মাঝে SQS

Step FunctionsLambda function-এর মাঝে SQS
চেহারাঅনেক ক্রম ধরা ধাপ, শাখা (Choice, Parallel, Map)প্রতি queue-তে এক ধাপ, প্রত্যেকটা স্বাধীন
অপেক্ষাWait state, task token দিয়ে দিনের পর দিন callback (Standard: এক বছর পর্যন্ত)Message queue-তে ১৪ দিন পর্যন্ত অপেক্ষা করে
Errorপ্রতি state-এ Retry আর Catch, চোখে দেখা যায় এমন ইতিহাসVisibility timeout দিয়ে retry, dead-letter queue
দামStandard: state transition ধরে; Express: request আর সময় ধরেRequest ধরে, খুবই সস্তা
কখন নেবেOrchestration, মানুষের অনুমোদন, audit trailএকটা ধাপকে buffer আর decouple করা, বিপুল পরিমাণ কাজ

কোন serverless টুকরোটা মানায়?

পুরো chapter থেকে নয়টা বাস্তব ঘটনা। গল্প আর keyword পড়ো, যে service-গুলো এই কাজের জন্য লড়ছে তাদের মধ্যে বেছে নাও, তারপর কারণটা পড়ো।

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

Compute

ঢাকার একটা e-commerce shop-এর দরকার seller-দের upload করা প্রতিটা product ছবির একটা ছোট thumbnail। প্রতিটায় সময় লাগে ২ সেকেন্ডের মতো। কোনো ঘণ্টায় ৩,০০০ upload আসে, রাতে একটাও না।

Keyword:event-drivenকাজপ্রতি কয়েক সেকেন্ডরাতে অলস

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

#একটা Well-Architected serverless checklist

Well-Architected Framework-এর জন্য AWS একটা Serverless Applications Lens প্রকাশ করে (chapter 26, lesson 26.1)। ছোট করে, প্রতিটা pillar ধরে:

Pillarনিজেকে জিজ্ঞেস করো
Operational excellenceপুরো stack কি একটা template-এ (AWS Serverless Application Model, CloudFormation, CDK)? Version আর alias দিয়ে, ধীরে ধীরে traffic সরিয়ে deploy করি তো? Log, metric আর trace (CloudWatch, X-Ray) চালু আছে?
Securityপ্রতিটা function-এর কি নিজের least-privilege execution role আছে? API-তে authentication আছে (Cognito, IAM, Lambda authorizer), নাকি public হলে WAF দিয়ে রক্ষা করা? Secret কি Secrets Manager বা Parameter Store-এ, code-এ না? Bucket কি OAC-এর পেছনে private?
Reliabilityপ্রতিটা async পথে retry, একটা DLQ বা on-failure destination, আর idempotent consumer আছে? হঠাৎ চাপ queue দিয়ে buffer হয়? Reserved concurrency দেওয়া আছে, যাতে একটা function বাকিদের না খেয়ে ফেলে? প্রতিটা ধাপের timeout কি caller-এর চেয়ে ছোট?
Performance efficiencyMemory কি মাপমতো (এটা CPU-ও ঠিক করে)? যেখানে দরকার সেখানে cold start সামলানো হয়েছে (provisioned concurrency, SnapStart)? ঘন ঘন read কি cache হয় (CloudFront, API Gateway cache, DAX)?
Cost optimizationসম্ভব হলে Lambda কি arm64 (Graviton)-এ? DynamoDB ঠিক capacity mode-এ? একটানা ২৪/৭ workload কি বরং container বা EC2-তে যাওয়া উচিত? Log-এর retention period দেওয়া আছে?
Sustainabilityঅলস থাকলে system কি শূন্যে নামে? কম byte নাড়াচাড়া করছি তো (caching, compression, উৎসেই event filter)?

#কোথায় ভুল হয়

লক্ষণসম্ভাব্য কারণসমাধান
Mobile user অন্যের S3 file পড়তে পারেApp-এ ভাগ করা IAM user key, বা policy variable ছাড়া roleResource-এ ${cognito-identity.amazonaws.com:sub} সহ identity pool
User একে অপরের to-do list দেখেAPI Gateway cache key-তে user নেইCache key-তে Authorization header যোগ করো, নয়তো user-ভিত্তিক response cache কোরো না
DAX-এর সাথে কথা বলতে গিয়ে Lambda timeoutFunction DAX cluster-এর VPC-তে নেই, বা security group DAX port আটকায় (8111, encryption থাকলে 9111)Function-কে VPC subnet-এ যুক্ত করো, function-এর security group থেকে DAX port খুলে দাও
প্রতিটা object-এ CloudFront 403 দেয়Bucket policy এই distribution-এর ARN-কে allow করে না, বা origin হলো website endpointOAC bucket policy ঠিক করো; REST endpoint ব্যবহার করো
Welcome email বন্ধ, নতুন subscriber আটকেStream batch ব্যর্থ হচ্ছে (SES sandbox, bug), মেয়াদ না ফুরানো পর্যন্ত retryসর্বোচ্চ retry আর record-এর বয়স, bisect on error, on-failure destination; SES production access
Thumbnail function deploy করার পর bill লাফ দিলOutput লেখা হচ্ছে trigger করা bucket-এই: recursive loopআলাদা output bucket বা prefix filter
ভেতরের একটা service বন্ধ হলেই checkout ব্যর্থলম্বা synchronous call-এর শিকলজরুরি না এমন call asynchronous করো (SNS, SQS); timeout, circuit breaker
Customer পুরনো update file পায়একই file নাম আবার ব্যবহার, edge cache-এর TTL শেষ হয়নিVersion সহ file নাম; জরুরি হলে invalidation
Multi-Region blog-এ comment edit উধাওদুই Region-এ একই item-এ একসাথে write, last writer winsপ্রতিটা item একটা home Region থেকে লেখো

#System design-এ serverless architecture

  • চাহিদার তালিকা থেকে শুরু করো, আর ওপরের table-এর মতো প্রতিটা লাইনকে একটা টুকরোর সাথে মেলাও। পরীক্ষার বেশিরভাগ উত্তর ঠিক এই মেলানোটাই।
  • Request-এর পথ থেকে কাজ সরাও: user-কে দ্রুত উত্তর দাও, ধীর অংশগুলো করুক stream, S3 event আর queue।
  • যে স্তরে পারো cache করো: static আর cache-যোগ্য response-এর জন্য CloudFront, বারবার আসা API উত্তরের জন্য API Gateway caching, ঘন ঘন পড়া DynamoDB item-এর জন্য DAX।
  • নিরাপদ হলে user-কে সরাসরি AWS-এর সাথে কথা বলতে দাও (identity pool credential বা presigned URL দিয়ে S3 upload), Lambda দিয়ে byte না ঠেলে।
  • গতানুগতিক কাজে managed service নাও: sign in-এর জন্য Cognito, email-এর জন্য SES, workflow-এর জন্য Step Functions।
  • কখন serverless আর লাভজনক না, সেটা জানো: একটানা অনেক traffic, ১৫ মিনিটের বেশি কাজ, GPU, বা ভারী relational report হলে container, EC2 আর RDS-এর দিকে তাকাও।

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

MyBlog.com design-এর কয়েকটা টুকরো, ap-southeast-1-এ, account 111122223333। Output ছোট করে দেখানো।

# 1. Template থেকে একটা serverless API (API Gateway + Lambda + DynamoDB) বানিয়ে deploy করো
sam init --name blog-api-example --runtime python3.13 --app-template hello-world
sam build && sam deploy --guided
#   Outputs: ApiUrl = https://a1b2c3d4e5.execute-api.ap-southeast-1.amazonaws.com/Prod/

# 2. Users table-এ DynamoDB Streams চালু করো (welcome email-এর জন্য new image-ই যথেষ্ট)
aws dynamodb update-table --table-name blog-users-example \
  --stream-specification StreamEnabled=true,StreamViewType=NEW_IMAGE
#   "LatestStreamArn": "arn:aws:dynamodb:ap-southeast-1:111122223333:table/blog-users-example/stream/2026-10-28T09:12:44.123"

# 3. Stream-কে Welcome function-এর সাথে জোড়ো, ব্যর্থতা সামলানোর নিরাপদ setting সহ
aws lambda create-event-source-mapping --function-name welcome-email-example \
  --event-source-arn arn:aws:dynamodb:ap-southeast-1:111122223333:table/blog-users-example/stream/2026-10-28T09:12:44.123 \
  --starting-position LATEST --batch-size 10 \
  --maximum-retry-attempts 3 --maximum-record-age-in-seconds 3600 --bisect-batch-on-function-error \
  --destination-config '{"OnFailure":{"Destination":"arn:aws:sqs:ap-southeast-1:111122223333:welcome-failed-example"}}'
#   "State": "Creating", "MaximumRetryAttempts": 3, "BisectBatchOnFunctionError": true

# 4. SES দিয়ে একটা test email পাঠাও (sandbox-এ দুটো address-ই verified হতে হবে)
aws sesv2 send-email --from-email-address hello@blog.example \
  --destination ToAddresses=nusrat@reader.example \
  --content 'Simple={Subject={Data=Welcome},Body={Text={Data=Thanks for subscribing}}}'
#   "MessageId": "0100018f-example-0000"

# 5. Thumbnail চালাও শুধু uploads/-এর জন্য, যাতে thumbs/-এর output কখনো ফিরে loop না বানায়
aws s3api put-bucket-notification-configuration --bucket blog-photos-example \
  --notification-configuration '{"LambdaFunctionConfigurations":[{
     "LambdaFunctionArn":"arn:aws:lambda:ap-southeast-1:111122223333:function:thumbnail-example",
     "Events":["s3:ObjectCreated:*"],
     "Filter":{"Key":{"FilterRules":[{"Name":"prefix","Value":"uploads/"}]}}}]}'

# 6. ফ্রাঙ্কফুর্টে একটা replica যোগ করে table-কে global table বানাও
aws dynamodb update-table --table-name blog-comments-example \
  --replica-updates '[{"Create":{"RegionName":"eu-central-1"}}]'
#   "Replicas": [{"RegionName": "eu-central-1", "ReplicaStatus": "CREATING"}]

# 7. একজন mobile user identity pool থেকে অস্থায়ী credential নেয়
aws cognito-identity get-id --identity-pool-id ap-southeast-1:11111111-2222-3333-4444-555555555555 \
  --logins cognito-idp.ap-southeast-1.amazonaws.com/ap-southeast-1_Example=eyJraWQiOi...
#   "IdentityId": "ap-southeast-1:9f8e7d6c-1234-5678-9abc-def012345678"
aws cognito-identity get-credentials-for-identity \
  --identity-id ap-southeast-1:9f8e7d6c-1234-5678-9abc-def012345678 \
  --logins cognito-idp.ap-southeast-1.amazonaws.com/ap-southeast-1_Example=eyJraWQiOi...
#   "Credentials": { "AccessKeyId": "ASIAEXAMPLE", "Expiration": "2026-10-28T10:15:00+06:00", ... }

# 8. Software update: আবার ব্যবহার করা একটা file নাম সব edge থেকে invalidate করো
aws cloudfront create-invalidation --distribution-id E2EXAMPLE1234 --paths "/latest.zip"
#   "Status": "InProgress"

#সারসংক্ষেপ

মূল কথাগুলো

  • Mobile back end (MyTodoList): API Gateway → Lambda → DynamoDB দিয়ে HTTPS REST; Cognito user pool user-কে sign in করায় আর Lambda চলার আগেই API Gateway JWT যাচাই করে; Cognito identity pool অস্থায়ী credential দেয়, যা ${cognito-identity.amazonaws.com:sub} দিয়ে প্রত্যেক user-এর নিজের S3 folder-এ সীমিত, app-এ key কখনো না; অনেক read throughput-এর জন্য DAX; বারবার আসা response-এর জন্য API Gateway caching (REST API, default ৩০০ সেকেন্ড), cache key-তে user রেখে।
  • Global website (MyBlog.com): static file একটা private S3 bucket-এ, সামনে OAC সহ CloudFront (bucket policy একটা distribution-এর জন্য, শুধু REST endpoint); public REST API-তে Cognito লাগে না; global data-র জন্য DynamoDB global table (বা Aurora Global Database), conflict হলে last writer wins।
  • Event: welcome email-এর জন্য DynamoDB Streams → Lambda → SES (function-এর IAM role SES-এর অনুমতি দেয়); thumbnail-এর জন্য S3 event → Lambda, বা SQS / SNS হয়ে। আলাদা output bucket; stream retry-র সীমা; DLQ।
  • Microservice: প্রতিটা service-এর নিজের চেহারা আর নিজের DNS নাম; synchronous (API Gateway, load balancer) availability-কে জুড়ে দেয়, asynchronous (SQS, SNS, Kinesis, Lambda trigger) ব্যর্থতা শুষে নেয়; Route 53, Cloud Map, Service Connect দিয়ে service discovery। Serverless খাটুনি কমায়: নিজে থেকে scale, ব্যবহার অনুযায়ী দাম, clone করা environment, বানিয়ে দেওয়া client SDK।
  • Software update-এর বোঝা নামানো: আগের ALB-র সামনে CloudFront বসাও: application বদলায় না, static file edge-এ cache হয়, ASG প্রায় বাড়ে না, বিশাল সাশ্রয়। Global Accelerator না (cache নেই)।
  • বেছে নেওয়া: ছোট event-driven কাজে Lambda, সারাক্ষণ চলা container-এ Fargate, GPU আর একটানা চাপে EC2; জানা key access-এ বিশাল scale হলে DynamoDB, join থাকলে RDS/Aurora; API feature আর হঠাৎ traffic-এ API Gateway, একটানা traffic আর লম্বা request-এ ALB; orchestration-এ Step Functions, একটা ধাপ buffer করতে SQS।