Course-এর সূচি

7.5

ElastiCache আর Caching Pattern

Valkey/Redis OSS বনাম Memcached, lazy loading, write-through, TTL, session store, leaderboard আর MemoryDB।

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

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

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

  • In-memory cache কী, কেন এটা read-কে দ্রুত আর database-কে শান্ত রাখে, আর এর জন্য কী দাম দিতে হয় (code বদলানো আর stale data), সেটা বুঝিয়ে বলতে।
  • পরীক্ষার scenario দেখে ElastiCache-এর তিনটা engine, Valkey, Redis OSS আর Memcached, থেকে ঠিকটা বেছে নিতে।
  • Topology-গুলো বোঝাতে: cluster mode disabled আর enabled, ElastiCache Serverless, Global Datastore, সাথে তাদের সীমা।
  • Security group, AUTH token, RBAC user, IAM authentication, TLS আর KMS দিয়ে cache সুরক্ষিত করতে, আর Memcached-এর জন্য SASL।
  • Lazy loading, write-through, TTL আর session store কাজে লাগাতে, আর invalidation, eviction ও cache stampede সামলাতে।
  • Leaderboard, chat, rate limiting আর “আশপাশে কী আছে” খোঁজার জন্য sorted set, pub/sub, counter আর geospatial index ব্যবহার করতে।
  • ElastiCache (একটা cache) আর MemoryDB (টেকসই in-memory database)-এর পার্থক্য ধরতে, আর দুটোর পরীক্ষার keyword চিনে ফেলতে।

#Database-এর সামনে cache বসাই কেন?

#Memory একটা query-র চেয়ে হাজার গুণ দ্রুত

RDS বা Aurora database data রাখে storage-এ, আর প্রতিটা query-র জন্য সত্যিকারের খাটুনি করে: SQL পড়া, plan বানানো, page পড়া, দরকার হলে join আর sort। ভালো করে সাজানো query-ও কয়েক millisecond নেয়। এখন হাজার হাজার user যখন একই data বারবার চায় (home page, জনপ্রিয় একটা product, কারও profile), database-কে ওই একই খাটুনি বারবার করতে হয়।

Amazon ElastiCache হলো পুরোপুরি managed একটা in-memory data store। Data disk-এ না রেখে রাখে RAM-এ, সরল key আর value হিসেবে, আর একটা read-এর উত্তর দেয় microsecond-এ (এক millisecond-এর অনেক কম)। Node চালানোর ঝামেলা AWS-এর: setup, patching, monitoring, নষ্ট হলে সারানো, backup। RDS যেমন তোমাকে managed relational database দেয়, ElastiCache তেমনি দেয় managed Valkey, Redis OSS বা Memcached।

মূলত দুটো কাজে এটা লাগে:

কাজকী করেলাভ কী
Database cacheRDS বা Aurora-র সামনে একটা স্তর হয়ে বসে। Application আগে cache-কে জিজ্ঞেস করে; hit হলে সাথে সাথে উত্তর, miss হলে database থেকে পড়ে ফলটা cache-এ রেখে দেয়।Database-এ read অনেক কমে যায় (read-heavy workload-এর চাপ সরে যায়), তাই database ছোট আর দ্রুত থাকে; response time millisecond থেকে microsecond-এ নামে।
Session storeUser-এর session (login অবস্থা, shopping cart) প্রতিটা web server-এর memory-তে না রেখে এক জায়গায় কেন্দ্রীয়ভাবে রাখে।Web tier হয়ে যায় stateless: Auto Scaling group-এর যেকোনো EC2 instance যেকোনো user-কে সামলাতে পারে, আর কাউকে log out না করেই একটা instance terminate করা যায় (লেসন ৬.৪)।

#দাম কী: application বদলাতে হয়

Cache নিজে থেকে কাজ করে না। Application-কে cache-aware হতে হয়: কখন cache পড়বে, miss হলে কী করবে, কখন cache-এ লিখবে, কখন key মুছবে, সব তার code-এ লেখা থাকে। RDS read replica-র সাথে মূল পার্থক্য এখানেই: replica ব্যবহার করতে শুধু read-গুলো আরেকটা endpoint-এ পাঠালেই হয়।

RDS / Aurora read replicaElastiCache
Code বদলাতে হয়?সামান্য: read পাঠাও replica endpoint-এহ্যাঁ: application-কে caching-এর logic লিখতে হয়
Read latencyMillisecond (এটা তো database-ই)Microsecond (memory)
কী উত্তর দিতে পারেযেকোনো SQL queryশুধু যে key তুমি রেখেছ
কতটা হালনাগাদReplica lag, সাধারণত এক সেকেন্ডের কমতোমার caching pattern আর TTL যতটা পুরনো হতে দেয়
সাধারণ ব্যবহারReport আর সাধারণ read traffic সরানোবারবার আসা গরম read; session; leaderboard; counter

যেকোনো cache-এর সাথে আরও দুটো খরচ আসে:

  • Stale data। Cache রাখে একটা কপি। Database বদলালে কপিটা পুরনো থেকে যেতে পারে, যতক্ষণ না সেটা নতুন করা হয় বা মেয়াদ ফুরায়। যেখানে হালনাগাদ data জরুরি, সেখানে application-এর একটা invalidation strategy লাগে।
  • আরও একটা জিনিস যার size ঠিক করতে হয়, সুরক্ষিত রাখতে হয়, নজরে রাখতে হয়। হঠাৎ cache উধাও হলে সব read একসাথে database-এ গিয়ে পড়ে (“cache stampede” অংশে আরও আছে)।

