সরাসরি পর্বে যান
পর্ব ৬১ · ৬৭-এর মধ্যে · মডিউল ৯

Cloud database আর DBaaS

Cloud Databases, DBaaS, Serverless, Cost, Security and Migration

Taught in Bangla, this lesson covers cloud databases and DBaaS: self-hosting versus VMs versus managed services, the main managed offerings, regions, availability zones and latency, where the bill comes from, serverless databases and connection storms, multi-tenant SaaS designs, security, compliance and data residency, observability of costly queries, and migration and vendor lock-in.

এই পর্বে যা শিখবেন

  • নিজের সার্ভার, IaaS VM আর DBaaS-এর পার্থক্য, আর shared responsibility model ধাপে ধাপে
  • বড় প্রদানকারী আর ডেভেলপার-কেন্দ্রিক প্ল্যাটফর্মের সেবাগুলো কী ধরনের, নিরপেক্ষভাবে
  • Region, availability zone, latency আর multi-AZ বনাম read replica বনাম cross-region DR
  • দামের মাত্রা দিয়ে মাসিক খরচ হিসাব, খরচ কমানোর অভ্যাস, আর query_log থেকে “দামি” কোয়েরি খোঁজা — লাইভ SQL-এ
  • Serverless-এর connection সমস্যা, multi-tenant নকশা, নিরাপত্তা, data residency, lock-in আর কম বিরতিতে migration

১ · ডেটাবেস কোথায় চলবে — নিজের সার্ভার, ভাড়ার VM, না managed সেবা

পর্ব ৫২-এ (Backup, replication আর high availability) দেখেছেন, একটি ডেটাবেস নিরাপদে চালাতে কত কাজ: backup, WAL archive, replica, failover, monitoring. এখন প্রশ্ন, এই কাজগুলো কে করবে? উত্তর ঠিক করে ডেটাবেস কোথায় চলবে।

বিয়ের দাওয়াতের রান্নার কথা ভাবুন। প্রথম পথ: বাড়ির উঠোনে নিজের হাঁড়ি-চুলায় নিজেরা রাঁধা — সব নিয়ন্ত্রণ আপনার, সব ঝামেলাও। দ্বিতীয় পথ: কমিউনিটি সেন্টারের রান্নাঘর ভাড়া — চুলা, গ্যাস আর ঘর তাদের, কিন্তু বাবুর্চি, বাজার আর রান্না আপনার। তৃতীয় পথ: ক্যাটারিং সার্ভিস — রান্না, পরিবেশন, থালা ধোয়া সব তারা করে। কিন্তু মেনু কী হবে, কতজন আসবেন, কে ঢুকতে পারবেন আর বিল কত উঠল — এগুলো এখনো আপনাকেই ঠিক করতে আর দেখতে হয়।

Self-managed · নিজের সার্ভার বা VPS

অফিসের র‍্যাকে একটি সার্ভার, কোনো হোস্টিং প্রতিষ্ঠানের VPS, বা cPanel হোস্টিংয়ের MySQL. বাংলাদেশের অনেক ছোট ব্যবসা আর স্থানীয় হোস্টিংয়ে এটিই প্রচলিত। খরচ অনুমানযোগ্য, ডেটা চোখের সামনে, কিন্তু update, backup আর রাত তিনটার বিপদ — সব আপনার।

IaaS VM · ক্লাউডে নিজে বসানো

ক্লাউডের একটি virtual machine ভাড়া নিয়ে নিজে PostgreSQL বা MySQL বসানো। হার্ডওয়্যার, বিদ্যুৎ আর নেটওয়ার্ক প্রদানকারীর; OS থেকে ওপরের সবকিছু আপনার। নিয়ন্ত্রণ পুরো, ঝামেলাও প্রায় পুরো।

DBaaS · managed ডেটাবেস

“Database as a Service”: আপনি বলেন কোন engine, কত বড়, কোন region — প্রদানকারী চালায় সার্ভার, patch, backup, PITR আর failover. এর আরেক নাম managed database. বদলে কিছু নিয়ন্ত্রণ (superuser, OS-এ ঢোকা, কিছু extension) ছাড়তে হয়।

বিষয়নিজের সার্ভার/VPSIaaS VMDBaaS
শুরু করতে কত সময়দিন থেকে সপ্তাহঘণ্টামিনিট
engine-এর সংস্করণ ও সেটিংযা খুশিযা খুশিপ্রদানকারীর অনুমোদিত তালিকা থেকে
backup, PITR, failoverনিজে বানাতে হয়নিজে বানাতে হয়কয়েকটি সেটিংয়ে চালু
খরচের ধরনশুরুতে কেনা, পরে স্থিরমাসে মাসে, ব্যবহার অনুযায়ীমাসে মাসে, সাধারণত VM-এর চেয়ে বেশি
দক্ষ মানুষ লাগেDBA + সিস্টেম adminDBA + সিস্টেম adminকম, তবে শূন্য নয়

কোনটি “ভালো” — তা নির্ভর করে দলের দক্ষতা, ডেটার আকার, আইন আর বাজেটের ওপর। একজন ডেভেলপারের একটি ছোট দোকানের সাইটে DBaaS মানুষের সময় বাঁচায়; আবার ২৪ ঘণ্টা ভারী লোডের, অভিজ্ঞ DBA দল থাকা প্রতিষ্ঠান অনেক সময় নিজের সার্ভারে কম খরচে চালায়। তবে একটি জিনিস তিন পথেই একই — দায়িত্বের ভাগ পরিষ্কার জানা চাই। এটিকে বলে shared responsibility model. নিচে স্তর ধরে ধরে দেখুন:

ডেটাবেসের স্তর (নিচ থেকে ওপরে)★ = এই ধাপের স্তর

            
এই স্তর কার?
নিজের সার্ভার
IaaS VM
DBaaS
  1. যন্ত্র আর ভবন। নিজের সার্ভারে UPS, জেনারেটর, ঠান্ডা ঘর আর নষ্ট ডিস্ক বদলানো আপনার (VPS হলে হোস্টিং প্রতিষ্ঠানের)। ক্লাউডে — VM হোক বা DBaaS — এই স্তর পুরোপুরি প্রদানকারীর।
  2. Operating system. VM-এ Linux-এর security patch আপনাকেই দিতে হয়; না দিলে পুরোনো ফাঁক খোলা থাকে। DBaaS-এ OS আপনার চোখেই পড়ে না।
  3. DB engine. DBaaS-এ minor patch সাধারণত আপনার বেছে দেওয়া “maintenance window”-তে নিজে থেকে বসে। কিন্তু major upgrade (যেমন PostgreSQL ১৫ থেকে ১৭) অ্যাপ ভাঙতে পারে — কবে করবেন আর আগে পরীক্ষা করবেন কি না, সেই সিদ্ধান্ত আপনার।
  4. Backup. DBaaS প্রতিদিনের snapshot আর WAL রেখে PITR দেয়। তবে কতদিন রাখা হবে (retention), প্রদানকারীর বাইরে আলাদা কপি রাখবেন কি না, আর restore সত্যিই কাজ করে কি না — পর্ব ৫২-এর এই প্রশ্নগুলো এখনো আপনার।
  5. High availability. একটি সেটিং চালু করলে অন্য zone-এ standby থাকে, আর failover নিজে থেকে হয়। কিন্তু failover-এর মুহূর্তে চলমান সংযোগ কেটে যায় — অ্যাপ আবার যুক্ত হতে আর অসমাপ্ত কাজ নিরাপদে আবার চেষ্টা করতে পারে কি না, সেটি আপনার কোডের দায়।
  6. Schema, index, কোয়েরি। এখানে থেকে দায় কখনো হস্তান্তর হয় না। index ছাড়া কোয়েরি ক্লাউডেও ধীর — শুধু বাড়তি বিল নিয়ে। কিছু সেবা index-এর পরামর্শ দেয়, কিন্তু সিদ্ধান্ত আপনার।
  7. মানুষ, ডেটা আর টাকা। কে কোন টেবিল পড়বে, পাসওয়ার্ড কোথায়, কোন ডেটা আইনত কোথায় থাকতে পারে, আর মাসের শেষে বিল কত — প্রদানকারী এর কোনোটিই আপনার হয়ে ঠিক করে না। ক্লাউডের অনেক ডেটা ফাঁসের ঘটনা আসলে এই স্তরের ভুল, যেমন ভুল করে খোলা রাখা অনুমতি।

২ · বাজারের managed সেবা — নাম আর ধরন

নাম অনেক, কিন্তু ধরন কয়েকটি। এক, চেনা engine-এর managed রূপ — ভেতরে আসল PostgreSQL, MySQL বা SQL Server, প্রদানকারী শুধু চালায়। দুই, “cloud-native” রূপ — বাইরে PostgreSQL বা MySQL-এর মতো কথা বলে, কিন্তু ভেতরের storage প্রদানকারীর নিজের নকশা। তিন, বিশ্বজুড়ে ছড়ানো distributed SQL (পর্ব ৫৪-এর বিষয়)। নিচের তালিকা উদাহরণ মাত্র, কোনো সুপারিশ নয়; সেবার নাম, ফিচার আর শর্ত প্রায়ই বদলায়, তাই সিদ্ধান্তের আগে প্রদানকারীর বর্তমান ডকুমেন্টেশন পড়ুন।

Amazon RDS (২০০৯ সালে MySQL দিয়ে শুরু) — PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, Db2-এর managed রূপ। Amazon Aurora — MySQL- আর PostgreSQL-সামঞ্জস্যপূর্ণ, কিন্তু নিজস্ব বিতরণকৃত storage; সাথে Aurora Serverless নামের স্বয়ংক্রিয়ভাবে বাড়া-কমা রূপ। পাশে key-value ধাঁচের DynamoDB (পর্ব ৫৬-এর NoSQL পরিবারে)।

Cloud SQL — MySQL, PostgreSQL আর SQL Server-এর managed রূপ। AlloyDB for PostgreSQL — PostgreSQL-সামঞ্জস্যপূর্ণ, analytics-এর জন্য বাড়তি column-ধাঁচের cache-সহ। Spanner — বিশ্বজুড়ে ছড়ানো, strongly consistent distributed SQL; পর্ব ৫৪-এ তার TrueTime-এর গল্প।

