9.2
একটা Stateful দোকান: Session, ডেটা আর Read Scaling
stickiness, cookie, server-side session, ডেটাবেস, replica আর caching, আর যে Security Group-গুলো সবকিছুকে জুড়ে রাখে।
28 মিনিট পড়া + Animation
টিপস: ডটেড-আন্ডারলাইন করা যেকোনো শব্দে ট্যাপ বা Hover করলে তার অর্থ দেখবে।
এই লেসন শেষে তুমি পারবে
- একটা web application কখন stateful হয়, আর কয়েকটা server-এ request ভাগ হলে shopping cart কেন ভেঙে পড়ে, সেটা বোঝাতে।
- একটা design-কে ধাপে ধাপে এগিয়ে নিতে: “cart server-এর memory-তে” থেকে sticky session, cookie-তে cart, তারপর ElastiCache বা DynamoDB-তে server-side session, আর প্রতিটা ধাপের দাম কী, সেটা বলতে।
- কোন ডেটা কোথায় থাকবে ঠিক করতে: স্বল্পমেয়াদি session-এর state, RDS-এ টেকসই user-এর ডেটা, আর cache-এ বারবার পড়া ডেটা।
- Read scale করতে read replica নাকি ElastiCache, বেছে নিতে, আর replica lag বা cache-এর পুরনো মান user-এর ওপর কী প্রভাব ফেলে, আগে থেকেই বলতে।
- Multi-AZ দিয়ে প্রতিটা data tier-কে AZ নষ্ট হওয়া থেকে বাঁচাতে, আর একে অন্যকে reference করা security group দিয়ে tier-গুলোকে তালাবদ্ধ করতে।
- প্রতিটা ধাপের পরীক্ষার ভাষা চিনতে: “instance terminate হলে session হারায়”, “legacy app, code বদলানো যাবে না”, “code না বদলে read scale করো”, “ডেটাবেসে ঢোকা সীমিত করো”।
#এমন দোকান, যাকে মনে রাখতে হয়
#My Cloth-এর গল্প আর তার চাহিদা
লেসন ৯.১-এর stateless app-কে শুধু সময় বলে দিতে হতো। যেকোনো server যেকোনো request-এর উত্তর দিতে পারত, কারণ কোনো উত্তর আগের কোনো উত্তরের ওপর নির্ভর করত না। এবার পরিচয় করো My Cloth-এর সাথে, একটা অনলাইন কাপড়ের দোকান। এর একটা shopping cart আছে, একই মুহূর্তে শত শত ক্রেতা, আর চাহিদাগুলো এমন:
- horizontally scale করতে হবে (বড় একটা server না, বেশি server), আর web tier-কে যতটা পারা যায় stateless রাখতে হবে;
- ক্রেতা কখনোই cart হারাবে না, কোনো server নষ্ট হলেও না, Auto Scaling কোনো server সরিয়ে দিলেও না;
- ক্রেতার তথ্য (নাম, ঠিকানা, আগের order) থাকবে একটা ডেটাবেসে;
- পুরো ব্যবস্থাটা একটা AZ হারালেও টিকে থাকবে, আর এমনভাবে তালাবদ্ধ থাকবে যে ডেটা পর্যন্ত শুধু ঠিক tier-টাই পৌঁছাতে পারে।
শুরু করব লেসন ৯.১ যেখানে শেষ হয়েছিল সেখান থেকে: কয়েকটা AZ জুড়ে একটা Auto Scaling group, সামনে একটা ALB। তারপর একটা একটা করে সমস্যায় পড়ব আর সমাধান করব, একজন solutions architect যেভাবে করেন।
#Stateless আর stateful-এর তফাত
একটা server stateless, যখন এখনকার request-এর উত্তর দিতে আগের কোনো request থেকে তার কিছুই লাগে না। আর stateful, যখন দুই request-এর মাঝে তাকে কিছু একটা মনে রাখতে হয়, এটাকেই বলে state: কে login করে আছে, cart-এ কী আছে, checkout-এর কোন ধাপে ক্রেতা আছে।
HTTP নিজে stateless; তাই state-কে কোথাও না কোথাও থাকতেই হয়: server-এর memory-তে, client-এর কাছে, অথবা একটা shared store-এ। এই বাছাইটাই ঠিক করে application কতটা ভালো scale করবে, আর একটা server মরে গেলে কী হবে। Cookie, session আর token নিয়ে সাধারণ আলোচনা আছে System Design-এর State, cookie আর session লেসনে; এই লেসনে আমরা সেগুলো AWS-এ খাটাব।
#ধাপ ১: cart থাকে server-এর memory-তে
দোকানের প্রথম version প্রতিটা cart রাখে যে server request সামলাল, তার RAM-এ (বা local disk-এ)। একটা server হলে চলে যায়। Load balancer-এর পেছনে কয়েকটা server হলেই সব ভেঙে পড়ে।
Load balancer কিন্তু ঠিক নিজের কাজটাই করছে: সে প্রতিটা request আলাদা করে ভাগ করে (লেসন ৬.৪)। ভুলটা design-এর, ALB-র না। সমস্যাটা আর পরের চারটা ধাপ, একটাই diagram-এ দেখে নাও:
My Cloth: cart কোথায় থাকে, ধাপে ধাপে
দুটো AZ-এ দুটো web server, সামনে একটা ALB। প্রতিটা tab design-এর একটা ধাপ; প্রতিটা ধাপ আগের ধাপের সমস্যা মেটায়, আবার নিজে একটা নতুন সমস্যা আনে।
পরিস্থিতি
সবচেয়ে সহজ design: প্রতিটা server নিজের memory-তে cart মনে রাখে।
My Cloth অনলাইনে কাপড় বিক্রি করে, একসাথে শত শত ক্রেতা। তাই আগে থেকেই দুটো AZ-এ দুটো web server চলছে, সামনে একটা ALB (লেসন ৯.১)। এক ক্রেতা একটা শার্টে “Add to cart” চাপল।
#ধাপ ২: sticky session
#তাৎক্ষণিক সমাধান
সবচেয়ে দ্রুত সমাধানে code-ই লাগে না: ALB-র target group-এ stickiness (session affinity) চালু করো। ALB browser-কে একটা cookie দেয় (duration-based stickiness-এ AWSALB, আর তোমার নিজের application cookie মেনে চললে AWSALBAPP), আর ওই cookie নিয়ে আসা পরের সব request যায় একই target-এ। ক্রেতা বারবার server ১-এই পৌঁছায়, যেখানে তার cart।
#লেসন ৬.৪-এ যা দেখেছি
লেসন ৬.৪-এ এটা খুঁটিয়ে দেখেছি; এখানে ছোট করে মনে করিয়ে দিই। Session ID আর session data আলাদা জিনিস। Cookie শুধু একটা টোকেন, রেস্টুরেন্টের টোকেনের মতো, যাতে লেখা “কাউন্টার ১”; আসল cart লেখা থাকে server ১-এর RAM-এ, যেমন রাঁধুনির খাতায় লেখা থাকে order। Server ১ crash করলে বা restart নিলে RAM মুছে যায়। পরের request তখনও cookie নিয়ে আসে, ALB দেখে server ১ নেই, বাধ্য হয়ে বেছে নেয় server ২, আর server ২ বলে “Your cart is empty”। Stickiness-এ ডেটা একটা server-এর পেটের ভেতর আটকা থাকে: server মরলে ডেটাও মরে।
#Stickiness-এর দাম
- Instance মরলে cart হারায়। একটা crash, health check-এ fail বা hardware বদল, ওই instance-এর সব session সাথে নিয়ে যায়।
- Scale in আর deployment-এও cart হারায়। কোন instance terminate হবে, Auto Scaling সেটা বাছে তার termination policy দেখে, কে কেনাকাটা করছে দেখে না (লেসন ৬.৫)। Deregistration delay চলতি request শেষ করতে দেয়, কিন্তু RAM তবুও যায়। Rolling deployment সব server-ই বদলায়, তাই সব cart খালি করে দিতে পারে।
- Load অসমান হয়। ক্রেতারা যে server-এ আটকেছে সেখানেই থাকে। ব্যস্ত server ব্যস্তই থাকে, আর scale out-এ নতুন চালু হওয়া instance পায় শুধু নতুন ক্রেতা, তাই scale out যতটা কাজে আসার কথা ততটা আসে না।
- Cookie-র ওপর নির্ভর। যে client cookie নেয় না, সে প্রতিটা request-এ নতুন করে route হয়।
চারটা server-এ সমান ভাগ থাকলে একটা instance terminate হওয়া মানে একসাথে প্রায় এক-চতুর্থাংশ cart খালি।
#ধাপ ৩: cart থাকবে cookie-তে
#State বয়ে নিক browser
Server যদি cart মনে না রাখে, তাহলে অন্য কাউকে রাখতে হবে। সবচেয়ে সহজ “অন্য কেউ” হলো browser। Server পুরো cart একটা cookie-তে লিখে দেয়, যেমন cart=shirt-M-blue,trousers-32, আর browser প্রতিটা request-এর সাথে সেটা ফেরত পাঠায়। যেকোনো server সেটা পড়তে পারে, তাই:
- web tier সত্যিকারের stateless: ALB ইচ্ছেমতো ভাগ করে, Auto Scaling যেকোনো instance সরাতে পারে, stickiness লাগে না;
- server-এর দিকে কিছুই রাখতে হয় না, বাড়তি কোনো খরচও নেই।
#এটা কেন বেশিদিন চলে না
- আকার। নিয়ম অনুযায়ী browser-কে একটা cookie-তে অন্তত ৪,০৯৬ byte রাখতে পারতে হয় (নাম, value আর attribute মিলিয়ে, RFC 6265), আর বাস্তবে সর্বোচ্চও মোটামুটি ততটুকুই; বড় cookie চুপচাপ ফেলে দেয়। Size, রং আর দাম সহ বিশটা জিনিসের cart-ই সেখানে পৌঁছে যায়। (ALB এখানে বাধা না: সে ১৬ KB-র একটা header আর মোট ৬৪ KB-র request header নেয়।)
- ভারী request। Browser domain-এর সব cookie পাঠায় প্রতিটা request-এ, ছবি, CSS আর API call-সহ। যে page ৪০টা request করে, তাতে ৩.৫ KB-র একটা cookie মানে প্রতি page view-এ প্রায় ১৪০ KB বাড়তি upload, তার অনেকটাই ধীর mobile network-এ।
- Cookie থাকে client-এর হাতে। ক্রেতা developer tools খুলে শার্টের দাম ৳১ করে দিতে পারে। তাই server-কে প্রতিটা cookie যাচাই করতে হয়: এমন secret দিয়ে HMAC sign করো যা শুধু server-রা জানে, আর signature না মিললে cookie বাতিল করো। Sign করা cookie-ও কিন্তু পড়া যায়, তাই এতে গোপন কিছু রাখা চলবে না; তথ্য সংবেদনশীল হলে encrypt করো।
- আবার হিসাব আর অন্য device। Checkout-এর সময় দাম আর stock server-কে ডেটাবেস দেখে আবার যাচাই করতেই হয়, আর cart ক্রেতার সাথে অন্য device বা browser-এ যায় না।
JWT-এর মতো sign করা token একই ধারণা, শুধু পরিচয়ের জন্য: ছোট, sign করা, পড়া যায়, প্রতিটা request-এর সাথে যায়। “এই user কে” বলার জন্য দারুণ, ক্রমশ বড় হতে থাকা shopping cart-এর জন্য খারাপ।
#ধাপ ৪: shared store-এ server-side session
#যায় শুধু একটা ID
এবার আগের দুই ধাপের ভালো অর্ধেকটা জুড়ে দাও। Cookie-তে থাকে শুধু একটা session ID: লম্বা একটা random মান (ধরো ১২৮টা random bit), যার নিজের কোনো অর্থ নেই। Session data, মানে cart, থাকে web server-এর বাইরে একটা shared store-এ, ওই ID ধরে।
প্রথম request: session তৈরি
web-1 একটা random ID বানায়, cart লেখে store-এ
sess:<id>নামে, ধরো ৩০ মিনিটের TTL দিয়ে, আর ফেরত পাঠায়Set-Cookie: session_id=<id>; HttpOnly; Secure; SameSite=Lax।পরের যেকোনো request: store থেকে পড়া
পরের click হয়তো পড়ল web-2-তে। সে store থেকে
sess:<id>পড়ে, শার্ট আর প্যান্ট দুটোই দেখে, নতুন জিনিস যোগ করে, session আবার লিখে দেয় আর TTL নতুন করে শুরু করে, তাই সক্রিয় ক্রেতার session কখনো মেয়াদোত্তীর্ণ হয় না।একটা server মরল: cart-এর কিছুই হলো না
Crash, scale in বা deployment server সরিয়ে দেয়, কিন্তু তাদের ভেতরে কোনো cart ছিল না। Web tier আবার stateless, stickiness-এর আর দরকার নেই।
Cookie cart-এর সব সমস্যাও এতে মিটে যায়: cookie ছোট্ট, request হালকা, store যতটা দেয় cart ততটা বড় হতে পারে, আর ID বদলালে ক্রেতা পায় শুধু “এমন session নেই”: ১২৮-bit-এর random ID আন্দাজ করা যায় না, তাই বদলে অন্য কারও cart খোলা যায় না।
#ElastiCache নাকি DynamoDB?
Note আর slide দুটোতেই উত্তর হিসেবে দুটোর নামই আছে, আর দুটোই ঠিক। তফাত হলো ডেটা কীভাবে রাখে।
| Amazon ElastiCache (Valkey বা Redis OSS) | Amazon DynamoDB | |
|---|---|---|
| ডেটা কোথায় থাকে | তোমার মাপমতো node-এর memory-তে, অথবা ElastiCache Serverless | Managed একটা table, Region-এর তিনটা AZ-এ রাখা |
| Read latency | Microsecond | এক অঙ্কের millisecond |
| মেয়াদ | SET … EX 1800: মেয়াদ ফুরানোর মুহূর্তেই key উধাও | একটা TTL attribute (epoch সেকেন্ডে); মেয়াদোত্তীর্ণ item পেছনে বসে মোছে কয়েক দিনের মধ্যে, তাই read-এর সময় সেগুলো বাদ দিতে হয় |
| Failure সামলানো | অন্য AZ-এ replica আর Multi-AZ automatic failover লাগে; replication asynchronous | ভেতরেই আছে: node নেই, failover সামলানোর ঝামেলাও নেই |
| Capacity | Node-এর আকার বা Serverless-এর সীমা | On-demand বা provisioned; item সর্বোচ্চ ৪০০ KB |
| কখন নেবে | প্রতি page-এ অনেক read, সবচেয়ে কম latency, ডেটাবেসের জন্য আগে থেকেই একটা cache চালাচ্ছ | Session টেকসই হতে হবে, কোনো server-ই চাও না, বা traffic হঠাৎ হঠাৎ বাড়ে-কমে |
পরীক্ষা আর বাস্তব দুই জায়গাতেই দুটো খুঁটিনাটি জরুরি:
- Session store হিসেবে Memcached দুর্বল। এর replica নেই, failover নেই, তাই একটা node গেলে তার session-ও যায়। Note-এ যখন বলছে “ElastiCache (Redis/Memcached)”, session-এর জন্য সেটা পড়ো replica সহ Valkey বা Redis OSS (লেসন ৭.৫); Memcached হলো এমন সাধারণ cache-এর জন্য যা হারালেও চলে।
- DynamoDB-র TTL কোনো ঘড়ি না। মেয়াদোত্তীর্ণ item এটা বিনা পয়সায় মোছে, write capacity খরচ না করে, কিন্তু মেয়াদ ফুরানোর কিছু পরে। যে item-এর
expires_atপেরিয়ে গেছে, application-কে নিজেই সেটাকে বাতিল ধরতে হবে।
দুটোতেই code বদলাতে হয়: application-কে session পড়তে আর লিখতে হবে store-এ। এটাই architecture দিয়ে সমাধানের দাম, আর এই কারণেই code বদলানো একেবারে অসম্ভব হলেই শুধু stickiness উত্তর থাকে।
#চারটা design চালিয়ে দেখো, তারপর ভাঙো
একটা design বেছে নাও, জিনিস যোগ করো, তারপর server crash করাও, scale in করো, cookie বদলাও, ৪ KB পার করো বা cache node নষ্ট করো। প্রতিবার চাপা মানে একটা request:
Cart থাকে কোথায়? একটা failure simulator
একটা design বেছে নাও, কয়েকটা জিনিস cart-এ দাও, তারপর কিছু একটা ভাঙো। প্রতিবার বোতাম চাপা মানে একই ক্রেতার একটা request।
Design
প্রতিটা server cart রাখে নিজের memory-তে। ALB প্রতিটা request পাঠায় পরের সুস্থ server-এ (round robin)।
Browser
কোনো cookie নেই
ALB
round robin
web-1
RAM: খালি
web-2
RAM: খালি
web-3
RAM: খালি
Request আর failure
কী ঘটল
এখনো কিছু ঘটেনি। “পরের জিনিস যোগ করো” চাপো।
নিজেকে যাচাই করোপ্রশ্ন
My Cloth পুরো cart রাখে একটা sign করা cookie-তে। খালি cart-এ ক্রেতা একেকটা প্রায় ১৮০ byte-এর জিনিস যোগ করছে; cookie-র নাম আর attribute-এ লাগে আরও প্রায় ৪০ byte, signature-এ ৪৪ byte। ৪,০৯৬ byte-এ browser cookie ফেলে দেওয়ার আগে মোটামুটি কয়টা জিনিস ধরবে?
#ধাপ ৫: user-এর ডেটার জায়গা ডেটাবেস
Cart আধা ঘণ্টা পরে মুছে গেলেও চলে; ক্রেতার নাম, ঠিকানা, password hash আর order-এর ইতিহাস কিন্তু না। এগুলো টেকসই, relational ডেটা, তাই যায় Amazon RDS-এ (লেসন ৭.১), অথবা Aurora-তে (লেসন ৭.৩)।
- Login-এর সময় web tier RDS থেকে account পড়ে; checkout-এ একটা transaction-এ order লেখে (stock যাচাই, order-এর row, payment-এর অবস্থা, সব একসাথে), তারপর cart-এর session মুছে দেয়।
- ভাগটা এখন পরিষ্কার: স্বল্পমেয়াদি state (session, cart) ElastiCache বা DynamoDB-তে, আসল হিসাবের খাতা RDS-এ, আর web server-এ কিছুই না।
- Session চাইলে account-এর কয়েকটা field-ও (page-এর মাথায় ক্রেতার নাম) রেখে দিতে পারে, যাতে প্রতিটা page view-এ RDS-এ যেতে না হয়।
এখন ডেটাবেসই design-এর সবচেয়ে ব্যস্ত অংশ, আর পরের দুটো ধাপ তাকে নিয়েই: অতিরিক্ত read, আর তার AZ নষ্ট হলে কী হয়।
#ধাপ ৬: read scale করা
#একটা primary-র ওপর অনেক বেশি read
কাপড়ের দোকান লেখে যত, পড়ে তার অনেক গুণ বেশি: প্রতিটা product page, category-র list আর search ডেটাবেসে যায়, অথচ order দেয় অল্প কয়েকটা request। Sale-এর সময় একমাত্র RDS instance-এর CPU ফুরিয়ে যায়। বড় instance class (vertical scaling) কিছু সময় কিনে দেয়, কিন্তু তার একটা ছাদ আছে। তার বদলে বারবার হওয়া read-গুলো primary-র ঘাড় থেকে নামাও, দুটোর একটা উপায়ে।
#উপায় ১: read replica
RDS read replica বানাও (MySQL, MariaDB, PostgreSQL, Oracle আর SQL Server-এ একটা source-এর সর্বোচ্চ ১৫টা; লেসন ৭.১)। Primary প্রতিটা পরিবর্তন তাদের কাছে asynchronously copy করে, আর প্রতিটা replica-র নিজের endpoint থাকে। Application write পাঠায় primary endpoint-এ, read পাঠায় replica-তে।
- Application-এ বদল সামান্য: read-এর জন্য দ্বিতীয় একটা connection string। Query একই SQL থাকে।
- Replica যেকোনো query-র উত্তর দেয়, তাই সাধারণ browsing, search আর report-এর জন্য মানানসই।
- প্যাঁচটা হলো replica lag। Replica এক মুহূর্ত পিছিয়ে থাকতে পারে: শেষ জ্যাকেটটা primary-তে বিক্রি হয়ে গেছে, অথচ এক-দুই সেকেন্ড replica তখনও দেখাচ্ছে “১টা বাকি”। যে read একটু পুরনো হলেও চলে, সেটা replica থেকে নাও; আর সিদ্ধান্ত (checkout-এর সময়ের stock, order-এর মোট দাম) আর user-এর নিজের সদ্য লেখা ডেটা (read-your-own-writes) পাঠাও primary-তে।
#উপায় ২: RDS-এর সামনে ElastiCache (lazy loading)
ডেটাবেসের সামনে ElastiCache বসাও আর lazy loading চালাও (cache-aside, লেসন ৭.৫):
- আগে cache পড়ো, যেমন
product:42। - Hit: memory থেকে এক millisecond-এর অনেক কম সময়ে উত্তর; RDS কিছুই করে না।
- Miss: RDS পড়ো, উত্তর দাও, আর ফলটা TTL দিয়ে cache-এ লিখে রাখো, যাতে পরের read hit হয়।
Hit ratio ৯৫% হলে সেকেন্ডে ১০,০০০ product read থেকে RDS-এ যায় মাত্র ৫০০। প্যাঁচের দুটো দিক আছে: application-কে cache ব্যবহার করার মতো করে লিখতে হয় (সত্যিকারের code বদল), আর cache-এর মান পুরনো হয়ে যেতে পারে: RDS-এ দাম বদলালেও cache-এ পুরনো দামই থাকে, যতক্ষণ না TTL ফুরায় বা code key-টা মুছে দেয়। Row বদলালেই key মুছে দাও বা নতুন মান লিখে দাও (write-through), নিরাপত্তার জন্য TTL রাখো, আর যে মান একদম ঠিক হতে হবে তার জন্য cache কখনো ব্যবহার কোরো না।
Read scale করা: replica নাকি cache
প্রতিটা order লেখার বিপরীতে product page পড়া হয় হাজার বার। Primary-র ঘাড় থেকে read নামানোর দুটো উপায়, প্রত্যেকটার নিজস্ব প্যাঁচ আছে।
পরিস্থিতি
প্রতিটা page view একটাই RDS instance-এ read query চালায়, প্রতিটা order-ও। Sale-এর সময় primary-র CPU ৯০% ছাড়িয়ে যায়, আর বাকি সবকিছুর সাথে checkout-ও ধীর হয়ে পড়ে।
| Read replica | ElastiCache | |
|---|---|---|
| Application-এ বদল | সামান্য: একটা read endpoint | হ্যাঁ: code-এ caching logic |
| Read latency | Millisecond | Microsecond |
| কীসের উত্তর দেয় | যেকোনো SQL query | শুধু যে key রেখেছ |
| পুরনো হওয়া | Replica lag (সাধারণত এক সেকেন্ডের কম) | TTL বা invalidation পর্যন্ত |
| আর কোথায় কাজে লাগে | Report, promote করে disaster recovery | Session (ধাপ ৪), counter, leaderboard |
অনেক দোকান দুটোই চালায়: সাধারণ read-এর জন্য replica, সবচেয়ে ব্যস্ত page-এর জন্য cache, আর session-এর জন্য সেই ElastiCache cluster (বা আলাদা একটা)।
#ধাপ ৭: প্রতিটা data tier-এ Multi-AZ
Web tier আগে থেকেই কয়েকটা AZ জুড়ে আছে। এক AZ-এ একটাই কপি রাখা data tier সেই পরিশ্রম জলে ফেলে দেয়: তার AZ নষ্ট হলে সব server সুস্থ, অথচ দোকান বন্ধ।
- RDS Multi-AZ: অন্য AZ-এর একটা standby প্রতিটা write পায় synchronously। Primary নষ্ট হলে RDS একই DNS endpoint standby-র দিকে ঘুরিয়ে দেয়, সাধারণত ৬০ থেকে ১২০ সেকেন্ডে, commit হওয়া কোনো ডেটা না হারিয়ে। Standby কোনো read সামলায় না; সেটা replica-র কাজ (লেসন ৭.১)।
- ElastiCache Multi-AZ (Valkey বা Redis OSS): অন্য AZ-এ একটা replica, automatic failover সহ। Primary node নষ্ট হলে ElastiCache replica-কে primary বানায়, সাধারণত কয়েক সেকেন্ডে, আর primary endpoint তার পিছু নেয়। Replication asynchronous, তাই শেষ মুহূর্তের কিছু write হারাতে পারে; session-এর জন্য সেটা মেনে নেওয়া যায়। ElastiCache Serverless নিজেই কয়েকটা AZ-এ replicate করে।
- Session যদি DynamoDB-তে থাকে, সেটা এমনিতেই তিনটা AZ-এ রাখা: কিছুই সাজাতে হয় না।
খেয়াল করো, RDS failover-এর সময় প্রতিটা tier-এ Multi-AZ থাকার লাভটা কী: এক-দুই মিনিট checkout অপেক্ষা করে আর আবার চেষ্টা করে, কিন্তু ঘোরাঘুরি আর cart ঠিকঠাক চলে, কারণ session আছে আরেকটা store-এ, যেটা নষ্ট হয়নি।
ElastiCache আর RDS-এর Multi-AZ
দুটো data store-ই অন্য AZ-এ একটা দ্বিতীয় কপি রাখে। একটা node, এমনকি পুরো একটা AZ হারালেও session আর order টিকে থাকে।
পরিস্থিতি
Web tier একটা session লেখে AZ a-র ElastiCache primary-তে। AZ b-র replica তার কপি পায় asynchronously, এক মুহূর্ত পরে।
#ধাপ ৮: tier থেকে tier, শিকলের মতো security group
শেষ চাহিদা হলো, ডেটা পর্যন্ত শুধু ঠিক tier-টাই পৌঁছাবে। Security group-এর rule-এ source হিসেবে আরেকটা security group দেওয়া যায় (লেসন ৩.৫), আর এটাই tier-গুলোকে শিকলের মতো জুড়ে দেয়:
| Security group | কার গায়ে | Inbound rule | Source |
|---|---|---|---|
alb-sg | ALB | TCP ৮০ আর ৪৪৩ | 0.0.0.0/0 (internet) |
app-sg | প্রতিটা web server (launch template দিয়ে) | TCP ৮০ (বা app-এর port) | alb-sg |
cache-sg | ElastiCache | TCP ৬৩৭৯ (Valkey/Redis OSS) | app-sg |
db-sg | RDS | TCP ৩৩০৬ (MySQL; PostgreSQL হলে ৫৪৩২) | app-sg |
এটা কেন সবচেয়ে মজবুত:
- Internet-এর মুখোমুখি শুধু ALB। কেউ তাকে এড়িয়ে web server-এ পৌঁছাতে পারে না, আর internet থেকে কেউ ডেটাবেসের port ছুঁতে পারে না।
- Address না, সদস্যপদ। যে instance-এর গায়ে
app-sg, সে-ই data tier-এ পৌঁছায়, তাই Auto Scaling-এর চালু করা instance সাথে সাথে কাজ করে, কোনো IP list আপডেট করতে হয় না। যার গায়ে নেই, সে বাতিল, একই VPC আর একই subnet-এ থাকলেও। - Stateful। উত্তর নিজে থেকেই ফিরে আসে; এই connection-গুলোর জন্য outbound বা ফেরার rule লাগে না।
- স্তরে স্তরে। Web আর data tier রাখো private subnet-এ, public IP ছাড়া, আর RDS রাখো “not publicly accessible”। Security group আর subnet-এর design, দুটোর প্রত্যেকটাই একা একজন আক্রমণকারীকে থামায়।
যে rule ডেটাবেসের port খোলে 0.0.0.0/0 থেকে, বা পুরো VPC CIDR থেকে, সেটা নিঃশব্দে শিকল ভেঙে দেয়: তখন VPC-র যেকোনো instance RDS-এ পৌঁছায়।
Tier থেকে tier, শিকলের মতো security group
প্রতিটা tier শুধু তার সামনের tier-এর security group থেকে আসা traffic নেয়। Internet-এর মুখোমুখি শুধু load balancer।
পরিস্থিতি
Inbound rule (বাকি সব security group আটকে দেয়)
| Security group | Port | Source |
|---|---|---|
| alb-sg | 80, 443 | 0.0.0.0/0 |
| app-sg | 80 | alb-sg |
| cache-sg | 6379 | app-sg |
| db-sg | 3306 | app-sg |
ক্রেতারা HTTPS-এ ALB-তে পৌঁছায়। Internet-এর জন্য খোলা একমাত্র group হলো alb-sg: 0.0.0.0/0 থেকে port ৮০ আর ৪৪৩।
#Three-tier-এর পুরো ছবি
ধাপগুলো জোড়া দিলে পাও classic three-tier web application, এই পুরো লেসনের লক্ষ্য:
| Tier | সেখানে কী চলে | কীভাবে scale করে | AZ নষ্ট হলে কীভাবে টেকে | কে পৌঁছাতে পারে |
|---|---|---|---|---|
| Presentation / প্রবেশপথ | Route 53 alias → public subnet-এ ALB | AWS নিজে সামলায় | চালু প্রতিটা AZ-এ ALB-র node | Internet, ৮০/৪৪৩-এ |
| Application (web) | Auto Scaling group-এ stateless EC2, private subnet-এ | Horizontally, Auto Scaling দিয়ে | দুই বা তিন AZ-এ instance; health check নষ্টগুলো বদলে দেয় | শুধু alb-sg |
| Data | ElastiCache (session, ব্যস্ত read) আর RDS (user, order), private subnet-এ | Read-এর জন্য replica আর cache; write-এর জন্য বড় class | ElastiCache Multi-AZ replica; RDS Multi-AZ standby | শুধু app-sg |
লেসন ৯.৩ পরের টুকরোটা যোগ করে: EFS দিয়ে শেয়ার করা file (upload করা ছবি), আর দ্রুত নতুন instance চালু করা।
#কোথায় গোলমাল হয়
| লক্ষণ | সম্ভাব্য কারণ | সমাধান |
|---|---|---|
| Cart-এ জিনিস আসে আর যায়; click-এর ফাঁকে ক্রেতা logout হয়ে যায় | Session server-এর RAM-এ, stickiness নেই | Session বাইরে সরাও (ElastiCache / DynamoDB); stickiness শুধু জোড়াতালি হিসেবে |
| প্রতিবার scale in বা deployment-এর পর cart খালি | RAM-এ state, সাথে sticky session | Session বাইরে সরাও |
| Scale out-এর পর নতুন instance বসে থাকে | Stickiness পুরনো ক্রেতাদের পুরনো server-এ আটকে রাখে | Session বাইরে সরাও, বা stickiness-এর duration কমাও |
| বড় cart উধাও; mobile-এ request ধীর | Cookie-তে cart, প্রায় ৪ KB-র বেশি; প্রতিটা request-এ ভারী cookie | Cookie-তে session ID, cart store-এ |
| ক্রেতা বদলানো দামে কিনে ফেলে | Sign না করা cart cookie server বিশ্বাস করেছে | Sign আর যাচাই করো, দাম server-এ আবার হিসাব করো, আরও ভালো server-side session |
| সবাই একসাথে logout | একমাত্র cache node নষ্ট (বা Memcached) | Multi-AZ সহ Valkey/Redis OSS replica, Serverless, বা DynamoDB |
| বিক্রি হয়ে যাওয়া জিনিসে “১টা বাকি” | পিছিয়ে থাকা replica বা পুরনো cache থেকে পড়া | Stock-এর সিদ্ধান্ত primary-তে; লেখার সময় invalidate |
| এক-দুই মিনিট checkout ব্যর্থ, browsing চলছে | RDS Multi-AZ failover চলছে | প্রত্যাশিত: retry আর reconnect; DNS cache ছোট রাখো |
| অচেনা একটা instance ডেটাবেসে পৌঁছে গেছে | ডেটাবেসের port 0.0.0.0/0 বা VPC CIDR-এর জন্য খোলা | Source = শুধু app-sg |
#System design-এ এর জায়গা
- State ঠেলে দাও stateless tier-এর কিনারায়: client-এর কাছে (ছোট, sign করা, শুধু পরিচয়), নয়তো একটা shared store-এ (বাকি সব)। Web tier নিজে এমন কিছু রাখে না যা হারালে ক্ষতি।
- ডেটার আয়ু দেখে store বাছো: কয়েক সেকেন্ড থেকে কয়েক ঘণ্টার session state cache-এ বা TTL সহ DynamoDB-তে; বছরের পর বছরের order backup সহ relational ডেটাবেসে।
- Write-এর আগে read scale করো: primary-কে shard করার তুলনায় replica আর cache সস্তা। Write একটা instance ছাপিয়ে গেলে পরের ধাপ Aurora (লেসন ৭.৩) বা অন্য data model, যা ডেটাবেস বাছাইয়ের পরের একটা chapter-এ আসবে।
- প্রতিটা tier-এর নিজের failure-এর পরিকল্পনা লাগে: ডেটার জন্য Multi-AZ, web tier-এর জন্য কয়েকটা AZ, ALB-তে health check।
- Security group-ই architecture-এর বর্ণনা: ওপরের চারটা rule পড়লেই একজন reviewer বুঝে যায় কে কার সাথে কথা বলে।
#পরীক্ষার keyword → পরের ধাপ
#নিজে করে দেখো
Command-গুলোতে বানানো নাম: target group tg-shop, security group sg-0alb…, sg-0app…, sg-0db…, sg-0cache…।
# Stage 2: duration-based stickiness on the target group (1 hour)
aws elbv2 modify-target-group-attributes --target-group-arn <tg-shop-arn> \
--attributes Key=stickiness.enabled,Value=true Key=stickiness.type,Value=lb_cookie \
Key=stickiness.lb_cookie.duration_seconds,Value=3600
# Stage 4a: a session store on ElastiCache (Valkey) with a replica in another AZ
aws elasticache create-replication-group --replication-group-id shop-sessions \
--replication-group-description "My Cloth sessions" --engine valkey \
--cache-node-type cache.t4g.small --num-cache-clusters 2 \
--automatic-failover-enabled --multi-az-enabled \
--cache-subnet-group-name private-data --security-group-ids sg-0cache1111
# Write and read a session with a 30-minute TTL (from a web server)
redis-cli -h <primary-endpoint> --tls SET sess:7f3a '{"cart":["shirt","trousers"]}' EX 1800
redis-cli -h <primary-endpoint> --tls TTL sess:7f3a
# Stage 4b: or a DynamoDB session table with TTL on the expires_at attribute
aws dynamodb create-table --table-name shop-sessions \
--attribute-definitions AttributeName=session_id,AttributeType=S \
--key-schema AttributeName=session_id,KeyType=HASH --billing-mode PAY_PER_REQUEST
aws dynamodb update-time-to-live --table-name shop-sessions \
--time-to-live-specification Enabled=true,AttributeName=expires_at
# Stage 6: a read replica for product pages
aws rds create-db-instance-read-replica --db-instance-identifier shop-db-replica-1 \
--source-db-instance-identifier shop-db
# Stage 7: make the primary Multi-AZ
aws rds modify-db-instance --db-instance-identifier shop-db --multi-az --apply-immediately
# Stage 8: chain the security groups
aws ec2 authorize-security-group-ingress --group-id sg-0app2222 \
--protocol tcp --port 80 --source-group sg-0alb1111
aws ec2 authorize-security-group-ingress --group-id sg-0db3333 \
--protocol tcp --port 3306 --source-group sg-0app2222
aws ec2 authorize-security-group-ingress --group-id sg-0cache1111 \
--protocol tcp --port 6379 --source-group sg-0app2222
Client-এর দিক থেকে stickiness দেখতে চাইলে curl -i https://shop.example.com/ -c jar.txt -b jar.txt দিয়ে দুবার request পাঠাও, আর response header-এ AWSALB cookie খুঁজে দেখো।
#সারসংক্ষেপ
মূল কথা
- Stateful app-এর আগের request-এর ডেটা লাগে। State server-এর RAM-এ থাকলে, request ভাগ করা load balancer প্রতিটা hop-এ cart হারায়।
- Sticky session cookie দিয়ে ক্রেতাকে একটা server-এ আটকে রাখে। Code বদলাতে হয় না, কিন্তু instance-এর সাথে cart মরে (crash, scale in, deployment), আর load অসমান হয়। ঠিক উত্তর শুধু যে legacy app-এর code বদলানো যায় না তার জন্য। Session ID বনাম session data: লেসন ৬.৪।
- Cookie-তে cart: server stateless, কিন্তু একটা cookie-তে প্রায় ৪ KB, যায় প্রতিটা request-এ, আর client বদলে দিতে পারে, তাই sign আর যাচাই করতে হয়, গোপন কিছু রাখা যায় না।
- Server-side session: cookie-তে শুধু একটা random session ID; ডেটা থাকে ElastiCache-এ (microsecond, replica সহ Valkey/Redis OSS) বা DynamoDB-তে (টেকসই, serverless, TTL কয়েক দিনের মধ্যে মোছে)। TTL অলস session-এর মেয়াদ শেষ করে। Code বদলাতে হয়।
- User-এর ডেটা (account, ঠিকানা, order) যায় RDS-এ; web tier কিছুই রাখে না।
- Read scaling: read replica (সামান্য code বদল, যেকোনো query, replica lag) বা ElastiCache lazy loading (code বদল, microsecond, TTL বা invalidation পর্যন্ত পুরনো)। “Code বদল ছাড়া” → replica।
- RDS-এর Multi-AZ (synchronous standby, ৬০–১২০ সেকেন্ডে failover) আর ElastiCache-এর (replica, কয়েক সেকেন্ডে failover) data tier-কে AZ নষ্ট হলেও টিকিয়ে রাখে; DynamoDB এমনিতেই তিনটা AZ জুড়ে।
- Security group একে অন্যকে reference করে: internet →
alb-sg(৮০/৪৪৩),alb-sg→app-sg,app-sg→cache-sg(৬৩৭৯) আরdb-sg(৩৩০৬)। Data-র port কখনো0.0.0.0/0-এর জন্য খুলবে না। - সব মিলিয়ে: classic three-tier web application।
আগে নিজে উত্তর দাও, তারপর ব্যাখ্যাটা পড়ো। ঠিক হলেও পড়ো, কারণ ভুল Option-গুলো কেন ভুল, সেটাও ওখানে আছে।
নিজেকে যাচাই করোপ্রশ্ন
একটা web application কখন stateful হয়?
নিজেকে যাচাই করোপ্রশ্ন
My Cloth একটা ALB-র পেছনে তিনটা EC2 instance চালায়, stickiness নেই। প্রতিটা instance cart রাখে memory-তে। এক ক্রেতা একটা শার্ট যোগ করল, তারপর প্যান্ট। ক্রেতা সম্ভবত কী দেখবে?
নিজেকে যাচাই করোপ্রশ্ন
একটা legacy application user-এর session রাখে local memory-তে। তার code বদলানো যাবে না। ALB-র পেছনে user-রা বারবার logout হয়ে যাচ্ছে। সবচেয়ে দ্রুত সমাধান কী?
নিজেকে যাচাই করোপ্রশ্ন
একটা অনলাইন দোকান ALB sticky session ব্যবহার করে, cart রাখে instance-এর memory-তে। Auto Scaling যতবার scale in করে, কিছু ক্রেতা দেখে তাদের cart খালি। একজন solutions architect কী সুপারিশ করবেন?
নিজেকে যাচাই করোপ্রশ্ন
Sticky session-এর সত্যিকারের দাম কোন দুটো?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
ALB stickiness-এ instance মরলে ক্রেতা cart হারায় কেন, যখন AWSALB cookie তখনও browser-এ আছে?
নিজেকে যাচাই করোপ্রশ্ন
My Cloth পুরো cart একটা cookie-তে সরিয়ে নিল। দলকে এখন কোন দুটো সমস্যা সামলাতে হবে?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
একটা দোকান দাম রাখে cart cookie-তে। এক ক্রেতা cookie বদলে ৳১-এ একটা জ্যাকেট কিনে ফেলল। কোন পরিবর্তনে এমন বদল আর গৃহীত হবে না?
নিজেকে যাচাই করোপ্রশ্ন
Sign করা cart cookie ধরা না পড়ে বদলানো যায় না। তার ভেতরের জিনিস নিয়ে কোনটা তবুও সত্যি?
নিজেকে যাচাই করোপ্রশ্ন
একটা দোকানের cart cookie ৩.৫ KB-র। প্রতিটা page view একই domain-এ ৪০টা request করে, আর site-এ দিনে ১,০০,০০০ page view হয়। দিনে browser-রা কত cookie ডেটা upload করে?
নিজেকে যাচাই করোপ্রশ্ন
Server-side session-এ browser-এর session cookie-তে কী থাকে?
নিজেকে যাচাই করোপ্রশ্ন
ALB-র পেছনের একটা application-এ Auto Scaling যতবার একটা EC2 instance terminate করে, user-রা session data হারায়। দল code বদলাতে পারে। কোন সমাধান সবচেয়ে scalable আর resilient?
নিজেকে যাচাই করোপ্রশ্ন
একটা কোম্পানি এমন serverless, টেকসই session store চায় যা মেয়াদোত্তীর্ণ session নিজে মুছে দেয়, আর capacity নিয়ে কোনো পরিকল্পনা লাগে না। কোনটা সবচেয়ে মানানসই?
নিজেকে যাচাই করোপ্রশ্ন
একটা DynamoDB session table-এ expires_at attribute-এ TTL চালু। একটা session-এর মেয়াদ ১০ মিনিট আগে ফুরিয়েছে, তবু lookup-এ সেটা ফেরত আসছে। কী হচ্ছে, আর application-এর কী করা উচিত?
নিজেকে যাচাই করোপ্রশ্ন
Session রাখা আছে ElastiCache-এ, ৩০ মিনিটের TTL, প্রতিটা request-এ application সেটা নতুন করে শুরু করে। ক্রেতার শেষ click ১০:০৫-এ, পরেরটা ১০:৪০-এ। কী হবে?
নিজেকে যাচাই করোপ্রশ্ন
যে user session-কে failure-এর পরও টিকে থাকতে হবে, তার জন্য ElastiCache for Memcached দুর্বল বাছাই কেন?
নিজেকে যাচাই করোপ্রশ্ন
My Cloth cart-এর session রাখে ElastiCache-এ। ক্রেতার নাম, ঠিকানা আর order-এর ইতিহাস কোথায় রাখা উচিত?
নিজেকে যাচাই করোপ্রশ্ন
RDS for MySQL-এর product catalogue read query-র চাপে কাবু। দল read scale করতে চায়, application-এর data access logic না বদলে, শুধু একটা connection string ছাড়া। কী করা উচিত?
নিজেকে যাচাই করোপ্রশ্ন
একটা দোকান product page পড়ে RDS read replica থেকে। এক ক্রেতা শেষ জ্যাকেটটা কিনল; এক সেকেন্ড পরে আরেক ক্রেতা জ্যাকেটের page-এ তখনও দেখছে “১টা বাকি”। কারণ কী?
নিজেকে যাচাই করোপ্রশ্ন
Lazy loading সহ ElastiCache ব্যবহার করা একটা application-এ সেকেন্ডে ১০,০০০ product read আসে। Cache hit ratio ৯৫%। সেকেন্ডে কয়টা read RDS-এ পৌঁছায়?
নিজেকে যাচাই করোপ্রশ্ন
একটা application ১ ঘণ্টার TTL সহ lazy loading চালায়। RDS-এ দাম বদলানোর পর ক্রেতারা পুরনো দামই দেখতে থাকে। কোন দুটো বদল এটা ঠিক করে?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
Read scaling-এর জন্য read replica আর ElastiCache-এর তুলনায় কোন কথাটা ঠিক?
নিজেকে যাচাই করোপ্রশ্ন
AZ a-তে My Cloth-এর RDS primary নষ্ট হলো। RDS Multi-AZ চালু; session আছে আরেক AZ-এর ElastiCache-এ। ক্রেতারা কী টের পাবে?
নিজেকে যাচাই করোপ্রশ্ন
কোন দুটো ব্যবস্থা three-tier app-এর data tier-কে একটা AZ হারানো থেকে বাঁচায়?
বেছে নাও ২
নিজেকে যাচাই করোপ্রশ্ন
যে ElastiCache primary-তে session রাখা, সেটা নষ্ট হলো। Cluster-এর অন্য AZ-এ replica আছে, Multi-AZ automatic failover চালু। Session-এর কী হবে?
নিজেকে যাচাই করোপ্রশ্ন
Web tier যাতে RDS for MySQL-এ connect করতে পারে, তার জন্য কোন security group rule ঠিক?
নিজেকে যাচাই করোপ্রশ্ন
একজন solutions architect-কে নিশ্চিত করতে হবে যে user-রা web server-এ পৌঁছাবে শুধু ALB দিয়ে। কোন configuration এটা করে?
নিজেকে যাচাই করোপ্রশ্ন
Web server-গুলোর একই subnet-এর একটা test EC2 instance RDS ডেটাবেসে connect করতে পারছে, যদিও পারার কথা না। ডেটাবেসের security group 3306 খোলে 10.0.0.0/16 থেকে, যা VPC-র CIDR। সমাধান কী?
নিজেকে যাচাই করোপ্রশ্ন
Sale-এর সময় Auto Scaling পাঁচটা নতুন web server চালু করল। ডেটাবেসের security group 3306 খোলে web tier-এর security group থেকে। নতুন server-রা যাতে RDS-এ পৌঁছায়, দলকে কী করতে হবে?
নিজেকে যাচাই করোপ্রশ্ন
এই লেসনের classic three-tier web architecture নিয়ে কোন দুটো কথা ঠিক?
বেছে নাও ২