#Engine তিনটা: Valkey, Redis OSS আর Memcached

ElastiCache তিনটা engine চালায়। Note আর বেশিরভাগ পরীক্ষার প্রশ্ন বলে Redis আর Memcached-এর কথা; ২০২৪ থেকে AWS Valkey-ও দেয়, আর নিজের Redis engine-এর নাম বদলে রেখেছে Redis OSS।

  • Redis OSS (পুরো নাম Remote Dictionary Server) হলো open-source Redis, ElastiCache-এ ৭.x version পর্যন্ত। এটা শুধু cache না: সমৃদ্ধ data structure, replication আর snapshot সহ একটা in-memory data store।
  • Valkey হলো Redis 7.2-এর open-source fork, ২০২৪-এ Redis তার license বদলানোর পর তৈরি, চালায় Linux Foundation। Protocol আর command হুবহু এক, তাই Redis-এর client আর code কিছু না বদলেই চলে। AWS এখন Valkey-কেই default হিসেবে সুপারিশ করে: অন্য engine-এর চেয়ে node-এ প্রায় ২০% সস্তা, Serverless-এ ৩৩% সস্তা, আর Serverless-এ সর্বনিম্ন storage বিল ১ GB-র বদলে ১০০ MB।
  • Memcached অনেক সরল, পুরনো একটা cache: শুধু key আর value, অনেকগুলো thread, ব্যস।

এই লেসনে পরীক্ষার প্রশ্নে “Redis” মানে Valkey বা Redis OSS: Redis-এর যেকোনো উত্তর Valkey-র বেলাতেও খাটে।

Valkey / Redis OSSMemcached
Data typeString, hash, list, set, sorted set, bitmap, সম্ভাবনাভিত্তিক counter, geospatial index, streamশুধু সাধারণ string (object)
Replicationহ্যাঁ: প্রতিটা shard-এ একটা primary আর সর্বোচ্চ ৫টা read replicaনা
Multi-AZ, automatic failoverহ্যাঁ (cluster mode disabled-এ ঐচ্ছিক, enabled-এ বাধ্যতামূলক)না
Persistence আর backupS3-এ snapshot: প্রতিদিন নিজে থেকে (৩৫ দিন পর্যন্ত রাখা যায়) আর হাতে নেওয়া; নতুন cluster-এ restoreNode-based cluster-এ না; data থাকে শুধু RAM-এ (Memcached-এর ElastiCache Serverless backup নিতে পারে)
Partitioning (sharding)Cluster mode enabled হলেহ্যাঁ: client key-গুলো সর্বোচ্চ ৬০টা node-এ ছড়িয়ে দেয়
ThreadCommand চলে একটা thread-এ (বড় node-এ network I/O-র জন্য বাড়তি thread)Multi-threaded: বড় node-এর সব core কাজে লাগায়
Pub/sub, transaction, Lua scriptআছেনেই
Global Datastore (Region পেরিয়ে)আছেনেই
AuthenticationAUTH token, RBAC user, IAM (Valkey 7.2+ / Redis OSS 7.0+)SASL
EncryptionIn transit (TLS) আর at rest (KMS)In transit ১.৬.১২ version থেকে; at rest Serverless-এ

কখন কোনটা নেবে:

  • Valkey বা Redis OSS, যখন লাগবে high availability (Multi-AZ, automatic failover), read replica, persistence / backup আর restore, জটিল data type (leaderboard, queue, geo), pub/sub, বা এমন session store যেটা node নষ্ট হলেও টিকে থাকবে। প্রায় সব ক্ষেত্রেই এটা লাগে, এজন্য পরীক্ষায় “cache”-এর default উত্তর Redis।
  • Memcached, যখন সাধারণ object-এর জন্য সবচেয়ে সরল cache চাও, বড় node-এ multi-threaded performance চাও, ইচ্ছেমতো node যোগ-বাদ দিতে চাও, আর cache-এর data হারালেও সমস্যা নেই (database থেকে আবার বানানো যায়)।

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

একটা team render করা product page cache করে। Page-গুলো সবসময় database থেকে আবার বানানো যায়, node-গুলো বড় ১৬-vCPU instance, আর team চায় replication ছাড়া সবচেয়ে সরল multi-threaded cache। কোন engine সবচেয়ে মানানসই?

#Topology: node-গুলো কীভাবে সাজানো

#Cluster mode disabled: একটাই shard

Cluster mode disabled হলে একটা Valkey বা Redis OSS cluster-এ (API-তে নাম replication group) shard থাকে ঠিক একটা: একটা primary node, যে read আর write দুটোই নেয়, আর ০ থেকে ৫টা read replica, যারা তাকে asynchronously কপি করে।

  • Primary endpoint সবসময় এখনকার primary-কে দেখায়; write পাঠাও সেখানে।
  • Reader endpoint connection-গুলো replica-দের মধ্যে ভাগ করে দেয়; read পাঠাও সেখানে।
  • Replica রাখো অন্য AZ-এ, আর Multi-AZ with automatic failover চালু করো: primary নষ্ট হলে ElastiCache একটা replica-কে primary বানায়, সাধারণত কয়েক সেকেন্ডে, আর primary endpoint-এর DNS বদলে দেয়। Replication asynchronous বলে শেষ কয়েকটা write হারাতে পারে।
  • Read বাড়াও replica যোগ করে; memory আর write বাড়ানো যায় শুধু বড় node type নিয়ে (vertical scaling)।