Azure SQL Database — SQL Server engine-এর managed রূপ, সাথে serverless বিকল্প। Azure Database for PostgreSQL আর Azure Database for MySQL — এখনকার প্রধান রূপের নাম “flexible server”. বিশ্বজুড়ে ছড়ানো NoSQL-এর জন্য Cosmos DB.

ছোট দল আর দ্রুত prototype-এর জন্য জনপ্রিয় কিছু প্ল্যাটফর্ম: Supabase — PostgreSQL-এর সাথে login, file storage আর টেবিল থেকে স্বয়ংক্রিয় API. Neon — serverless PostgreSQL, storage আর compute আলাদা, ডেটাবেসের “branch” বানানো যায়। PlanetScale — MySQL-সামঞ্জস্যপূর্ণ, YouTube-এ জন্মানো sharding ব্যবস্থা Vitess-এর ওপর। Turso — SQLite-এর একটি open-source fork libSQL-এর ওপর, প্রতি ব্যবহারকারী বা প্রতি গ্রাহকের জন্য আলাদা ছোট ডেটাবেসের ধাঁচে। এদের বিনা মূল্যের স্তর আর ফিচার ঘন ঘন বদলায়।

বাছাইয়ের সময় প্রথম প্রশ্ন হওয়া উচিত: engine কি standard? ভেতরে আসল PostgreSQL বা MySQL হলে আপনার SQL, driver আর pg_dump-এর অভ্যাস প্রায় অপরিবর্তিত থাকে, আর দরকারে অন্য জায়গায় সরা সহজ। প্রদানকারীর নিজস্ব API বা query language-এ লিখলে সুবিধা পান, কিন্তু বাঁধাও পড়েন — অংশ ৯-এ সে আলোচনা।

৩ · Region, availability zone আর latency

ক্লাউডের ডেটা সেন্টারগুলো সাজানো দুই স্তরে। একটি region হলো একটি ভৌগোলিক এলাকা, যেমন মুম্বাই বা সিঙ্গাপুর। প্রতিটি region-এ সাধারণত কয়েকটি availability zone (AZ) — আলাদা বিদ্যুৎ, ঠান্ডা আর নেটওয়ার্কের এক বা একাধিক ডেটা সেন্টার, যারা কাছাকাছি কিন্তু একসাথে নষ্ট হওয়ার সম্ভাবনা কম। AZ-গুলোর মধ্যে round trip সাধারণত এক অঙ্কের মিলিসেকেন্ড বা তারও কম, তাই sync replication চলে; region-গুলোর মধ্যে দূরত্ব বেশি, তাই সেখানে async.

বাংলাদেশের ব্যবহারকারীর জন্য region বাছাই একটি বাস্তব প্রশ্ন। লেখার সময় পর্যন্ত বড় ক্লাউডগুলোর কোনো region দেশের ভেতরে আছে বলে সাধারণত জানা যায় না, তাই প্রচলিত কাছের বিকল্প মুম্বাই আর সিঙ্গাপুর (AWS-এ ap-south-1 আর ap-southeast-1, Google Cloud-এ asia-south1 আর asia-southeast1; Azure-এ ভারতের কয়েকটি region আর Southeast Asia). তালিকা বদলায়, আর latency নির্ভর করে আপনার ISP কোন পথে ডেটা পাঠায় তার ওপর — ভৌগোলিকভাবে কাছের region সবসময় দ্রুততম নয়। তাই অনুমান না করে মাপুন। নিচের এডিটরে probes টেবিলে চারটি শহর থেকে চারটি জায়গায় round trip (city, region, rtt_ms) — সংখ্যাগুলো উদাহরণের জন্য বানানো, আসল মাপ নয়। placements টেবিলে চারটি নকশা: ব্যবহারকারী থেকে অ্যাপ সার্ভার, আর অ্যাপ থেকে ডেটাবেস — কত ms.

-- উদাহরণের সংখ্যা (illustrative), নিজের নেটওয়ার্কে মেপে নিন
SELECT region, ROUND(AVG(rtt_ms), 1) AS avg_rtt_ms, MAX(rtt_ms) AS worst_ms
FROM probes
GROUP BY region
ORDER BY avg_rtt_ms;
-- একটি পাতা = ব্যবহারকারীর ১টি round trip + পরপর ৮টি কোয়েরি
SELECT setup, user_to_app_ms + 8 * app_to_db_ms AS page_ms_8_queries
FROM placements
ORDER BY page_ms_8_queries;

প্রথম ফল: dhaka-local-dc | 9 | 12, singapore | 49 | 55, mumbai | 64.3 | 71, frankfurt | 173.3 | 180. দ্বিতীয় ফলটিই আসল শিক্ষা: app+db singapore | 57, app+db mumbai | 72, app+db frankfurt | 181, আর সবার শেষে app dhaka, db singapore | 401. অ্যাপ ঢাকার হোস্টিংয়ে আর ডেটাবেস সিঙ্গাপুরে রাখলে ব্যবহারকারী কাছে, কিন্তু প্রতিটি কোয়েরি সমুদ্র পেরোয় — ৮টি পরপর কোয়েরি মানে ৮ × ৪৯. নিয়ম: অ্যাপ সার্ভার আর ডেটাবেস একই region-এ (সম্ভব হলে একই AZ-এ) রাখুন; দূরত্ব থাকুক ব্যবহারকারী আর অ্যাপের মধ্যে, যেখানে একটি অনুরোধে একবারই পার হতে হয়। “chatty” অ্যাপের (একটি পাতায় শত কোয়েরি, পর্ব ৫০-এর N+1) দাম দূরত্বে বহু গুণ হয়।

জায়গা বাছাইয়ের পর তিনটি আলাদা জিনিস প্রায়ই গুলিয়ে যায়:

Multi-AZ standbyRead replicaCross-region কপি
উদ্দেশ্যHA — একটি zone বা সার্ভার মরলে চালু থাকাপড়ার চাপ ভাগ করাDR — পুরো region অচল হলেও বাঁচা
replicationসাধারণত sync বা প্রায়-syncসাধারণত async, lag থাকেasync, lag বেশি
কোয়েরি নেয়?প্রচলিত রূপে না — শুধু অপেক্ষা করে (কিছু নতুন রূপে পড়া নেয়)হ্যাঁ, শুধু পড়াপড়া নিতে পারে
failoverস্বয়ংক্রিয়, সাধারণত এক-দুই মিনিটের মধ্যেহাতে promote করতে হয়সাধারণত হাতে, পরিকল্পিত runbook ধরে
ভুল DELETE থেকে বাঁচায়?নানানা — বাঁচায় backup আর PITR

৪ · দামের মাত্রা — বিল কোথা থেকে আসে

ক্লাউডের দাম প্রদানকারী, region আর সময় ভেদে বদলায়, তাই এই পর্বে কোনো আসল দাম লেখা হয়নি। কিন্তু প্রায় সব DBaaS-এর বিল কয়েকটি একই মাত্রায় গড়া, আর সেগুলো বুঝলে যেকোনো প্রদানকারীর দামের পাতা পড়া সহজ:

মাত্রাকী দিয়ে মাপা হয়লক্ষ রাখুন
Computeinstance-এর আকার (vCPU, RAM) × চালু থাকার ঘণ্টা; serverless-এ “capacity unit” × সময়সাধারণত বিলের সবচেয়ে বড় অংশ
Storageপ্রতি GB প্রতি মাসঅনেক সেবায় বাড়ে, কিন্তু নিজে কমে না
IOPS / throughputনির্দিষ্ট IOPS কিনে রাখা, অথবা প্রতিটি I/O-র দামঅদক্ষ কোয়েরি এখানে সরাসরি টাকা খায়
Backupretention-এর snapshot আর log-এর GBলম্বা retention আর হাতে নেওয়া snapshot জমতে থাকে
Egress (data transfer)ক্লাউড থেকে বাইরে, বা zone/region পেরিয়ে যাওয়া GBসাধারণত ঢোকা বিনা মূল্যে, বের হওয়ায় দাম — বিলের চমক এখান থেকেই বেশি আসে
Replica আর standbyপ্রতিটি একটি পুরো instancemulti-AZ মোটামুটি compute দ্বিগুণ করে
অন্যান্যবাণিজ্যিক engine-এর license, বাড়তি monitoring, support planSQL Server বা Oracle-এ license-ই বড় অংশ হতে পারে

এবার এই মাত্রাগুলো দিয়ে একটি মাসিক হিসাব। সব দাম কাল্পনিক — একক “CR” (credit), কোনো আসল মুদ্রা বা আসল প্রদানকারীর দাম নয়; শুধু হিসাবের কাঠামো শেখার জন্য। তিনটি টেবিল: instance_classes (class, vcpu, ram_gb, প্রতি ঘণ্টার cr_per_hour), unit_rates (প্রতি GB storage, backup আর egress-এর হার — এক সারি), আর databases — একটি দোকানের চারটি ডেটাবেস: db_name, env (prod/staging/dev), class, hours_on (মাসে কত ঘণ্টা চালু; ৭৩০ ≈ পুরো মাস), storage_gb, backup_gb, egress_gb আর replicas (কয়টি বাড়তি কপি)।

SELECT d.db_name,
       d.hours_on * c.cr_per_hour              AS compute,
       d.replicas * d.hours_on * c.cr_per_hour AS replicas,
       d.storage_gb * u.storage_cr_per_gb      AS storage,
       d.backup_gb  * u.backup_cr_per_gb       AS backup,
       ROUND(d.egress_gb * u.egress_cr_per_gb, 2) AS egress,
       ROUND((1 + d.replicas) * d.hours_on * c.cr_per_hour
             + d.storage_gb * u.storage_cr_per_gb + d.backup_gb * u.backup_cr_per_gb
             + d.egress_gb * u.egress_cr_per_gb, 2) AS total_cr
FROM databases d
JOIN instance_classes c ON c.class = d.class
CROSS JOIN unit_rates u
ORDER BY total_cr DESC;