#Cluster mode enabled: অনেকগুলো shard

Cluster mode enabled হলে key-এর পুরো জায়গাটা ১৬,৩৮৪টা hash slot-এ ভাগ হয়ে কয়েকটা shard-এ ছড়িয়ে থাকে। প্রতিটা shard-এর নিজের primary আর সর্বোচ্চ ৫টা replica।

  • Write বাড়ে horizontally: প্রতিটা shard-এর primary নিজের slot-গুলোর write নেয়।
  • Default quota প্রতি cluster-এ ৯০টা node, বাড়িয়ে ৫০০ node পর্যন্ত নেওয়া যায় (Valkey বা Redis OSS ৫.০.৬ ও পরের version)। উদাহরণ: replica ছাড়া ৫০০টা shard, অথবা ১ primary + ৫ replica-র ৮৩টা shard (৮৩ × ৬ = ৪৯৮)।
  • চালু অবস্থাতেই shard যোগ-বাদ দেওয়া যায় (online resharding)।
  • Automatic failover এখানে বাধ্যতামূলক।
  • Client-কে cluster-aware হতে হয়, আর কয়েকটা key একসাথে ধরা command চলে কেবল যদি সব key একই slot-এ থাকে।

Memcached-এর নিজস্ব সরল sharding আছে: সর্বোচ্চ ৬০টা node-এর cluster, আর client প্রতিটা key-এর hash করে একটা node-এ পাঠায়। কোনো node-এর কোনো replica নেই।

Replication, failover আর backup

Cluster mode disabled একটা Valkey (বা Redis OSS) cluster: দুই AZ-এ একটা primary আর একটা replica। এর সাথে Memcached cluster মিলিয়ে দেখো, যে শুধু key-গুলো কয়েকটা node-এ ভাগ করে রাখে।

পরিস্থিতি

AZ a
AZ b
App tier
primarywrite
replica
set score
ধাপ 1 / 3
1

Application write করে primary endpoint-এ। Write নেয় শুধু primary।

#ElastiCache Serverless

ElastiCache Serverless (নভেম্বর ২০২৩ থেকে) node-এর size ঠিক করার ঝামেলা পুরোই সরিয়ে দেয়। Cache-এর একটা নাম দাও, একটা endpoint পাবে; memory, compute আর network ElastiCache নিজেই বাড়ায়।

  • Valkey, Redis OSS আর Memcached তিনটাতেই চলে; ভেতরে cluster mode-এ একটা proxy-র পেছনে চলে, তাই client-এর শুধু TLS জানলেই হয়।
  • Data নিজে থেকেই কয়েকটা AZ-এ replicate হয়, availability SLA ৯৯.৯৯%।
  • সবসময় in transit আর at rest encrypted।
  • বিল হয় জমা data (GB-hour) আর ElastiCache Processing Unit (ECPU) দিয়ে: ১ KB পর্যন্ত একটা সাধারণ read বা write-এ ১ ECPU, ৩.২ KB-র write-এ ৩.২ ECPU, আর বেশি CPU খাওয়া command-এ আরও বেশি। us-east-1-এ Valkey Serverless-এর দাম মোটামুটি প্রতি GB-hour $0.084 আর প্রতি দশ লাখ ECPU-তে $0.0023।

নতুন, হঠাৎ ওঠানামা করা বা আগে থেকে বোঝা যায় না এমন workload-এ, আর capacity নিয়ে মাথা ঘামাতে না চাইলে Serverless নাও; node type, parameter group-এর ওপর পুরো নিয়ন্ত্রণ আর স্থির, অনুমানযোগ্য load-এ সবচেয়ে কম খরচ চাইলে node-based cluster নাও।

#Global Datastore

Global Datastore (Valkey আর Redis OSS, node-based cluster) একটা cluster-কে আরও সর্বোচ্চ দুটো Region-এ replicate করে। Primary cluster write নেয়; secondary cluster-গুলো শুধু পড়ার কপি, asynchronously আপডেট হয়, সাধারণত এক সেকেন্ডের মধ্যে। কাজে লাগে সারা বিশ্বে কাছ থেকে দ্রুত read-এর জন্য আর Region পেরিয়ে disaster recovery-র জন্য: primary Region নষ্ট হলে একটা secondary cluster-কে primary বানিয়ে দাও।

#Security

Cache-এর নিরাপত্তা কয়েক স্তরে কাজ করে, ঠিক RDS-এর মতো (লেসন ৭.৪):

  1. Network: VPC আর security group। Node-based cache চলে তোমার VPC-তে, একটা cache subnet group-এর private subnet-এ, কোনো public IP নেই। Cache-এর security group cache-এর port (Valkey/Redis OSS-এ 6379, Memcached-এ 11211) খোলে শুধু application tier-এর security group থেকে, ঠিক যেভাবে EC2-কে RDS-এ ঢুকতে দাও। “অন্য EC2 যেন cache-এ ঢুকতে না পারে” প্রশ্নের উত্তর এটাই।
  2. API-র জন্য IAM। কে ElastiCache API ডাকতে পারবে, IAM policy সেটা ঠিক করে: cluster বানানো, বদলানো, মোছা, snapshot নেওয়া। শুধু এটা দিয়ে কে key পড়বে বা লিখবে সেটা নিয়ন্ত্রণ হয় না।
  3. Data-তে ঢোকার authentication (Valkey / Redis OSS):
    • Redis AUTH token: cluster-এ একটা password বসানো থাকে; কোনো command চালানোর আগে প্রতিটা client-কে সেটা পাঠাতে হয় (AUTH <token>)। Security group-এর ওপরে এটা বাড়তি একটা স্তর, আর এটার জন্য in-transit encryption চালু থাকতে হয়।
    • RBAC user আর user group (Redis OSS 6.0+, Valkey): আলাদা আলাদা user, প্রত্যেকের নিজের password আর access string, যেমন session:* key-তে শুধু পড়ার অনুমতি। একটাই শেয়ার করা token-এর বদলে এটা।
    • IAM authentication (Valkey 7.2+, Redis OSS 7.0+): application তার IAM role দিয়ে একটা স্বল্প মেয়াদের IAM token (১৫ মিনিট চলে) সই করে password-এর বদলে পাঠায়; IAM policy-তে লাগে elasticache:Connect। TLS লাগে; নতুন করে authenticate না করলে IAM connection ১২ ঘণ্টা পর কেটে যায়। কোনো password রাখা বা বদলানোর ঝামেলা নেই।
  4. Encryption। In transit: client আর node-এর মধ্যে, node-দের নিজেদের মধ্যে TLS; at rest: disk, snapshot আর swap-এর জন্য KMS, AWS managed key বা তোমার নিজের customer managed key দিয়ে।
  5. Memcached সমর্থন করে SASL authentication (১.৫.১৬+ version): প্রতিটা client-এর username আর password। Node-based cluster-এ এর AUTH token, RBAC বা IAM authentication নেই।

#Caching pattern

Data কখন cache-এ ঢুকবে, কখন বেরোবে, আর কতটা পুরনো হতে পারবে, সেটা ঠিক করে pattern।

#Lazy loading (cache-aside)

  1. আগে cache পড়ো

    Application cache-এর কাছে key-টা চায়, যেমন user:7।

  2. Hit: সাথে সাথে উত্তর

    Key থাকলে (cache hit) application সেটাই ফেরত দেয়। Database-কে কিছুই করতে হয় না।

  3. Miss: database পড়ো, তারপর cache ভরো

    Key না থাকলে (cache miss) application database-এ query চালায়, ফলটা user-কে দেয়, আর cache-এ লিখে রাখে, যাতে পরের read hit হয়।

  • সুবিধা: কেউ যে data সত্যিই চেয়েছে, শুধু সেটাই cache-এ যায়, তাই memory নষ্ট হয় না। Cache node নষ্ট বা খালি হলেও সর্বনাশ হয় না: read শুধু miss করে database-এ যায় (ধীর, কিন্তু ঠিক)।
  • অসুবিধা:
    • Miss penalty: একটা miss-এ তিনটা যাত্রা (cache get → database query → cache set), তাই প্রথম read সরাসরি database পড়ার চেয়েও ধীর।
    • Stale data: Database আপডেট হলে cache জানে না; key-এর মেয়াদ না ফুরানো বা মুছে না দেওয়া পর্যন্ত পাঠক পুরনো value দেখে।
  • সমাধান: প্রতিটা key-তে একটা TTL (time to live, যেমন ১ ঘণ্টা) দাও। তাহলে stale data সর্বোচ্চ এক TTL বাঁচে। অনেক application row আপডেট করার সময় key-টাও মুছে দেয়, যাতে পরের read নতুন করে আনে।

Lazy loading (cache-aside)

Application আগে cache-কে জিজ্ঞেস করে, miss হলে তবেই database-এ যায়। দেখো একটা miss, একটা hit, database বদলানোর পর পুরনো (stale) data পড়া, TTL শেষ হওয়া, আর একটা cache stampede।

পরিস্থিতি

User
App server
ElastiCachememory-তে
RDS database
profile 7 খোলোget user:7
ধাপ 1 / 4
1

একজন user profile 7 খুলল। Cache-এ এটা আছে কি না application জানে না, তাই সে সবসময় আগে cache-কেই জিজ্ঞেস করে।

Hit ratio কতটা জরুরি? Hit ratio h হলে database পায় সব read-এর (1 − h) ভাগ, আর গড় read latency হয় h × (cache-এ এক যাত্রা) + (1 − h) × (cache-এ যাত্রা + database query + cache-এ যাত্রা)। প্রতি সেকেন্ডে ১০,০০০ read আর ৯০% hit ratio হলে database পর্যন্ত যায় সেকেন্ডে মাত্র ১,০০০টা। Cache ০.৫ ms আর query ১০ ms হলে গড় read লাগে ০.৯ × ০.৫ + ০.১ × ১১ = ১.৫৫ ms, ১০ ms-এর জায়গায়। ঠান্ডা cache-এ (০% hit) প্রতিটা read ১১ ms: cache না থাকার চেয়েও ধীর।

Cache hit ratio calculator

সংখ্যায় lazy loading। Slider সরাও আর দেখো hit ratio কীভাবে ঠিক করে database-এ কত চাপ থেকে যায়, আর user-রা গড়ে কত দ্রুত উত্তর পায়।

চেষ্টা করো:

Database পর্যন্ত যাওয়া read

1,000 প্রতি সেকেন্ডে

90% database-এর read চাপ কমল

গড় read latency

1.55 ms