চার সারি: shop-prod | 584 | 584 | 50 | 24 | 27 | 1269, analytics | 584 | 0 | 80 | 16 | 4.5 | 684.5, shop-staging | 292 | 0 | 10 | 2 | 0.45 | 304.45, shop-dev | 292 | 0 | 5 | 0.8 | 0.18 | 297.98. প্রতিটি column একটি মাত্রা: compute = ৭৩০ ঘণ্টা × ঘণ্টার হার; replica একটি পুরো instance-এর সমান। unit_rates-এর একটিমাত্র সারি CROSS JOIN (পর্ব ২০) দিয়ে প্রতিটি সারির পাশে বসেছে। খেয়াল করুন, এই উদাহরণে compute আর replica-ই বিলের বেশিরভাগ, আর dev ও staging মিলে প্রায় prod-এর একটি instance-এর সমান — অথচ এরা রাতে আর ছুটির দিনে কারও কাজে লাগে না।

খরচ কমানোর অভ্যাস

  • Right-sizing: CPU আর memory-র ব্যবহার কয়েক সপ্তাহ দেখে instance-এর আকার ঠিক করা। “নিরাপদ থাকতে বড়টা নিই” অভ্যাস প্রতি মাসে টাকা খায়।
  • dev/test বন্ধ রাখা: অফিস সময়ের বাইরে বন্ধ, বা প্রয়োজনে চালু হওয়া serverless রূপ।
  • Reserved capacity: সারাক্ষণ চলা prod-এর জন্য এক বা তিন বছরের প্রতিশ্রুতিতে ছাড় — কিন্তু আকার আর engine আগে স্থির হওয়া চাই।
  • Storage আর backup পরিষ্কার: পুরোনো হাতে নেওয়া snapshot, অপ্রয়োজনীয় লম্বা retention, ব্যবহার না হওয়া replica.
  • Egress কমানো: অ্যাপ আর ডেটাবেস একই region/zone-এ; বড় export কাছের storage-এ; শুধু দরকারি column আনা।
  • কোয়েরির দক্ষতা = টাকা: একটি missing index মানে বেশি I/O, বড় instance আর বাড়তি replica — অংশ ৮-এ দেখবেন।

প্রথম দুটি অভ্যাসের ফল হিসাব করি। নিচের এডিটরে একই টেবিল, সাথে monthly_cost নামের একটি view (পর্ব ২৪) — ওপরের সূত্রটিই, প্রতিটি ডেটাবেসের total_cr দেয়। ধরুন dev আর staging সপ্তাহে ৫ দিন, দিনে ১২ ঘণ্টা চলবে (মাসে ≈ ২২ কর্মদিবস × ১২ = ২৬৪ ঘণ্টা), আর monitoring দেখাল analytics-এর CPU বেশিরভাগ সময় অলস, তাই সেটিকে medium-এ নামানো হলো:

SELECT ROUND(SUM(total_cr), 2) AS before_cr FROM monthly_cost;
UPDATE databases SET hours_on = 12 * 22 WHERE env IN ('dev', 'staging');
UPDATE databases SET class = 'medium' WHERE db_name = 'analytics';
SELECT db_name, class, hours_on, total_cr FROM monthly_cost ORDER BY total_cr DESC;
SELECT ROUND(SUM(total_cr), 2) AS after_cr FROM monthly_cost;

আগে 2555.93. দুটি UPDATE-এ প্রথমটি ২টি সারি, দ্বিতীয়টি ১টি সারি বদলায়। তারপর: shop-prod | large | 730 | 1269, analytics | medium | 730 | 392.5, shop-staging | medium | 264 | 118.05, shop-dev | medium | 264 | 111.58; মোট 1891.13 — কাল্পনিক এই উদাহরণে প্রায় এক-চতুর্থাংশ কম, prod-এ হাত না দিয়েই। view নিজে কোনো ডেটা রাখে না, তাই UPDATE-এর পর নতুন মান দিয়ে আবার হিসাব করে। বাস্তবে analytics নামানোর আগে peak সময়ের ব্যবহারও দেখুন — গড় অলস হলেও মাসের শেষের রিপোর্টে হয়তো পুরো CPU লাগে।

৫ · Serverless ডেটাবেস আর connection-এর ঝড়

Serverless database-এ আপনি instance-এর আকার বাছেন না; চাপ বাড়লে ক্ষমতা নিজে বাড়ে (autoscaling), আর কেউ ব্যবহার না করলে কিছু সেবা compute পুরো বন্ধ করে দেয় (scale to zero) — তখন শুধু storage-এর বিল। ছোট প্রকল্প, dev পরিবেশ আর অনিয়মিত চাপের সাইটে এটি সস্তা। দাম: বন্ধ অবস্থা থেকে প্রথম অনুরোধে কিছুটা দেরি (cold start), আর সারাক্ষণ ভারী চাপে নির্দিষ্ট instance-এর চেয়ে প্রায়ই দামি।

আসল ফাঁদটি অন্য জায়গায়। অ্যাপ নিজেও যখন serverless function-এ চলে (AWS Lambda, Google Cloud Run functions, Vercel ইত্যাদি), প্রতিটি সমান্তরাল function instance নিজের ডেটাবেস সংযোগ খোলে। PostgreSQL প্রতিটি সংযোগে একটি আলাদা process চালায় — সংযোগ সস্তা নয়, আর max_connections-এর default মাত্র ১০০. পর্ব ৪৯-এর connection pool এখানে কাজ করে না, কারণ প্রতিটি function instance-এর নিজের আলাদা ছোট pool. একটি ফ্ল্যাশ সেলের সকালে কী হয়:

function instance → ডেটাবেসmax_connections = 100

            
সংখ্যায়
চালু function
ডেটাবেসে সংযোগ
ব্যর্থ অনুরোধ
  1. শান্ত সময়। কয়েকটি function instance, প্রত্যেকে একটি সংযোগ খুলে রেখেছে। এখানে কোনো সমস্যা চোখে পড়ে না — তাই পরীক্ষার সময় এটি ধরা পড়ে না।
  2. চাপের ঢেউ। platform মুহূর্তে শত শত instance চালু করে, আর প্রত্যেকে নিজের সংযোগ চায়। ১০১তম থেকে PostgreSQL সংযোগ ফিরিয়ে দেয়: too many clients already.
  3. Retry-এর ঝড়। ব্যর্থ function আবার চেষ্টা করে, platform আরও instance চালায়। প্রতিটি নতুন সংযোগে TLS handshake, authentication আর নতুন process — ডেটাবেস আসল কাজের বদলে দরজা খোলা-বন্ধে ব্যস্ত। এটিই connection storm.
  4. Pooler. function আর ডেটাবেসের মাঝে একটি PgBouncer-ধাঁচের pooler (managed রূপে RDS Proxy, বা অনেক প্ল্যাটফর্মের নিজস্ব “pooled” সংযোগ ঠিকানা)। transaction pooling মোডে একটি সার্ভার-সংযোগ শুধু একটি transaction-এর সময় একজন client-কে দেওয়া হয়।
  5. ফল আর দাম। ৪০০ client, ডেটাবেসে ২০ সংযোগ — বেশিরভাগ transaction কয়েক ms-এর, তাই সারি দ্রুত এগোয়। কিন্তু একই সংযোগ পরপর আলাদা client পায়, তাই session-এর ওপর নির্ভর করা কিছু (SET দিয়ে বদলানো সেটিং, temp table, advisory lock, কিছু ক্ষেত্রে prepared statement) অন্যের হাতে চলে যেতে পারে বা কাজ করে না।
  6. Data API. কিছু প্ল্যাটফর্ম HTTP বা WebSocket-এর ওপর কোয়েরি নেয় (serverless driver বা data API) — function দীর্ঘ TCP সংযোগ ধরে রাখে না, pool থাকে প্রদানকারীর দিকে। সাথে মনে রাখুন: compute scale to zero হলে প্রথম অনুরোধে cold start-এর দেরি যোগ হয়।

কোডের দিকে দুটি অভ্যাস: সংযোগ বা pool তৈরি করুন handler-এর বাইরে, যাতে একই function instance পরের অনুরোধে সেটি আবার ব্যবহার করে; আর প্রতিটি instance-এর pool ছোট রাখুন (প্রায়ই ১টি সংযোগ)। Node.js-এর pg লাইব্রেরি দিয়ে একটি উদাহরণ (চালানো যাবে না; ঠিকানা আর পাসওয়ার্ড আসে environment থেকে):

import pg from "pg";

// handler-এর বাইরে: warm instance পরের অনুরোধে একই pool পায়
const pool = new pg.Pool({
  connectionString: process.env.DATABASE_URL, // pooler-এর ঠিকানা, কোডে পাসওয়ার্ড নয়
  max: 1,                                     // প্রতি instance-এ একটি সংযোগ
  idleTimeoutMillis: 10000,
});

export async function handler(event) {
  const { rows } = await pool.query(
    "SELECT order_id, status FROM orders WHERE customer_id = $1", [event.customerId]);
  return { statusCode: 200, body: JSON.stringify(rows) };
}

আরও গভীরে: Aurora আর Neon-এর মতো সেবা storage আর compute আলাদা করে। Aurora-র ২০১৭ সালের SIGMOD গবেষণাপত্রের মূল কথা “log-ই ডেটাবেস”: compute শুধু WAL/redo record পাঠায় তিনটি AZ-এ ছড়ানো ছয়টি storage কপিতে, লেখা টেকসই হয় ছয়ের মধ্যে চারটির সম্মতিতে, আর page বানানোর কাজ storage নিজেই করে — তাই replica বা নতুন compute-এর জন্য ডেটা কপি করতে হয় না। Neon একই ভাবনায় copy-on-write branch দেয়: পুরো ডেটাবেসের একটি কপি সেকেন্ডে, যেখানে শুধু বদলানো page নতুন জায়গা নেয় — migration পরীক্ষার জন্য চমৎকার। আর compute-এর কোনো স্থায়ী অবস্থা নেই বলেই scale to zero সম্ভব।

৬ · Multi-tenant SaaS — অনেক গ্রাহক, একটি ডেটাবেস

ক্লাউডের অনেক অ্যাপ একটি সফটওয়্যার অনেক প্রতিষ্ঠানকে বিক্রি করে — যেমন দোকানের হিসাবের একটি POS অ্যাপ, যা ব্যবহার করে শত শত দোকান। প্রতিটি দোকান একটি tenant. নকশা তিন রকম: প্রতি tenant-এর আলাদা ডেটাবেস (বিচ্ছিন্নতা সবচেয়ে বেশি, পরিচালনা সবচেয়ে কঠিন), প্রতি tenant-এর আলাদা schema, আর সবার জন্য একই টেবিলে tenant_id column — সবচেয়ে প্রচলিত আর সস্তা, কিন্তু একটি ভুলে এক দোকানের ডেটা অন্য দোকানে দেখা যায়। এটিই multi-tenant নকশার কেন্দ্রীয় ঝুঁকি।