90.0% × 0.50 + 10.0% × 11.0 ms

একটা hit0.50 ms
একটা miss (৩ যাত্রা)11.0 ms
গড় read latency1.55 ms
Cache ছাড়া10.0 ms

#Write-through

Application যখনই database-এ write করে, একই code-এর পথে নতুন value-টা cache-এও লিখে দেয়।

  • সুবিধা: এভাবে লেখা data-র জন্য cache কখনো stale হয় না, আর সেই data-র read সবসময় hit। User সবসময় সর্বশেষ value দেখে।
  • অসুবিধা:
    • Write penalty: প্রতিটা update-এ দুবার write, তাই write ধীর। User-রা সাধারণত মেনে নেয়, কারণ read-এর তুলনায় write কম হয়, আর write-এ একটু সময় লাগবে বলেই সবাই ধরে নেয়।
    • Cache churn: যা লেখা হয় সবই cache-এ যায়, এমনকি যে data কেউ কোনোদিন পড়বে না সেটাও, ফলে memory নষ্ট হয়, দরকারি key-ও বেরিয়ে যেতে পারে।
    • Data না থাকা: নতুন বা বদলানো node-এ, বা cache চালুর আগে লেখা data-র ক্ষেত্রে, আবার write না হওয়া পর্যন্ত data cache-এ থাকে না।

Write-through caching

প্রতিটা write যায় database-এ আর cache-এ দুই জায়গায়, তাই read সবসময় হালনাগাদ data পায়। খরচটাও দেখো: দুবার write, কেউ পড়ে না এমন data-য় ভরা cache, আর কিছু ফাঁক যা lazy loading দিয়ে ভরাতে হয়।

পরিস্থিতি

User
App
ElastiCache
RDS
item 9-এর দাম = ১৫
ধাপ 1 / 5
1

দোকানের manager item 9-এর দাম বদলাল।

#দুটো মেলাও, সাথে TTL

দুটো pattern একে অন্যের দুর্বলতা ঢাকে, তাই বাস্তবে সাধারণত দুটোই চলে:

  • Lazy loading miss হলে cache ভরে (নতুন node, পুরনো data)।
  • Write-through data বদলালে সেটা হালনাগাদ রাখে।
  • প্রতিটা key-তে TTL কেউ না পড়া data সরিয়ে দেয় (churn) আর যেকোনো হারানো update কতক্ষণ stale থাকবে তার সীমা টানে।
Lazy loadingWrite-through
Data cache-এ ঢোকেRead miss হলেপ্রতিটা write-এ
Stale dataহতে পারে, TTL বা delete পর্যন্তনা (যদি না cache write ব্যর্থ হয়)
PenaltyRead miss: ৩ যাত্রাপ্রতিটা write: ২ বার লেখা
Memory খরচশুধু যা পড়া হয়যা লেখা হয় সব (churn)
Node নষ্ট / নতুন nodeসমস্যা নেই: miss হয়ে আবার ভরেআবার না লেখা পর্যন্ত data নেই
পরীক্ষার ভাষা“Cache memory কমাও, প্রথম read-এ একটু দেরি চলবে”“Cache-এর data কখনো stale হবে না, read হবে দ্রুত”

আরও দুটো ছোট pattern-এর নাম জেনে রাখো: write-behind (এখন cache-এ লেখো, পরে database-এ পাঠাও; দ্রুত কিন্তু ঝুঁকির) আর refresh-ahead (গরম key-এর মেয়াদ ফুরানোর একটু আগেই নতুন করে আনো)।

#আসল কঠিন কাজ cache invalidation

Programmer Phil Karlton যেমন বলেছিলেন: “There are only two hard things in Computer Science: cache invalidation and naming things.”

কঠিন জায়গাটা হলো বোঝা, cache-এর কপিটা কখন আর সত্যি নেই। কাজের নিয়ম:

  • Update-এর সময় key-তে নতুন value বসানোর চেয়ে key মুছে দেওয়া ভালো; পরের read আসল সত্যটা নিয়ে আসবে।
  • সবসময় একটা TTL দাও, write-through key-তেও, নিরাপত্তা জাল হিসেবে।
  • TTL ঠিক করো business কতটা পুরনো data সহ্য করতে পারে তা দেখে: stock আর দামের জন্য কয়েক সেকেন্ড, profile-এর জন্য কয়েক মিনিট, product catalogue-এর জন্য কয়েক ঘণ্টা।
  • যে data প্রতি মুহূর্তে একদম নির্ভুল হতে হবে (payment-এর সময় account balance), সেটা কখনো cache কোরো না; database থেকে পড়ো।

#Eviction: memory ভরে গেলে

একটা cache node-এর RAM নির্দিষ্ট। ভরে যাওয়ার পর নতুন key এলে কী সরবে, তা ঠিক করে maxmemory policy:

Policyকী evict করে
volatile-lru (ElastiCache-এর default)TTL দেওয়া key-দের মধ্যে সবচেয়ে কম সম্প্রতি ব্যবহৃতটা
allkeys-lruসব key-এর মধ্যে সবচেয়ে কম সম্প্রতি ব্যবহৃতটা: শুধু cache হলে ভালো পছন্দ
volatile-lfu / allkeys-lfuসবচেয়ে কম বার ব্যবহৃতটা (LFU)
volatile-ttlযার মেয়াদ সবচেয়ে কাছে
volatile-random / allkeys-randomএলোমেলো একটা key
noevictionকিছুই না: write ব্যর্থ হয় out-of-memory error দিয়ে