নিচে tenants (tenant_id, name, plan) আর invoices (tenant_id, invoice_id, customer, amount, issued_on). primary key (tenant_id, invoice_id) — প্রতিটি দোকানের নিজের ক্রমিক নম্বর, আর tenant_id প্রথমে থাকায় index-ও tenant ধরে সাজানো। app_session টেবিলে এখন কোন tenant লগইন করে আছে (২ = Chowdhury Pharmacy), আর my_invoices view শুধু সেই tenant-এর সারি দেখায়। “Karim” নামের গ্রাহক তিনটি দোকানেই আছেন:

-- ভুল: tenant-এর শর্ত ভুলে গেলে
SELECT tenant_id, invoice_id, amount FROM invoices WHERE customer = 'Karim';
-- ঠিক: প্রতিটি কোয়েরিতে tenant_id
SELECT invoice_id, amount FROM invoices
WHERE tenant_id = 2 AND customer = 'Karim';
-- আরও নিরাপদ: শর্তটি ডেটাবেসের ভেতরে বাঁধা
SELECT invoice_id, customer, amount FROM my_invoices WHERE customer = 'Karim';

প্রথম ফল পাঁচ সারি — তিন দোকানের Karim: 1 | 1 | 450, 1 | 3 | 300, 2 | 1 | 2200, 2 | 4 | 150, 3 | 2 | 3500. ফার্মেসির কর্মী এই পাতায় অন্য দুই দোকানের বিক্রিও দেখতেন — একটি ডেটা ফাঁস। দ্বিতীয় আর তৃতীয় ফল একই: 1 | 2200 আর 4 | 150. তৃতীয়টিতে কোয়েরি লেখক tenant-এর কথা ভাবেনইনি, তবু ভুল হয়নি, কারণ শর্তটি view-এর ভেতরে। SQLite-এ এটি শুধু অনুকরণ; PostgreSQL-এ একই কাজের আসল যন্ত্র row-level security (পর্ব ৫১):

ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON invoices
  USING (tenant_id = current_setting('app.tenant_id')::int);
-- অ্যাপ প্রতিটি transaction-এর শুরুতে (pooler-এর সাথেও নিরাপদ):
BEGIN;
SET LOCAL app.tenant_id = '2';
SELECT invoice_id, amount FROM invoices WHERE customer = 'Karim';
COMMIT;

SET LOCAL শুধু ওই transaction-এর জন্য — অংশ ৫-এর transaction pooler-এর সাথে এটিই নিরাপদ, কারণ সাধারণ SET সংযোগে থেকে যায় আর পরের client পেয়ে যেতে পারে। মনে রাখুন, টেবিলের মালিক আর superuser সাধারণত RLS এড়িয়ে যান (মালিকের জন্য FORCE ROW LEVEL SECURITY আছে), তাই অ্যাপ চালান আলাদা, কম ক্ষমতার role দিয়ে।

ক্লাউডে multi-tenant নকশার আরেক প্রশ্ন: কোন গ্রাহক কতটা সম্পদ খায়? একজনের ভারী কোয়েরি সবাইকে ধীর করলে তাকে বলে noisy neighbor. request_log টেবিলে প্রতিদিন প্রতি tenant-এর queries (কতটি কোয়েরি), db_ms (ডেটাবেসে মোট কত ms) আর egress_mb:

SELECT t.name, t.plan,
       SUM(r.queries)          AS queries,
       SUM(r.db_ms) / 1000.0   AS db_seconds,
       ROUND(100.0 * SUM(r.db_ms) / SUM(SUM(r.db_ms)) OVER (), 1) AS pct_db_time,
       ROUND(1.0 * SUM(r.db_ms) / SUM(r.queries), 1)             AS ms_per_query,
       (SELECT COUNT(*) FROM invoices i
        WHERE i.tenant_id = t.tenant_id)                         AS invoice_rows
FROM tenants t
JOIN request_log r ON r.tenant_id = t.tenant_id
GROUP BY t.tenant_id
ORDER BY pct_db_time DESC;

তিন সারি: Ma Electronics | basic | 1550 | 199 | 66 | 128.4 | 2, Chowdhury Pharmacy | pro | 10600 | 84 | 27.9 | 7.9 | 4, Rahman Store | basic | 2500 | 18.5 | 6.1 | 7.4 | 3. সবচেয়ে কম কোয়েরি করা, basic plan-এর Ma Electronics ডেটাবেসের দুই-তৃতীয়াংশ সময় খাচ্ছে — প্রতি কোয়েরিতে গড়ে ১২৮ ms, বাকিদের ৮ ms-এর কম। সন্দেহ: তাদের কোনো রিপোর্ট পুরো টেবিল পড়ছে। SUM(SUM(r.db_ms)) OVER () হলো GROUP BY-এর পরের সারিগুলোর ওপর window (পর্ব ২৬) — সব tenant-এর মোট, তাই ভাগফলটি শতাংশ। এই রিপোর্টই ঠিক করে দেয়: কোয়েরি ঠিক করা, plan-এর দাম বদলানো, না ভারী tenant-কে আলাদা ডেটাবেসে সরানো।

৭ · ক্লাউডে নিরাপত্তা, compliance আর data residency

পর্ব ৫১-এর (ডেটাবেস নিরাপত্তা) সব নিয়ম ক্লাউডেও খাটে, সাথে কয়েকটি ক্লাউড-বিশেষ অভ্যাস:

Private networking

ডেটাবেস থাকুক একটি private network-এর (VPC, VNet) ভেতরে, কোনো public IP ছাড়া। অ্যাপ একই network থেকে যুক্ত হয়; মানুষ ঢোকেন VPN বা bastion দিয়ে। “সবার জন্য খোলা, পাসওয়ার্ড তো আছে” — ইন্টারনেটে খোলা ডেটাবেস স্বয়ংক্রিয় স্ক্যানারের নিশানা।

IAM authentication

স্থায়ী পাসওয়ার্ডের বদলে ক্লাউডের পরিচয়-ব্যবস্থা থেকে স্বল্পমেয়াদি token. অ্যাপের পরিচয়ে অনুমতি, মানুষের জন্য আলাদা ব্যক্তিগত পরিচয়; কেউ চাকরি ছাড়লে একটি জায়গায় বন্ধ।

Encryption আর secrets

disk, backup আর snapshot-এ at-rest encryption, চাবি key-management সেবায়; সংযোগে TLS বাধ্যতামূলক। পাসওয়ার্ড কোডে বা Git-এ নয় — secrets manager-এ, নিয়মিত বদলে।

Audit log

কে কখন instance বদলাল, কে snapshot অন্যকে শেয়ার করল (control plane-এর log), আর কে কোন টেবিল পড়ল (ডেটাবেসের ভেতরের audit, যেমন pgaudit). log নিজেও সুরক্ষিত, আলাদা অ্যাকাউন্টে।

এই অভ্যাসগুলো কোড হিসেবেও লেখা যায়। নিচে একই কথা তিন ভাষায় — শুধু নমুনা, চালানো যাবে না; নাম, network আর আকার আপনার নিজের, আর কোথাও আসল পাসওয়ার্ড নেই:

aws rds create-db-instance \
  --db-instance-identifier shop-db \
  --engine postgres \
  --db-instance-class db.m6g.large \
  --allocated-storage 100 \
  --master-username app_admin \
  --manage-master-user-password \
  --multi-az \
  --storage-encrypted \
  --no-publicly-accessible \
  --enable-iam-database-authentication \
  --backup-retention-period 7 \
  --deletion-protection \
  --db-subnet-group-name shop-private-subnets \
  --vpc-security-group-ids sg-0123456789abcdef0

--manage-master-user-password পাসওয়ার্ড বানিয়ে সরাসরি Secrets Manager-এ রাখে — কমান্ডে বা shell history-তে পাসওয়ার্ড থাকে না।

gcloud sql instances create shop-db \
  --database-version=POSTGRES_16 \
  --edition=ENTERPRISE \
  --tier=db-custom-2-8192 \
  --region=asia-south1 \
  --availability-type=REGIONAL \
  --network=default \
  --no-assign-ip \
  --enable-point-in-time-recovery \
  --database-flags=cloudsql.iam_authentication=on \
  --deletion-protection

REGIONAL মানে অন্য zone-এ standby (HA); --no-assign-ip আর --network মিলে শুধু private IP — এর জন্য network-এ private services access আগে চালু থাকতে হয়।

resource "aws_db_instance" "shop" {
  identifier                          = "shop-db"
  engine                              = "postgres"
  instance_class                      = "db.m6g.large"
  allocated_storage                   = 100
  username                            = "app_admin"
  manage_master_user_password         = true
  multi_az                            = true
  storage_encrypted                   = true
  publicly_accessible                 = false
  iam_database_authentication_enabled = true
  backup_retention_period             = 7
  deletion_protection                 = true
  db_subnet_group_name                = aws_db_subnet_group.private.name
  vpc_security_group_ids              = [aws_security_group.db.id]
}

কোড হিসেবে রাখলে প্রতিটি বদল Git-এ পর্যালোচনা হয়, আর “কেউ console-এ public access চালু করে দিয়েছিল” ধাঁচের ভুল ধরা সহজ।

Compliance আর data residency

Data residency মানে ডেটা ভৌগোলিকভাবে কোথায় জমা থাকবে। কিছু ধরনের ডেটা — সরকারি তথ্য, ব্যাংক বা আর্থিক প্রতিষ্ঠানের গ্রাহক-তথ্য, স্বাস্থ্যের রেকর্ড — দেশের ভেতরে রাখার আইন, নীতিমালা বা নিয়ন্ত্রক সংস্থার নির্দেশনা থাকতে পারে, আর এসব নিয়ম সময়ের সাথে বদলায়। এই পর্ব আইনি পরামর্শ নয়: আপনার প্রতিষ্ঠানের ক্ষেত্রে কী প্রযোজ্য, তা compliance দল, আইনজীবী আর সংশ্লিষ্ট নিয়ন্ত্রকের বর্তমান নির্দেশনা থেকে নিশ্চিত হোন। প্রযুক্তির দিক থেকে মনে রাখার বিষয়: backup, cross-region replica, log আর support-এর জন্য পাঠানো ডেটাও “ডেটা” — শুধু মূল ডেটাবেস কোথায়, তা দেখলে চলে না। দেশের ভেতরে থাকা বাধ্যতামূলক হলে দেশীয় ডেটা সেন্টার বা স্থানীয় ক্লাউড প্রতিষ্ঠান, অথবা মিশ্র নকশা (সংবেদনশীল অংশ দেশে, বাকিটা ক্লাউডে) বিকল্প হতে পারে। ইউরোপের GDPR-এর মতো আইন বিদেশি গ্রাহকের ডেটার ক্ষেত্রেও প্রশ্ন তোলে।