Memcached সবসময় LRU দিয়ে evict করে। CloudWatch-এর Evictions আর DatabaseMemoryUsagePercentage metric নজরে রাখো: একটানা eviction মানে cache ছোট হয়ে গেছে (বড় করো বা ছড়াও), নয়তো key-তে TTL নেই। volatile-lru-তে TTL ছাড়া key কখনো evict হয় না, তাই এমন key-তে ভরা cache শেষে out-of-memory error দেয়।

#Cache stampede (thundering herd)

কোনো hot key-এর মেয়াদ ফুরালে, বা একটা cache node বদলে খালি হয়ে ফিরলে, একই মুহূর্তে শত শত request miss করে আর সবাই একই ভারী query চালায়। Database-কে বানানো হয়েছিল স্বাভাবিকভাবে miss করা ১০% read-এর মাপে, হঠাৎ সে পায় সবগুলো। ঠেকানোর উপায়:

  • একজনই আবার বানাবে: প্রথম request একটা ছোট lock নেয় (SET lock:home 1 NX EX 5) আর key আবার আনে; বাকিরা একটু অপেক্ষা করে বা পুরনো value দেয়।
  • Jitter: প্রতিটা TTL-এ এলোমেলো কয়েক সেকেন্ড যোগ করো, যাতে সব key একসাথে না ফুরায়।
  • সবচেয়ে গরম key-গুলো মেয়াদ ফুরানোর আগেই নতুন করো, আর নতুন cache-এ traffic পাঠানোর আগে তাকে গরম করে নাও।
  • একটা replica রাখো, যাতে node নষ্ট হলে খালি cache না হয়ে failover হয়।

#Session store

ElastiCache-এর দ্বিতীয় চিরাচরিত কাজ session রাখা। Application একটা এলোমেলো ID-তে (sess:a1f) session লেখে, TTL দেয় session timeout-এর সমান; browser cookie-তে রাখে শুধু ID; প্রতিটা web server session পড়ে cache থেকে। প্রতিটা request TTL আবার নতুন করে দেয়, তাই সক্রিয় user log in থাকে আর চুপ থাকা session নিজেই মেয়াদ ফুরিয়ে যায়।

লেসন ৬.৪-এর সমস্যাটার (server মরলে sticky session cart হারায়) আসল সমাধান এভাবেই হয়। Session-এর জন্য নাও replica আর Multi-AZ সহ Valkey বা Redis OSS (বা Serverless), কারণ session store হারালে সব user একসাথে log out; session পুরোপুরি টেকসই রাখতে হলে DynamoDB।

Session store হিসেবে ElastiCache

ALB-র পেছনের দুটো web server নিজের memory-তে কোনো session রাখে না। প্রতিটা request session পড়ে ElastiCache থেকে, তাই যেকোনো server যেকোনো user-কে সামলাতে পারে।

পরিস্থিতি

Browser
ALB
web-110.0.1.10
web-210.0.2.10
ElastiCachesession store
log in
ধাপ 1 / 3
1

User log in করল। ALB round robin দিয়ে web-1 বাছল; কোনো stickiness চালু নেই।

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

একটা application lazy loading ব্যবহার করে। Database-এ একটা product-এর দাম বদলানোর পরও customer-রা কয়েক ঘণ্টা ধরে পুরনো দাম দেখছে। Memory খরচ কম রেখে সবচেয়ে কম খাটুনিতে কোন পরিবর্তন এটা ঠিক করবে?

#Valkey আর Redis OSS আর কীসে পটু

Valkey আর Redis OSS-এর আসল data structure আছে, আর প্রতিটা command একবারে পুরোটা (atomically) চলে, তাই database বা Memcached যে কাজ ভালো পারে না, এরা সেগুলো সহজে করে।

#Sorted set দিয়ে gaming leaderboard

লাখ লাখ player-কে score অনুযায়ী সাজানো relational database-এ ব্যয়বহুল: প্রতিটা page view-এ একটা ORDER BY score DESC। Sorted set member-দের unique রাখে আর score অনুযায়ী সবসময় সাজানো রাখে। প্রতিটা নতুন score real-time-এ নিজের জায়গায় বসে যায়, O(log N) সময়ে।

  • ZADD game:lb 4200 rafi একজন player যোগ বা আপডেট করে।
  • ZINCRBY game:lb 50 rafi point বাড়ায়।
  • ZREVRANGE game:lb 0 2 WITHSCORES top 3 ফেরত দেয়।
  • ZREVRANK game:lb rafi একজনের rank বলে দেয়।

Sorted set দিয়ে real-time leaderboard

প্রত্যেক player একটা sorted set-এর member, score হলো সাজানোর চাবি। Point দাও আর দেখো প্রতিটা write-এর সাথে set নিজেই নিজেকে নতুন করে সাজায়, তারপর এক command-এ top 3 পড়ো।

Point দাও:
RankPlayerScore
1rafi4,200
2mitu3,900
3arif3,650
4nila3,100
5tanvir2,800
6sara2,450

Top 3 (game-এর screen-এ যা দেখায়)

1) rafi 4200 2) mitu 3900 3) arif 3650

Cache-এ পাঠানো command

  • > ZADD game:leaderboard 4200 rafi 3900 mitu 3650 arif …