৮ · Observability — কোন কোয়েরি সময় আর টাকা খাচ্ছে

প্রতিটি বড় প্রদানকারী কোয়েরি-স্তরের monitoring দেয় — AWS-এ Performance Insights আর নতুন CloudWatch Database Insights, Google Cloud SQL-এ Query Insights, Azure-এ Query Store-ভিত্তিক Query Performance Insight. নাম যা-ই হোক, ভেতরের ধারণা পর্ব ৫৩-এর pg_stat_statements: একই আকারের কোয়েরি (মান বদলে ? বসানো “fingerprint”) এক সারিতে, সাথে কতবার চলেছে, গড়ে কত সময় আর কত ডেটা পড়েছে। নিচের query_log টেবিলে সেই ধাঁচে এক দিনের হিসাব: fingerprint, calls, mean_ms, rows_per_call আর blocks_read_per_call (প্রতিবার কয়টি page পড়েছে)।

SELECT fingerprint, calls, mean_ms,
       ROUND(calls * mean_ms / 1000.0) AS total_s,
       ROUND(100.0 * calls * mean_ms / SUM(calls * mean_ms) OVER (), 1) AS pct_time
FROM query_log
ORDER BY total_s DESC
LIMIT 3;
-- তুলনা: শুধু "সবচেয়ে ধীর" দেখলে কী পেতাম?
SELECT fingerprint, mean_ms FROM query_log ORDER BY mean_ms DESC LIMIT 1;

প্রথম ফল: orders-এর customer_id দিয়ে খোঁজা 250000 | 38 | 9500 | 77, phone-এর LIKE 40000 | 52 | 2080 | 16.8, আর product_id দিয়ে খোঁজা 900000 | 0.4 | 360 | 2.9. দ্বিতীয় ফল: monthly sales report | 9200. সবচেয়ে ধীর কোয়েরিটি (৯.২ সেকেন্ড) দিনে মাত্র ৩০ বার চলে — মোট ২৭৬ সেকেন্ড, তালিকার প্রথম তিনেও নেই। আসল বোঝা হলো ৩৮ ms-এর একটি “মাঝারি” কোয়েরি, যা আড়াই লাখ বার চলে আর ডেটাবেসের সময়ের ৭৭% নেয়। নিয়ম: অগ্রাধিকার ঠিক করুন মোট সময় (calls × mean) দিয়ে, গড় দিয়ে নয়।

এবার একই টেবিল থেকে টাকার প্রশ্ন। যে সেবায় প্রতিটি I/O-র দাম আছে, বা যেখানে I/O-র চাপে বড় instance লাগে, সেখানে পড়া page-এর সংখ্যাই বিল:

SELECT fingerprint,
       calls * blocks_read_per_call AS blocks_read,
       ROUND(100.0 * calls * blocks_read_per_call
             / SUM(calls * blocks_read_per_call) OVER (), 1) AS pct_io,
       ROUND(1.0 * blocks_read_per_call / rows_per_call) AS blocks_per_row
FROM query_log
ORDER BY blocks_read DESC
LIMIT 3;

তিন সারি: orders-এর কোয়েরি 650000000 | 82.3 | 433, phone LIKE 124000000 | 15.7 | 3100, মাসিক রিপোর্ট 12300000 | 1.6 | 34167. প্রথমটি ৬টি সারি ফেরাতে প্রতিবার ২,৬০০ page পড়ছে — প্রতি সারিতে ৪৩৩টি page. এটি orders(customer_id)-এ index না থাকার লক্ষণ (পর্ব ৪১); index দিলে কয়েকটি page-এ নামবে, আর এক ধাক্কায় মোট I/O-র ৮২% প্রায় মুছে যাবে। phone-এর LIKE '%…' শুরুতে wildcard থাকলে সাধারণ B+ tree index কাজে লাগে না। রিপোর্টের প্রতি-সারির সংখ্যা বড় দেখালেও সেটি স্বাভাবিক — অনেক সারি যোগ করে অল্প সারি ফেরায় — আর সেটি replica বা warehouse-এ (পর্ব ৫৫) পাঠানো যায়।

৯ · Migration আর vendor lock-in

নিজের সার্ভার থেকে ক্লাউডে যাওয়ার দুটি প্রধান পথ। Dump/restore (পর্ব ৫২-এর logical backup): লেখা বন্ধ করে pg_dump, নতুন জায়গায় pg_restore, তারপর অ্যাপ ঘোরানো। সরল, কিন্তু পুরো সময় অ্যাপ বন্ধ — ছোট ডেটাবেসে ঠিক আছে, বড়টিতে ঘণ্টার পর ঘণ্টা। Logical replication: পুরোনো ডেটাবেস চালু রেখেই নতুনটিতে কপি আর পরিবর্তনের ধারা পাঠানো, শেষে কয়েক মিনিটের বিরতিতে সরে যাওয়া। প্রদানকারীদের migration সেবাগুলোও (AWS DMS, Google Database Migration Service, Azure Database Migration Service) ভেতরে প্রায়ই এই ধারণাই ব্যবহার করে। PostgreSQL থেকে PostgreSQL-এ ধাপগুলো:

পুরোনো (অফিসের সার্ভার) → নতুন (DBaaS)অ্যাপ এখন কোথায় লিখছে

            
অবস্থা
অ্যাপ লিখছে
নতুনের ডেটা
বিরতি (downtime)
  1. প্রস্তুতি। logical decoding চালু করতে wal_level = logical, যা সার্ভার restart চায় — তাই আগে থেকে পরিকল্পনা। UPDATE আর DELETE পাঠাতে প্রতিটি টেবিলে primary key (বা অন্য replica identity) লাগে। তারপর publication: কোন টেবিলের পরিবর্তন পাঠানো হবে।
  2. Schema আগে। logical replication শুধু সারির পরিবর্তন পাঠায়, CREATE TABLE বা ALTER নয় (DDL যায় না)। তাই নতুন জায়গায় আগে schema বসান, আর migration চলার সময় schema বদল স্থগিত রাখুন।
  3. Subscription. নতুন ডেটাবেস পুরোনোটির সাথে যুক্ত হয়ে প্রথমে প্রতিটি টেবিলের পুরো কপি নেয়, তারপর সেই মুহূর্ত থেকে পরিবর্তন। সংযোগের পাসওয়ার্ড কমান্ডে না লিখে password file বা secrets-এ রাখুন। এর মধ্যে অ্যাপ স্বাভাবিকভাবে পুরোনোতে চলছে।
  4. ধরে ফেলা আর যাচাই। lag কমে সেকেন্ডে আসে। এখন নতুন জায়গায় অ্যাপের পড়ার কোয়েরি পরীক্ষা করুন — latency, plan, extension. দুই দিকের সারি গোনা আর EXCEPT দিয়ে পার্থক্য খোঁজা (নিচের এডিটর)।
  5. Cutover. লেখা থামান, lag শূন্য হতে দিন। একটি প্রচলিত ফাঁদ: sequence-এর বর্তমান মান logical replication-এ যায় না — না বসালে নতুন জায়গায় প্রথম INSERT-ই duplicate key দেবে। তারপর connection string বদল। মোট বিরতি কয়েক মিনিট — এই পুরো প্রক্রিয়ার নাম cutover.
  6. ফেরার পথ। পুরোনো ডেটাবেস কিছুদিন রেখে দিন; চাইলে নতুন থেকে পুরোনোতে উল্টো replication চালু রাখুন, যাতে সমস্যা হলে ফেরা যায়। ভালো migration-এ “কীভাবে ফিরব” প্রশ্নের উত্তর শুরুতেই লেখা থাকে।
-- পুরোনো সার্ভারে (postgresql.conf-এ wal_level = logical, তারপর restart)
CREATE PUBLICATION shop_pub FOR ALL TABLES;
-- নতুন সার্ভারে, schema বসানোর পর
CREATE SUBSCRIPTION shop_sub
  CONNECTION 'host=old-db.example.internal dbname=shop user=replicator sslmode=require'
  PUBLICATION shop_pub;
SELECT subname, received_lsn, latest_end_time FROM pg_stat_subscription;
-- cutover-এ: প্রতিটি sequence-কে টেবিলের সর্বোচ্চ id-র পরে বসানো
SELECT setval('orders_order_id_seq', (SELECT MAX(order_id) FROM orders));

যাচাইয়ের মূল কৌশল পর্ব ২২-এর EXCEPT. নিচের এডিটরে দোকানের নমুনা ডেটাবেস (customers, products, orders …) হলো “পুরোনো” দিক; target_orders হলো নতুন জায়গার orders-এর কপি, যেখানে শেষ মুহূর্তের কিছু পরিবর্তন এখনো পৌঁছায়নি:

SELECT 'source' AS side, COUNT(*) AS n, SUM(order_id) AS id_sum FROM orders
UNION ALL
SELECT 'target', COUNT(*), SUM(order_id) FROM target_orders;
SELECT 'missing or changed in target' AS problem, *
FROM (SELECT * FROM orders EXCEPT SELECT * FROM target_orders);
SELECT 'only in target' AS problem, *
FROM (SELECT * FROM target_orders EXCEPT SELECT * FROM orders);

প্রথম ফল: source | 10 | 10055, target | 9 | 9045 — একটি সারি কম। দ্বিতীয় ফল দুই সারি: 1008 | 8 | 2025-10-05 | shipped আর 1010 | 7 | 2025-10-09 | delivered. তৃতীয় ফল এক সারি: 1008 | 8 | 2025-10-05 | pending. অর্থাৎ 1010 নতুন জায়গায় নেই, আর 1008-এর status পুরোনো মানে আটকে আছে — দুই দিকের EXCEPT মিলিয়েই “নেই” আর “বদলেছে” আলাদা করা যায়। শুধু COUNT দেখলে 1008-এর সমস্যা ধরা পড়ত না। বড় টেবিলে পুরো EXCEPT ভারী, তাই বাস্তবে id-র পরিসর ধরে টুকরো টুকরো hash মেলানো হয়।

Vendor lock-in আর বেরোনোর পথ

Vendor lock-in মানে একটি প্রদানকারী ছাড়া এত কঠিন বা দামি যে দাম বাড়লেও বা সেবা খারাপ হলেও থেকে যেতে হয়। কয়েকটি স্তরে বাঁধা পড়েন: প্রদানকারীর নিজস্ব query language বা API, নিজস্ব extension আর ফিচার, তার পরিচয়-ব্যবস্থা আর network-এর সাথে জড়ানো কনফিগ, আর ডেটার আকার নিজেই — কয়েক TB বের করার egress-এর বিল আর সময়। একেবারে এড়ানো প্রায়ই সম্ভবও না, কাম্যও না; লক্ষ্য হলো সচেতন সিদ্ধান্ত আর একটি exit strategy:

  • সম্ভব হলে standard engine (PostgreSQL, MySQL) আর standard SQL; নিজস্ব ফিচার ব্যবহারের জায়গাগুলো তালিকায় রাখা।
  • নিয়মিত logical export (pg_dump বা mysqldump) প্রদানকারীর বাইরের storage-এ, আর মাঝে মাঝে অন্য জায়গায় restore করে দেখা — এটি backup-ও, বেরোনোর মহড়াও।
  • infrastructure কোড হিসেবে (Terraform), আর অ্যাপের সংযোগ একটি config-এ — যাতে ঠিকানা বদলাতে কোড বদলাতে না হয়।
  • চুক্তি আর ডকুমেন্টেশনে দেখা: ডেটা কোন ফরম্যাটে বের করা যায়, আর বেরোনোর খরচ কত।

১০ · AI-এর যুগে ক্লাউড ডেটাবেসের সিদ্ধান্ত

AI মিনিটে একটি Terraform ফাইল বা CLI কমান্ড লিখে দেয়, আর সেটি চলেও। কিন্তু ক্লাউডে “চলে” আর “নিরাপদ ও সাশ্রয়ী” — আলাদা কথা। সাধারণ ভুল:

AI-এর ভুলফলকীভাবে ধরবেন
“সহজে যুক্ত হতে” public access চালু, নিয়ম সবার জন্য খোলাইন্টারনেট থেকে স্ক্যান আর পাসওয়ার্ড অনুমানpublicly accessible, firewall নিয়ম আলাদা করে পড়ুন
কোডে বা কনফিগে সরাসরি পাসওয়ার্ডGit-এ পাসওয়ার্ড ফাঁসsecrets manager বা প্রদানকারীর পাসওয়ার্ড-ব্যবস্থা চান
পুরোনো বা বানানো flag আর দামের সংখ্যাকমান্ড ব্যর্থ, বা ভুল বাজেটপ্রতিটি flag বর্তমান ডকুমেন্টেশনে মিলান; দাম প্রদানকারীর calculator-এ
serverless function-এ প্রতি অনুরোধে নতুন সংযোগচাপের দিনে connection stormpooler বা data API কোথায়, জিজ্ঞেস করুন; load test
multi-tenant কোয়েরিতে tenant_id-এর শর্ত বাদএক গ্রাহকের ডেটা অন্যজনের পাতায়দুই tenant-এর নমুনা ডেটায় চালিয়ে দেখুন; RLS চালু রাখুন

AI-কে শুধু “একটি RDS বানিয়ে দাও” না বলে লক্ষ্য, সীমা আর যাচাইয়ের পরিকল্পনা চান:

আমার অ্যাপ: PostgreSQL, ডেটা ৮০ GB, ব্যবহারকারী বেশিরভাগ বাংলাদেশে, অ্যাপ চলে serverless function-এ। লক্ষ্য: RPO ৫ মিনিট, RTO ৩০ মিনিট; ডেটাবেসে কোনো public IP থাকবে না; পাসওয়ার্ড কোডে থাকবে না। ১. কোন region আর কোন ধরনের managed সেবা নেবে, কারণসহ বলো; latency কীভাবে মাপব, তাও বলো। ২. Terraform কোড দাও; প্রতিটি attribute কেন, এক লাইনে লেখো; কোনো দাম অনুমান করে লিখবে না। ৩. connection storm ঠেকাতে pooler-এর নকশা দাও, আর transaction pooling-এ কোন জিনিস ভাঙতে পারে বলো। ৪. বেরোনোর পথ (exit strategy) আর নিয়মিত export-এর একটি পরিকল্পনা দাও। অনিশ্চিত কোনো flag বা ফিচার থাকলে স্পষ্ট করে বলো।

AI-এর পরিকল্পনা মানার আগে — চেকলিস্ট

পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:

  • DBaaS-এ shared responsibility কী? — হার্ডওয়্যার, OS, patch, backup আর failover প্রদানকারীর; schema, কোয়েরি, index, অনুমতি, ডেটা আর খরচ ব্যবহারকারীর।
  • Multi-AZ আর read replica-র পার্থক্য? — multi-AZ standby HA-র জন্য (সাধারণত sync, স্বয়ংক্রিয় failover); read replica পড়ার চাপ ভাগের জন্য (async, lag থাকে)।
  • Serverless function থেকে ডেটাবেস “too many connections” দিচ্ছে — সমাধান? — সংযোগ handler-এর বাইরে, ছোট pool, আর মাঝে PgBouncer/RDS Proxy-ধাঁচের pooler বা HTTP data API.
  • কম downtime-এ ডেটাবেস ক্লাউডে নেবেন কীভাবে? — schema আগে, logical replication দিয়ে কপি আর ধারা, যাচাই, তারপর লেখা থামিয়ে lag শূন্য করে sequence বসিয়ে cutover.
  • ক্লাউড ডেটাবেসের বিলের প্রধান মাত্রা? — compute, storage, IOPS, backup, egress আর replica.

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১২০০৯ সালে Amazon RDS আসার পর DBaaS দ্রুত ছড়িয়েছে। এতে DBA-র কাজ কি শেষ হয়ে গেছে, নাকি বদলে গেছে?

RDS-এর আগে একটি নতুন ডেটাবেস মানে হার্ডওয়্যার কেনা, OS বসানো, DBMS compile বা install, backup script লেখা, replication সাজানো — সপ্তাহের কাজ, যার বড় অংশ প্রতিটি প্রতিষ্ঠানে একইভাবে বারবার হতো। RDS আর পরে Google Cloud SQL, Azure SQL Database এই একঘেয়ে, সবার একই কাজগুলো একটি API-র পেছনে নিয়ে গেল: কয়েক মিনিটে instance, একটি সেটিংয়ে backup আর PITR, আরেকটিতে অন্য zone-এ standby. ছোট দলের জন্য এটি বিপ্লব — যাদের কোনো DBA নেই, তারাও এখন মোটামুটি নিরাপদ ডেটাবেস পায়।

কিন্তু যে কাজগুলো সরে গেছে, সেগুলো মূলত “যন্ত্র চালানো”-র কাজ। DBA-র কাজের আরেকটি বড় অংশ — schema নকশা, index বাছাই, ধীর কোয়েরি খোঁজা, capacity-র পরিকল্পনা, কে কী দেখতে পারবে, restore-এর মহড়া — সরেনি। বরং ক্লাউডে এগুলোর ফল সরাসরি বিলে দেখা যায়: একটি খারাপ কোয়েরি আগে শুধু সার্ভার ধীর করত, এখন বড় instance আর বেশি I/O-র টাকাও খায়। তাই অনেক প্রতিষ্ঠানে ভূমিকার নাম বদলেছে — database reliability engineer, platform engineer — আর কাজে যোগ হয়েছে খরচের দেখাশোনা (FinOps), infrastructure-as-code আর একাধিক সেবার মধ্যে বাছাই।

একটি সূক্ষ্ম ঝুঁকিও আছে। managed সেবা সমস্যাগুলো লুকিয়ে রাখে বলে দল অনেক সময় জানে না ভেতরে কী হচ্ছে — failover-এ সংযোগ কেন কাটল, storage কেন হঠাৎ বেড়ে গেল, major upgrade কেন অ্যাপ ভাঙল। বিপদের দিনে সেই জ্ঞানের অভাব ধরা পড়ে।

মূল উপলব্ধি: DBaaS “যন্ত্রের যত্ন” কিনে দেয়, “ডেটার যত্ন” নয়। DBA-র কাজ শেষ হয়নি; হাতের কাজ কমে নকশা, কোয়েরি, নিরাপত্তা আর খরচের দিকে সরেছে।

প্র ০২Amazon Aurora-র নকশাকারীরা বলেছেন “log-ই ডেটাবেস”। প্রচলিত PostgreSQL বা MySQL-এর replication-এর তুলনায় storage আর compute আলাদা করার লাভ আর দাম কী?

প্রচলিত নকশায় প্রতিটি ডেটাবেস সার্ভারের নিজের disk, যেখানে data page আর WAL দুটোই থাকে। replica বানাতে পুরো ডেটা কপি করতে হয়, আর প্রতিটি replica নিজের disk-এ সেই একই page আবার লেখে। ক্লাউডে disk নিজেই network-এর ওপারে থাকে, তাই একটি page লেখা মানে বহু network I/O — data page, WAL, আর MySQL-এ বাড়তি binlog ও doublewrite. Aurora দলের ২০১৭ সালের SIGMOD গবেষণাপত্রের মূল যুক্তি ছিল: ক্লাউডে বাধা CPU বা disk নয়, network.

তাদের সমাধান: compute শুধু redo log record পাঠায় একটি বিতরণকৃত storage স্তরে, যা তিনটি AZ-এ ছয়টি কপি রাখে। লেখা টেকসই ধরা হয় ছয়ের মধ্যে চারটি নিশ্চিত করলে, পড়ার জন্য তিনটি যথেষ্ট — চার আর তিন মিলে ছয়ের বেশি, তাই যেকোনো পড়ার দল শেষ লেখার দলের সাথে অন্তত একটি কপিতে মেলে। page বানানোর কাজ storage নিজেই পেছনে করে। ফল: একটি পুরো AZ আর আরও একটি কপি হারালেও পড়া চলে; replica-রা একই storage পড়ে বলে নতুন replica-য় ডেটা কপি লাগে না, lag কম; crash-এর পর দীর্ঘ redo replay লাগে না।