প্রতিটা update-এর খরচ O(log N), আর set সবসময় সাজানোই থাকে, তাই দশ লাখ player হলেও microsecond-এ rank বের হয়। Database হলে প্রতিটা read-এ ORDER BY চালাতে হতো।

#Chat আর notification-এর জন্য pub/sub

Pub/sub-এ publisher একটা channel-এ message পাঠায় (PUBLISH room:42 "hi"), আর যত subscriber connect হয়ে আছে (SUBSCRIBE room:42) সবাই সাথে সাথে পায়। Real-time chat, live notification আর অনেক server-কে একসাথে খবর পাঠানোর জন্য মানানসই। Message পাঠিয়েই খালাস: offline থাকা subscriber সেটা আর পায় না। Message জমিয়ে রেখে পরে আবার চালাতে চাইলে stream (বা SQS, Kinesis) নাও।

#Counter দিয়ে rate limiting

INCR atomic, তাই অনেক server নিরাপদে একটাই key-তে গুনতে পারে। প্রতি user প্রতি মিনিটে ১০০ request-এর একটা fixed-window limiter:

  1. INCR rate:user42:202610251430 (key-এর ভেতরে এখনকার মিনিট)।
  2. প্রথমবার বাড়ানোর সময় key-তে ৬০ সেকেন্ডের EXPIRE দাও।
  3. Counter ১০০ পেরোলে request ফিরিয়ে দাও HTTP 429 দিয়ে।

#Geospatial: “কাছের driver দেখাও”

Uber বা Foodpanda-র মতো app-এর লাগে “আমার ২ km-এর মধ্যে কোন driver বা restaurant আছে”। GEOADD drivers 90.4125 23.8103 d17 একজন driver-এর অবস্থান রাখে; GEOSEARCH drivers FROMLONLAT 90.41 23.81 BYRADIUS 2 km ASC microsecond-এ সবচেয়ে কাছেরগুলো ফেরত দেয়।

#Distributed lock (সংক্ষেপে)

SET lock:order:991 <owner> NX PX 10000 সফল হয় শুধু একজন client-এর জন্য, তাই order 991 নিয়ে কাজ করে কেবল একটা worker; worker crash করলে lock নিজেই মেয়াদ ফুরিয়ে খুলে যায়। একই কাজ দুবার হওয়া ঠেকাতে ভালো; যেখানে নির্ভুলতা জীবন-মরণ, সেখানে database বা DynamoDB-র conditional write বেশি নিরাপদ।

#MemoryDB: যখন in-memory store-টাই database

Amazon MemoryDB হলো একটা টেকসই, Valkey আর Redis OSS-এর সাথে মেলানো primary database। তোমার code-এর কাছে এটা দেখতে Redis-এর মতোই, কিন্তু প্রতিটা write acknowledge করার আগে একটা Multi-AZ transactional log-এ commit হয়, তাই node নষ্ট হলেও acknowledge করা কোনো write হারায় না।

ElastiCacheMemoryDB
ভূমিকাDatabase-এর সামনের cache, বা session storeনিজেই primary database
টেকসই কতটাReplica asynchronous; failover-এ সাম্প্রতিক write হারাতে পারে; snapshotপ্রতিটা write Multi-AZ transaction log-এ; node আর AZ হারালেও data টিকে থাকে
ReadMicrosecondMicrosecond
WriteMicrosecondএক অঙ্কের millisecond (log-এ commit)
খরচকমবেশি

পরীক্ষার keyword: “durable in-memory database”, “Redis-compatible primary database”, “microsecond read আর কোনো data হারানো চলবে না” → MemoryDB। “Cache”, “database-এর চাপ কমাও”, “session state” → ElastiCache।

#System design-এ caching

  • গরম, বারবার আসা, একটু পুরনো হলেও চলে এমন read cache করো: product page, profile, configuration, ভারী query-র ফল। যে data একদম নির্ভুল হতে হবে, সেটা সরাসরি database থেকে পড়ো।
  • Default pattern: lazy loading + write-এর সময় delete + প্রতিটা key-তে TTL; লেখার ঠিক পরেই যে data পড়া হয়, তার জন্য write-through যোগ করো।
  • যা হঠাৎ হারানো চলবে না (session, leaderboard, rate-limit counter), তার জন্য অন্য AZ-এ replica সহ Valkey (বা Serverless)। Memcached শুধু ফেলে দেওয়া যায় এমন object cache-এর জন্য।
  • খালি cache-এর জন্য তৈরি থাকো: database-কে এমন মাপে রাখো যাতে cache failover সামলাতে পারে, jitter দাও, cache গরম করে নাও, আর hot key-কে stampede থেকে বাঁচাও।
  • স্তরে স্তরে cache: edge-এ CloudFront, database-এর সামনে ElastiCache, SQL লাগে এমন read-এর জন্য RDS read replica বা Aurora replica। DynamoDB-র নিজস্ব built-in cache আছে, সেটা DynamoDB-র লেসনে দেখবে।
  • CloudWatch-এ নজর রাখো CacheHitRate, Evictions, CurrConnections, EngineCPUUtilization আর ReplicationLag-এ।

Session আর state-এর মূল ধারণার জন্য System Design-এর লেসন State, cookie আর session দেখো।

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

# 1. The quickest start: a Serverless Valkey cache (encrypted, Multi-AZ, no sizing)
aws elasticache create-serverless-cache --serverless-cache-name app-cache \
  --engine valkey --security-group-ids sg-0cache0123456789 \
  --subnet-ids subnet-0aaa1111 subnet-0bbb2222