দাম কী? প্রথমত, এটি প্রদানকারীর নিজস্ব storage — বাইরে PostgreSQL/MySQL-এর মতো কথা বললেও ভেতরের আচরণ, সংস্করণ আর ফিচার আসল engine থেকে কিছুটা আলাদা হতে পারে, আর অন্য কোথাও হুবহু এই ব্যবস্থা পাবেন না। দ্বিতীয়ত, দামের মডেল ভিন্ন হতে পারে (যেমন I/O ধরে বিল), যা অদক্ষ কোয়েরিকে দামি করে। Neon-এর মতো পরে আসা সেবাগুলো একই “storage-compute আলাদা” ধারণা open-source PostgreSQL-এর ওপর গড়েছে, সাথে branch আর scale to zero.

মূল উপলব্ধি: ক্লাউডের বাধা অনুযায়ী DBMS-এর ভেতরটা নতুন করে ভাবা যায় — পর্ব ৪৮-এর WAL এখানে শুধু recovery-র উপায় নয়, ডেটাবেসের মূল রূপ। কিন্তু প্রতিটি নিজস্ব নকশা কিছুটা বাঁধনও আনে।

প্র ০৩PostgreSQL প্রতিটি সংযোগে একটি আলাদা process চালায়। serverless-এর যুগে এই পুরোনো নকশা কেন সমস্যা, আর PgBouncer থেকে RDS Proxy পর্যন্ত pooler কীভাবে উত্তর দিয়েছে?

PostgreSQL-এর জন্ম ১৯৮০-৯০-এর দশকের Berkeley-র গবেষণায়, যখন একটি ডেটাবেসে অল্প কয়েকটি দীর্ঘস্থায়ী client থাকত। প্রতিটি সংযোগে একটি OS process সরল আর নিরাপদ: একটি process crash করলে অন্যরা টিকে থাকে। কিন্তু প্রতিটি process-এর memory আর context switch-এর খরচ আছে, আর নতুন সংযোগে fork, authentication আর TLS handshake লাগে। তাই কয়েকশো সংযোগের ওপরে প্রায়ই throughput বাড়ে না, বরং কমে।

ওয়েব অ্যাপের যুগে সমস্যা প্রথম দেখা দেয় অনেক অ্যাপ সার্ভার একসাথে সংযোগ খুললে। এর একটি পরিচিত উত্তর PgBouncer — Skype-এর প্রকৌশলীদের হাতে জন্মানো একটি হালকা pooler, যা হাজারো client সংযোগ নিয়ে অল্প কয়েকটি সার্ভার-সংযোগে ভাগ করে। transaction mode-এ সার্ভার-সংযোগ শুধু transaction চলাকালীন ধার দেওয়া হয়, তাই দক্ষতা অনেক বেশি; বদলে session-এর অবস্থা (SET, temp table, advisory lock) ভাগ করা যায় না, আর দীর্ঘদিন prepared statement-ও সমস্যা ছিল — নতুন সংস্করণগুলো এর কিছুটা সমাধান করেছে।

serverless function সমস্যাটিকে চরমে নেয়: হাজারো স্বল্পজীবী instance, যারা নিজে pool রাখতে পারে না, আর হঠাৎ একসাথে জেগে ওঠে। তাই প্রদানকারীরা pooler-কে সেবা বানিয়েছে — AWS-এর RDS Proxy, Supabase-এর Supavisor, অনেক প্ল্যাটফর্মের আলাদা “pooled” ঠিকানা — আর কেউ কেউ HTTP বা WebSocket-এর ওপর কোয়েরি নেওয়ার driver দিয়েছে, যাতে function TCP সংযোগই ধরে না রাখে। MySQL-এ প্রতিটি সংযোগ একটি thread, তুলনায় হালকা, তবু বিপুল সংখ্যায় একই প্রশ্ন আসে।

মূল উপলব্ধি: ডেটাবেসের সংযোগ একটি সীমিত, দামি সম্পদ। অ্যাপের ধরন বদলালে (সার্ভার থেকে function) সংযোগ ব্যবস্থাপনাও বদলাতে হয় — pooler বা data API এখন serverless নকশার অপরিহার্য অংশ।

প্র ০৪২০২২ সালে Heroku তার বিনা মূল্যের Postgres আর dyno বন্ধ করে, আর ২০২৪ সালে PlanetScale তার বিনা মূল্যের Hobby plan তুলে নেয়। এ থেকে vendor lock-in আর exit strategy নিয়ে কী শেখা যায়?

দুটি ঘটনাই প্রতিষ্ঠানগুলোর নিজেদের ঘোষণা অনুযায়ী ঘটেছে, আর বহু ছাত্র, শখের প্রকল্প আর ছোট স্টার্টআপকে অল্প সময়ের নোটিশে সিদ্ধান্ত নিতে হয়েছে: টাকা দিয়ে থাকা, না অন্য কোথাও সরা। যাঁদের ডেটাবেস ছিল standard engine-এ — Heroku Postgres ভেতরে আসল PostgreSQL — তাঁদের কাজ তুলনায় সহজ ছিল: pg_dump নিয়ে অন্য যেকোনো PostgreSQL সেবায় restore. যাঁরা প্ল্যাটফর্মের বিশেষ সুবিধা বা কাজের ধারার ওপর বেশি নির্ভর করেছিলেন, তাঁদের সরতে বেশি সময় লেগেছে।

শিক্ষাটি ব্যবসায়িক, প্রযুক্তিগত নয়: প্রদানকারী আপনার অংশীদার, কিন্তু তার দাম, plan আর অগ্রাধিকার তার নিজের ব্যবসার হিসাবে বদলায়। প্রতিষ্ঠান কেনাবেচা হয়, পণ্য বন্ধ হয়, বিনা মূল্যের স্তর সবচেয়ে আগে বদলায়। তাই প্রশ্নটি “lock-in আছে কি না” নয় — কিছু না কিছু থাকবেই — বরং “বেরোতে হলে কত সময় আর খরচ লাগবে, আর সেটি আমি জানি কি না”।

বাস্তব exit strategy কয়েকটি অভ্যাস: standard engine আর portable SQL যতটা সম্ভব; নিজস্ব ফিচার কোথায় ব্যবহার হলো, তার তালিকা; প্রদানকারীর বাইরে নিয়মিত logical export, আর বছরে অন্তত একবার অন্য জায়গায় restore-এর মহড়া; infrastructure কোড হিসেবে; আর ডেটার আকার বড় হলে egress-এর খরচ আগে থেকে হিসাব করা। বড় প্রতিষ্ঠান অনেক সময় এর বেশি যায় না — দুই প্রদানকারীতে একসাথে চালানো প্রায়ই খরচ আর জটিলতায় লাভের চেয়ে বেশি।

মূল উপলব্ধি: বিনা মূল্যের বা সুবিধাজনক সেবা নিন, কিন্তু চোখ খোলা রেখে। যে ডেটা আপনি নিজে বের করে অন্য জায়গায় চালিয়ে দেখেননি, তার ওপর আপনার নিয়ন্ত্রণ আসলে অনুমান।

প্র ০৫“ক্লাউডে কোয়েরির দক্ষতা মানেই টাকা” — কেন? BigQuery-র মতো scan ধরে বিল বা I/O ধরে বিলের সেবায় একটি ভুল কোয়েরি কীভাবে খরচ বাড়ায়?

নিজের সার্ভারে একটি অদক্ষ কোয়েরির দাম লুকানো: সার্ভার তো কেনাই আছে, কোয়েরি শুধু ধীর। দাম আসে পরোক্ষে — বাকিরা ধীর, একসময় বড় সার্ভার কিনতে হয়। ক্লাউডে এই দাম প্রতি মাসে সরাসরি বিলে আসে, আর কিছু সেবায় প্রতিটি কোয়েরিতেই।

কয়েকটি পথে। এক, যেসব analytics সেবা পড়া ডেটার পরিমাণ ধরে বিল করে (Google BigQuery-র on-demand মডেল এর পরিচিত উদাহরণ), সেখানে SELECT * একটি বিশাল টেবিলে চালালে সব column-এর সব বাইট পড়ার দাম লাগে — column-ভিত্তিক storage-এ শুধু দরকারি column বাছলে আর partition দিয়ে তারিখ সীমিত করলে একই উত্তর অনেক কম ডেটা পড়ে পাওয়া যায়। দুই, যেসব OLTP সেবা I/O ধরে দাম নেয়, সেখানে missing index-এর পুরো টেবিল scan প্রতিবার হাজারো page পড়ে — অংশ ৮-এর উদাহরণে একটি কোয়েরি মোট I/O-র ৮২%. তিন, নির্দিষ্ট instance-এর সেবায় অদক্ষতা CPU আর memory খায়, তখন বড় instance বা বাড়তি read replica লাগে — compute-এর বিল দ্বিগুণ। চার, অপ্রয়োজনীয় বড় ফল অ্যাপে বা অন্য region-এ পাঠালে egress.

তাই ক্লাউডে performance tuning (পর্ব ৫৩) সরাসরি খরচ কমানোর কাজ। অনেক দল তাই কোয়েরি-monitoring-এর পাশে খরচের ড্যাশবোর্ড রাখে, analytics-এ প্রতি কোয়েরির সর্বোচ্চ scan সীমা বসায়, আর নতুন কোয়েরি production-এ যাওয়ার আগে EXPLAIN দেখে। একটি index বা একটি WHERE-এর শর্ত কখনো কখনো মাসের বিলের বড় অংশ বাঁচায়।

মূল উপলব্ধি: ক্লাউডে প্রতিটি পড়া page আর প্রতিটি চালু ঘণ্টার একটি দাম আছে। ভালো schema, ঠিক index আর সংযত কোয়েরি — এই কোর্সের পুরো শিক্ষাই এখানে টাকার অঙ্কে মাপা যায়।

অনুশীলন