aws elasticache describe-serverless-caches --serverless-cache-name app-cache \
  --query "ServerlessCaches[0].[Status,Endpoint.Address]"

# 2. A node-based Valkey cluster: 1 primary + 1 replica in another AZ, failover, TLS, KMS, AUTH token
aws elasticache create-replication-group --replication-group-id sessions \
  --replication-group-description "session store" \
  --engine valkey --cache-node-type cache.r7g.large \
  --num-cache-clusters 2 --multi-az-enabled --automatic-failover-enabled \
  --cache-subnet-group-name private-cache --security-group-ids sg-0cache0123456789 \
  --transit-encryption-enabled --at-rest-encryption-enabled \
  --auth-token 'use-a-long-random-secret-here' \
  --snapshot-retention-limit 7

# 3. Test a failover (promotes the replica)
aws elasticache test-failover --replication-group-id sessions --node-group-id 0001

# 4. Security group: only the app tier may reach port 6379
aws ec2 authorize-security-group-ingress --group-id sg-0cache0123456789 \
  --protocol tcp --port 6379 --source-group sg-0app0123456789

App tier-এর একটা EC2 instance থেকে (endpoint-এর নামটা উদাহরণ):

valkey-cli -h master.sessions.abc123.use1.cache.amazonaws.com -p 6379 --tls -a "$AUTH_TOKEN"

SET user:7 '{"name":"Rina","email":"rina@example.com"}' EX 300   # cache for 5 minutes
GET user:7                                                       # hit
TTL user:7                                                       # seconds left
DEL user:7                                                       # invalidate on update

ZADD game:lb 4200 rafi 3900 mitu 3650 arif                       # leaderboard
ZINCRBY game:lb 500 arif
ZREVRANGE game:lb 0 2 WITHSCORES                                 # top 3

INCR rate:user42:202610251430                                    # rate limiting
EXPIRE rate:user42:202610251430 60

CONFIG GET maxmemory-policy        # on ElastiCache, change it in the parameter group instead
INFO stats                         # keyspace_hits, keyspace_misses, evicted_keys

Python-এ TTL সহ lazy loading:

import json, valkey

cache = valkey.Valkey(host=ENDPOINT, port=6379, ssl=True, password=AUTH_TOKEN)

def get_user(user_id):
    key = f"user:{user_id}"
    hit = cache.get(key)                      # trip 1
    if hit:
        return json.loads(hit)
    row = db.query("SELECT * FROM users WHERE id = %s", user_id)   # trip 2
    cache.set(key, json.dumps(row), ex=300)   # trip 3, TTL 5 minutes
    return row

def update_email(user_id, email):
    db.execute("UPDATE users SET email = %s WHERE id = %s", email, user_id)
    cache.delete(f"user:{user_id}")           # invalidate: next read reloads

#সারসংক্ষেপ

মূল কথাগুলো

  • ElastiCache একটা managed in-memory store: microsecond-এ read, কাজে লাগে database cache (read-heavy workload-এর চাপ সরাতে) আর session store (stateless web tier) হিসেবে। Read replica-র মতো না, এর জন্য application code বদলাতে হয়, আর এটা stale data দিতে পারে।
  • Engine: Valkey (Redis-এর open-source fork, AWS-এর সুপারিশ করা default, node-এ প্রায় ২০% আর Serverless-এ ৩৩% সস্তা), Redis OSS, আর Memcached। Valkey/Redis OSS: replication (প্রতি shard-এ সর্বোচ্চ ৫টা replica), Multi-AZ automatic failover, snapshot (ElastiCache-এ AOF নেই), সমৃদ্ধ data type, pub/sub। Memcached: multi-threaded, শুধু sharding, replication নেই, persistence নেই।
  • Cluster mode disabled: ১টা shard, ১ primary + সর্বোচ্চ ৫ replica, write বাড়াতে বড় node। Cluster mode enabled: অনেক shard, default ৯০ node, সর্বোচ্চ ৫০০। Serverless: GB-hour আর ECPU-র বিল, Multi-AZ, সবসময় encrypted। Global Datastore: আরও সর্বোচ্চ ২টা Region, শুধু পড়ার secondary, DR।
  • Security: network-এর জন্য VPC + security group; API-র জন্য IAM; data-তে ঢুকতে Redis AUTH token (TLS লাগে), RBAC user, বা IAM authentication (Valkey 7.2+ / Redis OSS 7.0+); TLS আর KMS; Memcached-এ SASL।
  • Lazy loading: শুধু যা পড়া হয় তা cache, ৩ যাত্রার miss penalty, stale data। Write-through: কখনো stale না, write penalty, churn, নতুন node-এ data নেই। দুটো মেলাও আর সবকিছুতে TTL দাও।
  • Invalidation আসল কঠিন কাজ: update-এ delete করো, সবসময় TTL দাও। Eviction চলে maxmemory policy মেনে (default volatile-lru; LRU, LFU, TTL, random)। Lock, jitter আর refresh-ahead দিয়ে hot key-কে stampede থেকে বাঁচাও।
  • Valkey/Redis-এর ব্যবহার: leaderboard (sorted set), pub/sub chat, rate limiting (INCR + EXPIRE), geospatial “কাছে কী আছে”, সাধারণ distributed lock।
  • MemoryDB = Multi-AZ transaction log সহ টেকসই Redis-compatible primary database; ElastiCache = cache।