একটি কোয়েরি লেখা, একটি হাতে trace, একটি হিসাব, একটি ফল অনুমান।

  1. কোয়েরি লিখুন: অংশ ৬-এর tenants আর invoices টেবিল থেকে প্রতিটি দোকানের নাম, invoice-এর সংখ্যা আর মোট বিক্রি (amount-এর যোগফল) বের করুন, বেশি বিক্রি আগে। (অংশ ৬-এর প্রথম এডিটরে লিখে চালাতে পারেন।)
    SELECT t.name, COUNT(i.invoice_id) AS invoices, COALESCE(SUM(i.amount), 0) AS total_sales
    FROM tenants t
    LEFT JOIN invoices i ON i.tenant_id = t.tenant_id
    GROUP BY t.tenant_id, t.name
    ORDER BY total_sales DESC;

    ফল: Ma Electronics | 2 | 22000, Chowdhury Pharmacy | 4 | 3840, Rahman Store | 3 | 1950. JOIN-এর শর্তে tenant_id মেলানো জরুরি — invoice_id প্রতিটি দোকানে ১ থেকে শুরু, তাই শুধু invoice_id-তে মেলালে ভুল যোগফল আসবে। LEFT JOIN আর COALESCE রাখা হলো যাতে নতুন, কোনো invoice ছাড়া দোকানও ০ দেখায়।

  2. হাতে trace করুন: একটি ডেটাবেসে max_connections = 100, যার ১০টি admin ও monitoring-এর জন্য রাখা। সেলের সময় ৬০০টি function instance একসাথে চলবে, প্রতিটি একটি transaction করে যা গড়ে ২০ ms নেয়। (ক) pooler ছাড়া কয়টি অনুরোধ সংযোগই পাবে না? (খ) transaction mode-এর pooler ৪০টি সার্ভার-সংযোগ রাখলে সেকেন্ডে মোটামুটি কতটি transaction চালানো যায়?

    (ক) অ্যাপের জন্য ১০০ − ১০ = ৯০টি সংযোগ, তাই ৬০০ − ৯০ = ৫১০টি অনুরোধ “too many clients” পাবে (retry হলে আরও খারাপ)। (খ) প্রতিটি সংযোগ সেকেন্ডে ১০০০ ÷ ২০ = ৫০টি transaction চালাতে পারে, তাই ৪০ × ৫০ = প্রায় ২,০০০টি. ৬০০টি অনুরোধ তাই এক সেকেন্ডের অনেক কম সময়ে শেষ হয়, যদি ডেটাবেসের CPU আর I/O এই চাপ নিতে পারে। শর্ত: transaction ছোট রাখা — একটি transaction-এর ভেতরে HTTP call বা ব্যবহারকারীর জন্য অপেক্ষা করলে সংযোগ আটকে থাকে আর হিসাব ভেঙে যায়।

  3. খরচের হিসাব (কাল্পনিক হার): একটি ডেটাবেস ঘণ্টায় ০.৪ CR, মাসে ৭৩০ ঘণ্টা চলে; storage ২০০ GB, প্রতি GB ০.১ CR; egress ১,০০০ GB, প্রতি GB ০.০৯ CR. দল multi-AZ standby যোগ করতে চায় (একটি পুরো instance-এর সমান), আর CDN দিয়ে egress অর্ধেক করতে চায়। আগে আর পরে মাসিক খরচ কত?

    আগে: compute ৭৩০ × ০.৪ = ২৯২; storage ২০০ × ০.১ = ২০; egress ১,০০০ × ০.০৯ = ৯০; মোট ৪০২ CR. পরে: compute দ্বিগুণ = ৫৮৪; storage ২০ (standby-এর storage-ও আলাদা বিল হলে আরও ২০); egress ৫০০ × ০.০৯ = ৪৫; মোট ৬৪৯ CR (বা ৬৬৯). HA যোগ করায় খরচ প্রায় ১.৬ গুণ হলো — এটি কি RTO-র লক্ষ্যে দরকার, সেই সিদ্ধান্ত ব্যবসার। আসল প্রদানকারীতে standby-এর storage আর cross-AZ ট্রাফিক কীভাবে বিল হয়, দামের পাতায় দেখে নিন।

  4. ফল অনুমান করুন: অংশ ৬-এর my_invoices view দেখে app_session-এ কোন tenant আছে। কেউ চালালেন UPDATE app_session SET tenant_id = 3; তারপর SELECT COUNT(*), SUM(amount) FROM my_invoices; — ফল কী? আর বাস্তব অ্যাপে এই অনুকরণের দুর্বলতা কোথায়?

    ফল 2 | 22000 — Ma Electronics-এর দুটি invoice (১৮৫০০ + ৩৫০০)। view নিজে ডেটা রাখে না; প্রতিবার app_session পড়ে শর্ত বসায়, তাই tenant বদলালেই ফল বদলায়। দুর্বলতা: যে কেউ app_session বদলাতে পারলে অন্য tenant-এর ডেটা দেখতে পারে, আর মূল টেবিল invoices-ও সরাসরি পড়া যায়। আসল ব্যবস্থায় অ্যাপের role মূল টেবিলে RLS policy-র অধীনে, tenant-এর মান আসে যাচাই করা login থেকে (SET LOCAL), আর সেই role নিজে policy বদলাতে পারে না।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমLogical replication দিয়ে PostgreSQL ডেটাবেস ক্লাউডে নেওয়ার কাজগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. পুরোনো সার্ভারে wal_level = logical আর একটি publication
  2. নতুন ডেটাবেসে schema বসানো
  3. নতুন ডেটাবেসে subscription — পুরো কপি, তারপর পরিবর্তনের ধারা
  4. সারি গোনা আর EXCEPT দিয়ে দুই দিক মেলানো
  5. লেখা থামিয়ে lag শূন্য করা, sequence বসানো আর connection string বদল

একটি managed ডেটাবেস সেবায় (DBaaS) সাধারণত কোন কাজটি ব্যবহারকারীর দায়িত্বেই থাকে?

  • নষ্ট ডিস্ক বদলানো
  • Operating system-এর security patch
  • কোন column-এ index লাগবে, তা ঠিক করা
  • প্রতিদিনের স্বয়ংক্রিয় backup চালানো

একটি সেবার অ্যাপ সার্ভার ঢাকার একটি হোস্টিংয়ে, আর ডেটাবেস সিঙ্গাপুরের একটি region-এ; দুইয়ের মধ্যে round trip প্রায় ৫০ ms. প্রতিটি পাতায় পরপর ১০টি কোয়েরি চলে। পাতা ধীর কেন, আর প্রধান সমাধান কী?

  • ডেটাবেস instance ছোট; বড় instance নিলেই হবে
  • প্রতিটি কোয়েরি সমুদ্র পেরোয় (১০ × ৫০ ms); অ্যাপ আর ডেটাবেস একই region-এ রাখা
  • একটি read replica যোগ করা
  • storage-এর IOPS বাড়ানো

Multi-AZ standby আর read replica সম্পর্কে কোন কথাটি সাধারণভাবে সঠিক?

  • Multi-AZ standby মূলত HA আর স্বয়ংক্রিয় failover-এর জন্য; read replica মূলত পড়ার চাপ ভাগ করতে, lag-সহ
  • দুটিই ভুল DELETE থেকে ডেটা বাঁচায়
  • read replica সবসময় sync, তাই lag থাকে না
  • standby পড়ার কোয়েরি নেয়, আর read replica নেয় না

serverless function থেকে PostgreSQL-এ চাপের সময় “too many clients already” ত্রুটি আসছে। সবচেয়ে উপযুক্ত সমাধান কোনটি?

  • max_connections কয়েক হাজারে তোলা
  • প্রতিটি অনুরোধে নতুন সংযোগ খুলে কাজ শেষে বন্ধ করা
  • ব্যর্থ হলে সাথে সাথে বারবার retry করা
  • মাঝে transaction mode-এর একটি pooler বসানো, আর function-এ ছোট pool handler-এর বাইরে রাখা

একটি query log-এ: কোয়েরি A দিনে ৩০ বার চলে, প্রতিবার গড়ে ৯,২০০ ms; কোয়েরি B দিনে ২,৫০,০০০ বার, গড়ে ৩৮ ms. ডেটাবেসের মোট সময় কমাতে কোনটি আগে দেখা উচিত?

  • A, কারণ সেটি সবচেয়ে ধীর
  • B, কারণ calls × mean হিসাবে B-এর মোট সময় অনেক বেশি
  • দুটি সমান গুরুত্বপূর্ণ
  • EXPLAIN ছাড়া কিছুই বলা যায় না

PostgreSQL-এর logical replication দিয়ে migration-এর cutover-এর পর নতুন ডেটাবেসে প্রথম INSERT-এই “duplicate key” ত্রুটি এল। সবচেয়ে সম্ভাব্য কারণ কী?

  • টেবিলে primary key নেই
  • logical replication DDL পাঠায় না
  • sequence-এর মান কপি হয়নি, তাই নতুন id পুরোনো id-র সাথে মিলে গেছে
  • সংযোগে TLS চালু ছিল না

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. তিন পথ, এক প্রশ্ন: নিজের সার্ভার, IaaS VM না DBaaS — বাছাইয়ের আগে লিখে নিন কোন স্তর কার দায়িত্ব। schema, কোয়েরি, অনুমতি, ডেটা আর বিল সবসময় আপনার।
  2. জায়গা: অ্যাপ আর ডেটাবেস একই region-এ; region বাছুন মাপা latency আর আইনের শর্ত দেখে। multi-AZ = HA, read replica = পড়ার ক্ষমতা, cross-region = DR, আর ভুল DELETE-এর জন্য backup.
  3. খরচ: compute, storage, IOPS, backup, egress আর replica; right-sizing, dev বন্ধ রাখা, reserved capacity আর মোট সময় (calls × mean) ধরে কোয়েরি ঠিক করা।
  4. Serverless আর multi-tenant: function-এর সংযোগ সামলায় pooler বা data API; tenant_id-এর শর্ত ডেটাবেসের ভেতরে বাঁধুন (RLS, SET LOCAL).
  5. নিরাপত্তা আর বেরোনোর পথ: public IP নয়, IAM আর secrets manager, encryption, audit log; migration-এ logical replication, যাচাইয়ে EXCEPT, cutover-এ sequence; আর নিয়মিত logical export.

পরের পর্বে: এতদিনের সব শিক্ষা এক জায়গায়। পর্ব ৬২-এ ক্যাপস্টোন — একটি সম্পূর্ণ ডেটাবেস নকশা থেকে deployment পর্যন্ত, ধাপে ধাপে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান