সরাসরি পর্বে যান
পর্ব ২২ · ৮১-এর মধ্যে · মডিউল ৪

Managed database — replica, failover, backup আর connection

Managed Databases — Replicas, Failover, Backups and Connections

Taught in Bangla, this lesson explains what a managed database provider handles and what stays with you, the difference between a Multi-AZ standby and a read replica, each step of failover and client retry settings, replica lag and read-your-writes, automated backups, point-in-time recovery and snapshots, maintenance and major upgrades, connection budgeting with a pooling proxy, and self-managed versus managed cost, with simulators and worked examples.

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

  • Managed database-এ কোন কাজ provider-এর, আর কোন কাজ আপনার
  • Multi-AZ standby আর read replica-র পার্থক্য, আর কোনটি কোন সমস্যার সমাধান
  • Failover-এর প্রতিটি ধাপ, DNS endpoint-এর বদল আর client-এর retry সেটিং
  • Replica lag, read-your-writes, automated backup, PITR আর snapshot
  • Connection-এর হিসাব, PgBouncer-ধরনের proxy আর connection storm এড়ানো
  • Sizing, monitoring, private network আর self-managed বনাম managed খরচ

১ · Managed মানে কী — কে কী সামলায়

ধরুন আপনি নিজের বাড়িতে থাকেন। পানির পাম্প, জেনারেটর, লিফট, ছাদের ট্যাংক, সব আপনাকেই দেখতে হয়। এবার ধরুন একটি ভালো ফ্ল্যাটে উঠলেন, যেখানে মাসে সার্ভিস চার্জ দেন। কেয়ারটেকার পাম্প ঠিক করেন, জেনারেটর চালান। কিন্তু ঘরে কী রাখবেন, কতজন অতিথি ডাকবেন, সেটি তিনি ঠিক করেন না। আর আপনি নিজের ঘরের আলমারি ভেঙে ফেললে তিনি কিছুই করতে পারবেন না।

Managed database ঠিক এমন। একে DBaaS (Database as a Service) বলে। Provider একটি database engine, যেমন PostgreSQL বা MySQL, আপনার জন্য চালায়। আপনি VM, OS বা engine install নিয়ে ভাবেন না। আপনি পান একটি endpoint, মানে একটি ঠিকানা, যেখানে app সংযোগ করে।

কাজProviderআপনি
Hardware, OS, engine installপুরোটাকিছু না
নিরাপত্তা patchপ্রয়োগ করেসময় বেছে নেন, পরীক্ষা করেন
Backupচালায় ও জমা রাখেকতদিন রাখবেন ঠিক করেন, restore পরীক্ষা করেন
Failoverটের পায় ও চালায়App-এর reconnect ঠিক রাখেন
Schema, index, query tuningপরামর্শ দিতে পারেপুরো দায় আপনার
Engine-এর settingঅনুমোদিত তালিকা দেয়Parameter group-এ বদলান
Network, access, passwordহাতিয়ার দেয়ঠিকমতো সাজান
Instance-এর আকার আর খরচবিল পাঠায়বেছে নেন, নজর রাখেন

দাম হিসেবে আপনি কিছু ক্ষমতা ছাড়েন। সাধারণত server-এ SSH করা যায় না, পূর্ণ superuser মেলে না, আর সব extension চলে না। ধীর query managed হলেই দ্রুত হয় না। Index না থাকলে সে আগের মতোই ধীর থাকবে। Query tuning-এর গভীর আলোচনা আছে DBMS কোর্সের performance tuning পর্বে.

Amazon RDS এসেছিল ২০০৯ সালে, শুরুতে MySQL নিয়ে। SQL Azure (আজকের Azure SQL Database) ২০১০ সালে, আর Google Cloud SQL ২০১১ সালে আসে। ২০১৩ সালে RDS-এ PostgreSQL যোগ হয়। প্রায় একই সময়ে দলগুলো বুঝতে শুরু করে, database চালানোর বেশিরভাগ কাজ প্রতিটি কোম্পানিতে একই রকম, তাই সেটি কেনা যায়।

তিন provider-এ একই ধারণা

ধারণাAWSAzureGoogle Cloud
Managed relational databaseAmazon RDSAzure SQL Database, Azure Database for PostgreSQL ও MySQLCloud SQL
Compute আর storage আলাদা নকশাAuroraAzure SQL HyperscaleAlloyDB
Connection proxyRDS ProxyFlexible Server-এর built-in PgBouncerCloud SQL-এর managed connection pooling (edition-ভেদে)

নাম আর সুবিধা সময়ের সাথে বদলায়, তাই provider-এর বর্তমান নথি দেখে নিন। এই পর্বের ধারণা তিন জায়গাতেই খাটে।

Storage আলাদা করা নকশা (ধারণা হিসেবে)

সাধারণ নকশায় প্রতিটি কপির নিজের disk থাকে, আর ডেটা কপি থেকে কপিতে যায়। Aurora-ধরনের নকশায় compute আর storage ভাগ করা হয়। একটি shared storage layer কয়েকটি zone জুড়ে ডেটার কপি রাখে, আর primary ও replica সবাই সেখান থেকে পড়ে। ফলে নতুন replica দ্রুত যোগ হয়, lag সাধারণত কম থাকে, failover-ও প্রায়ই ছোট হয়। তবে এগুলো সব পণ্যে সমান নয়। I/O-এর বিল, engine-এর সামঞ্জস্য আর lock-in আলাদা করে যাচাই করতে হয়।

২ · Multi-AZ standby বনাম read replica

এই পর্বের সবচেয়ে সাধারণ ভুল ধারণা হলো, “আমার তো replica আছে, তাই HA হয়ে গেছে।” HA মানে high availability, অর্থাৎ বিকল হলেও সেবা চালু থাকা। দুটি জিনিসের চেহারা এক, কাজ আলাদা।

Standby হলো হাসপাতালের জেনারেটর। সারাদিন বসে থাকে, কোনো রোগীর কাজে লাগে না, তবু তেল আর রক্ষণাবেক্ষণের খরচ আছে। কারেন্ট গেলেই সে দায়িত্ব নেয়। Read replica হলো ব্যাংকের বাড়তি কাউন্টার, যেখানে শুধু ব্যালান্স দেখা যায়। ভিড় কমায়, কিন্তু মূল কাউন্টার বন্ধ হলে নিজে থেকে টাকা জমা নিতে শুরু করে না।

তিন zone জুড়ে primary, standby আর read replica

One primary, one synchronous standby, two asynchronous read replicas

Primary, standby আর read replica: তিনটি availability zone-এ App Writer endpoint Reader endpoint AZ-aAZ-bAZ-c Primary Replica ২ Replica ১ Standby read + write শুধু read শুধু read অপেক্ষায় synchronous: OK-র আগেই কপি নিশ্চিত asynchronous: পিছিয়ে থাকতে পারে Failover-এর পর writer endpoint যায় Standby-তে।
ছবি ২২.১ — Standby লেখা নিশ্চিত করে, replica পড়ার চাপ নেয়। দুটি আলাদা endpoint লক্ষ করুন।
বিষয়Multi-AZ standbyRead replica
উদ্দেশ্যAvailability, মানে সেবা চালু রাখাপড়ার ক্ষমতা বাড়ানো
Replicationসাধারণত synchronousসাধারণত asynchronous
Query নেয়?সাধারণত না (কিছু ধরনে নেয়)হ্যাঁ, শুধু read
Primary বিকল হলেনিজে থেকে দায়িত্ব নেয়সাধারণত নিজে নেয় না, হাতে promote করতে হয়
ঠিকানাWriter endpoint একই থাকেআলাদা endpoint
লেখার গতিতে প্রভাবপ্রতি commit-এ zone পেরোনোর RTT যোগ হয়প্রায় নেই
Commit করা ডেটা হারানোসাধারণত হারায় নাLag-এর সমান হারাতে পারে
খরচপ্রায় দ্বিগুণ, কিন্তু কোনো বাড়তি query ক্ষমতা নেইপ্রতিটি আলাদা instance-এর দাম

এখানে Multi-AZ মানে একই region-এর আলাদা availability zone-এ কপি রাখা। বড় বিপদের পর সেবা ফেরানোকে বলে DR (disaster recovery). এই কাজে ভিন্ন region-এ রাখা কপিকে বলে cross-region replica. সেটি প্রায় সবসময় asynchronous, কারণ দূরত্বের কারণে synchronous লেখা খুব ধীর হয়ে যায়।

কিছু পণ্যে দুটি ভূমিকা একসাথে মেলে। যেমন কোনো কোনো cluster ধরনে standby পড়ার কাজও নেয়। তবু প্রশ্ন একই থাকে: এই কপিটি কোন বিপদের জন্য? Replication-এর তত্ত্ব, মানে log, quorum আর semi-synchronous আচরণ, আছে System Design-এর replication পর্বে আর DBMS-এর backup ও replication পর্বে.

৩ · Failover — কী ঘটে, আর app কী দেখে

Failover শুধু “standby চালু হলো” নয়। এটি কয়েকটি ধাপের একটি ক্রম, আর প্রতিটি ধাপের সময় লাগে। প্রথমে একটি লেখা কীভাবে দুই zone-এ পৌঁছায় দেখুন, তারপর primary-র zone বিকল হলে কী ঘটে। WAL হলো write-ahead log, যেখানে প্রতিটি পরিবর্তন আগে লেখা হয়। LSN হলো সেই log-এর অবস্থানের নম্বর। এখানে LSN সহজ করে ছোট সংখ্যায় দেখানো হয়েছে, আর সব সময় ধরে নেওয়া।

অবস্থা
ঘড়ি
Primary (AZ-a)
Standby (AZ-b)
Endpoint-এর IP
App-এর অবস্থা
  1. লেখা শুরু। App অর্ডার ১০০১ পাঠাল। দুই কপিই LSN ৫০০০-এ। App এখনো OK পায়নি।
  2. Primary-র log. Primary নিজের WAL-এ লিখল, LSN হলো ৫০০১. একই সাথে পরিবর্তনটি অন্য zone-এ পাঠাল। এই অবস্থায় primary মরলে app OK পায়নি, তাই কোনো মিথ্যা প্রতিশ্রুতি হয়নি।
  3. Standby নিশ্চিত করল। Standby নিজের disk-এ রেখে ack পাঠাল। লেখার পথ provider-ভেদে আলাদা: কোথাও block storage স্তরে কপি হয়, কোথাও database log স্তরে। মূল নিয়ম একই।
  4. এবার OK. মোট ৩ ms. এর মধ্যে zone পেরোনোর RTT-ও আছে। Synchronous-এর দাম এটিই, আর লাভ হলো OK পাওয়া ডেটা দুই zone-এ আছে।
  5. T+০: AZ-a-তে বিদ্যুৎ নেই। অর্ডার ১০০২ পাঠানো হয়েছিল, উত্তর আসেনি। App জানে না সেটি লেখা হয়েছে কি না। এটিই “অজানা ফল”-এর অবস্থা।
  6. T+২০: টের পাওয়া। Provider-এর monitor কয়েকটি health check ব্যর্থ দেখে নিশ্চিত হলো। তাড়াহুড়া করলে সাময়িক network সমস্যাতেই failover হতো, তাই এই দেরি ইচ্ছাকৃত।
  7. T+৫০: Standby এখন primary. Crash recovery শেষ করে সে লেখা নিতে শুরু করল। DNS-এ endpoint-এর IP বদলে গেল। কিন্তু app-এর হাতে এখনো পুরোনো IP আছে।
  8. T+৬০: App ফিরল। DNS TTL ১০ সেকেন্ড শেষ, নতুন IP পাওয়া গেল, connection আবার তৈরি হলো। ১০০২ একই idempotency key-তে আবার গেল, তাই আগে লেখা হয়ে থাকলেও অর্ডার দ্বিগুণ হবে না। LSN হলো ৫০০২.
  9. T+১৫ মিনিট: পুরো সুরক্ষা ফিরল। নতুন standby তৈরি হয়ে ডেটা মেলাল। এই সময়ের আগে পর্যন্ত আপনার কাছে একটিই কপি ছিল। এই দুর্বল সময়টিও হিসাবে রাখুন।

DNS endpoint কেন, আর app-এর দায় কী

অনেক সেবায়, যেমন RDS-এ, endpoint হলো একটি DNS নাম। Failover-এ নামটি নতুন IP দেখায়। কিছু সেবায় ঠিকানা একই থাকে, IP-টিই নতুন যন্ত্রে সরে যায় (Cloud SQL-এর HA এমন বলে নথিতে উল্লেখ আছে)। দুই ক্ষেত্রেই পুরোনো TCP connection মরে যায়, তাই reconnect app-কেই করতে হবে।

  • DNS cache: App বা runtime যদি পুরোনো IP ধরে রাখে, database চালু হলেও app মরা ঠিকানায় যেতে থাকে। কোনো কোনো runtime-এর default cache TTL মানে না।
  • Pool-এর মরা connection: Pool থেকে নেওয়ার আগে connection যাচাই করতে হবে, আর সর্বোচ্চ আয়ু বেঁধে দিতে হবে।
  • Connect timeout: মরা host অনেক সময় উত্তরই দেয় না। ছোট timeout না থাকলে একেকটি চেষ্টায় অনেকক্ষণ আটকে থাকবেন।
  • লেখার retry: উত্তর না পাওয়া লেখা হয়তো commit হয়েছে। তাই idempotency key ছাড়া লেখা retry করবেন না।

কত সময় লাগে? Instance-ধরনের Multi-AZ-এ provider-এর নথি সাধারণত এক-দুই মিনিটের কথা বলে। Cluster বা shared storage নকশায় আরও কম হতে পারে। আবার দীর্ঘ transaction চললে বা crash recovery-তে অনেক কাজ জমে থাকলে বেশি লাগতে পারে। নিজের workload-এ পরীক্ষা করে মাপুন। অনেক সেবায় “force failover” বা reboot-with-failover নামে পরীক্ষার সুযোগ আছে, যা staging-এ চালানো যায়।

Simulator — retry সেটিং কত অনুরোধ বাঁচায়

ধরে নিই টের পেতে ২০ সেকেন্ড, promote হতে ৩০ সেকেন্ড, DNS TTL ১০ সেকেন্ড, মোট ৬০ সেকেন্ড। প্রতি সেকেন্ডে ১০০ অনুরোধ আসে। মরা host-এ একটি চেষ্টা ৩ সেকেন্ড আটকে থাকে। budget হলো একটি অনুরোধের জন্য মোট সর্বোচ্চ অপেক্ষা। Exponential backoff মানে প্রতিবার বিরতি দ্বিগুণ করা, আর jitter মানে সেই বিরতিতে এলোমেলো অংশ মেশানো।

// Failover: how many requests fail under each client retry setting? All numbers ASSUMED.
function mulberry32(a){return()=>{a=a+0x6D2B79F5|0;let t=Math.imul(a^a>>>15,1|a);
  t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296}}
const DETECT = 20, PROMOTE = 30, DNS_TTL = 10;  // seconds of the failover
const RATE = 100, TIMEOUT = 3;                  // req/s; seconds one dead attempt hangs
function run(name, o) {
  const rnd = mulberry32(22);
  const up = DETECT + PROMOTE + (o.dns ?? DNS_TTL);  // this client reaches the new primary
  let failed = 0, worst = 0;
  const attempts = {};
  for (let i = 0; i < 120 * RATE; i++) {
    const born = i / RATE;
    let now = born, ok = false;
    for (let a = 0; a <= o.retries; a++) {
      const sec = Math.floor(now);
      attempts[sec] = (attempts[sec] || 0) + 1;
      if (now >= up) { ok = true; break; }
      let wait = Math.min(o.base * 2 ** a, o.cap);
      if (o.jitter) wait *= rnd();
      now += TIMEOUT + wait;
      if (now - born > o.budget) break;         // the caller gave up
    }
    if (ok) worst = Math.max(worst, now - born); else failed++;
  }
  const peak = Math.max(...Object.values(attempts));
  console.log(name.padEnd(26) + String(failed).padStart(6) +
    worst.toFixed(1).padStart(8) + String(peak).padStart(7));
}
console.log("policy".padEnd(26) + "failed maxWait peak/s");
run("no retry",               { retries: 0, base: 0, cap: 0, budget: 15 });
run("3 retries, fixed 1s",    { retries: 3, base: 1, cap: 1, budget: 15 });
run("5 retries, exp",         { retries: 5, base: 1, cap: 8, budget: 15 });
run("5 retries, exp+jitter",  { retries: 5, base: 1, cap: 8, jitter: true, budget: 15 });
run("job: 12 retries, 120s",  { retries: 12, base: 1, cap: 8, jitter: true, budget: 120 });
run("exp+jitter, DNS held 60", { retries: 5, base: 1, cap: 8, jitter: true, budget: 15, dns: 60 });
policy                    failed maxWait peak/s
no retry                    6000     0.0    100
3 retries, fixed 1s         4800    12.0    400
5 retries, exp              5100     9.0    300
5 retries, exp+jitter       4746    15.0    431
job: 12 retries, 120s          7    69.7   1068
exp+jitter, DNS held 60     9748    15.0    431

Retry না থাকলে 6000 ব্যর্থ, মানে ১০০ × ৬০. Retry শুধু বিভ্রাটের শেষ দিকের অনুরোধ বাঁচায়। তিনবার retry-তে শেষ ১২ সেকেন্ডের অনুরোধ টিকে যায়, তাই 4800 ব্যর্থ, কিন্তু চাপ হয় ৪ গুণ (400). Exponential-এ ১৫ সেকেন্ডের budget তিনটি চেষ্টাতেই ফুরিয়ে যায়, তাই ফল 5100, তিনবারের fixed retry-র চেয়েও খারাপ। অর্থাৎ retry-র সংখ্যা নয়, মোট সময়ের budget-ই আসল।

Background job-এর সারিটি লক্ষ করুন। সে ১২০ সেকেন্ড অপেক্ষা করতে পারে, তাই প্রায় সব বাঁচে (7 ব্যর্থ), কিন্তু একসাথে জমে যাওয়া চেষ্টায় peak হয় 1068, স্বাভাবিকের প্রায় ১০ গুণ। নতুন primary ঠিক এই ধাক্কাই খায়। এখানে অনুরোধ আগে থেকেই সমানভাবে ছড়ানো, তাই jitter peak তেমন কমায়নি। Jitter-এর আসল কাজ দেখা যায় যখন সব client একই মুহূর্তে ব্যর্থ হয়। শেষ সারিতে DNS ৬০ সেকেন্ড ধরে রাখায় app-এর বিভ্রাট ১১০ সেকেন্ড, ব্যর্থ 9748. একটি ছোট client সেটিং সবচেয়ে বড় ক্ষতি করল।

৪ · Replica lag আর “নিজের লেখা না দেখা”

আপনি profile-এর ছবি বদলালেন, পাতা reload করলেন, আগের ছবিই দেখলেন। আবার reload করলেন, এবার নতুন ছবি। কেউ কেউ ভাবেন bug. আসলে এটি replication lag: লেখা গেছে primary-তে, আর পড়া এসেছে একটু পিছিয়ে থাকা replica থেকে। এমন পুরোনো উত্তরকে বলে stale read.

রেলস্টেশনের বোর্ডের কথা ভাবুন। প্রধান অফিসে ট্রেনের নতুন সময় লেখা হলো, কিন্তু প্ল্যাটফর্মের বোর্ড বদলান একজন মানুষ। তিনি ব্যস্ত থাকলে বোর্ডে কিছুক্ষণ পুরোনো সময়ই থাকে। ভিড় বাড়লে এই দেরিও বাড়ে।

যা নিজে লিখেছেন তা অবশ্যই দেখতে পাওয়ার নিশ্চয়তাকে বলে read-your-writes. নিচের simulator-এ ২০ সেকেন্ড ধরে লেখা ৩,০০০/s হয়, অথচ replica প্রতি সেকেন্ডে ২,০০০-এর বেশি প্রয়োগ করতে পারে না। ১০০ জন ব্যবহারকারী প্রতি সেকেন্ডে কিছু লেখেন, তারপর ০.২ আর ৬ সেকেন্ড পরে পড়েন।

// Replica lag during a write burst, and four ways to route reads. All numbers ASSUMED.
const APPLY = 2000, NET = 0.05;        // replica applies 2000 writes/s; 50 ms network
const lag = [];                        // lag[t] = seconds behind at second t
let backlog = 0;
console.log("  t  writes  backlog  lag(s)");
for (let t = 0; t < 70; t++) {
  const writes = (t >= 10 && t < 30) ? 3000 : 500;  // a 20-second burst
  backlog = Math.max(0, backlog + writes - APPLY);
  lag[t] = backlog / APPLY + NET;
  if (t % 10 === 9) {
    console.log(String(t).padStart(3) + String(writes).padStart(8) +
      String(backlog).padStart(9) + lag[t].toFixed(2).padStart(8));
  }
}
// 100 users each second save something, then read it twice: after 0.2 s and after 6 s.
const USERS = 100, READS = [0.2, 6], STICKY = 5;
function route(toPrimary) {
  let bad = 0, sent = 0;
  for (let t = 0; t < 60; t++) for (const d of READS) {
    const l = lag[Math.floor(t + d)];
    if (toPrimary(d, l)) sent += USERS;
    else if (l > d) bad += USERS;
  }
  return String(bad).padStart(6) + String(sent).padStart(10);
}
console.log("routing".padEnd(30) + " stale toPrimary");
console.log("all reads to replica".padEnd(30) + route(() => false));
console.log("primary for 5 s after write".padEnd(30) + route(d => d <= STICKY));
console.log("replica only if caught up".padEnd(30) + route((d, l) => l > d));
console.log("all reads to primary".padEnd(30) + route(() => true));
  t  writes  backlog  lag(s)
  9     500        0    0.05
 19    3000    10000    5.05
 29    3000    20000   10.05
 39     500     5000    2.55
 49     500        0    0.05
 59     500        0    0.05
 69     500        0    0.05
routing                        stale toPrimary
all reads to replica            4700         0
primary for 5 s after write     1400      6000
replica only if caught up          0      4700
all reads to primary               0     12000

লেখা যতক্ষণ ২,০০০/s-এর ওপরে, backlog বাড়তেই থাকে: প্রতি সেকেন্ডে ১,০০০ করে, ২০ সেকেন্ডে 20000, আর lag ১০ সেকেন্ডের বেশি। চাপ কমলেও backlog সাথে সাথে শেষ হয় না, কমে ২,০০০ − ৫০০ = ১,৫০০/s হারে। তাই ঝড় থামার পরও প্রায় ১৩ সেকেন্ড পুরোনো ডেটা আসে।

সব read replica-তে পাঠালে 4700টি পড়া পুরোনো। “লেখার পর ৫ সেকেন্ড primary” নিয়মে কমে 1400, কারণ ৫ সেকেন্ড একটি অনুমান, আর lag তার চেয়ে বড় হয়েছিল। Replica-র অবস্থান মিলিয়ে পড়লে (লেখার LSN পর্যন্ত replica পৌঁছেছে কি না) ভুল 0, আর primary-তে যায় মাত্র 4700, অর্ধেকেরও কম। সব primary-তে পাঠালেও ভুল শূন্য, কিন্তু তখন replica রাখার মানেই থাকে না।

  • Lag-কে metric বানান: Replica-প্রতি lag দেখুন, গড় নয়, আর alarm বসান (পরের অংশে)।
  • সব read সমান নয়: Dashboard-এর গ্রাফ কয়েক সেকেন্ড পুরোনো হলে চলে। পেমেন্টের ফল বা ব্যালান্স সাধারণত চলে না।
  • Replica ছোট রাখবেন না: ছোট replica লেখা প্রয়োগে পিছিয়ে পড়ে। Primary-র সমান আকার দিয়ে শুরু করা নিরাপদ।
  • দীর্ঘ report query: Replica-তে লম্বা query চললে replay আটকে lag বাড়তে পারে, বা query বাতিল হতে পারে। PostgreSQL-এ এটি একটি পরিচিত trade-off.

Monotonic read-এর মতো অন্য anomaly আর তাদের সমাধান আছে System Design-এর replication পর্বে.

৫ · Backup, PITR আর snapshot

Standby আর replica যন্ত্রের বিপদ থেকে বাঁচায়। মানুষের ভুল থেকে বাঁচায় না, কারণ ভুল DELETE-ও মুহূর্তে সব কপিতে পৌঁছে যায়। এখানেই backup-এর কাজ।

ধরনকীকখন কাজে লাগে
Automated backupProvider-এর নিয়মিত snapshot আর জমানো transaction logPITR, দৈনন্দিন সুরক্ষা। Retention শেষে মুছে যায়
PITRSnapshot + log replay দিয়ে নির্দিষ্ট মুহূর্তে ফেরাভুল query, খারাপ migration
Manual snapshotআপনি হাতে নেওয়া ছবি, যা নিজে থেকে মোছে নাবড় পরিবর্তনের আগে, দীর্ঘদিন রাখা
অন্য region বা account-এ কপিBackup-এর আলাদা কপিRegion-এর বিপদ, account ফাঁস হওয়া

PITR-এর ধারণা সহজ: একটি পুরোনো ছবি থেকে শুরু করে log-এর প্রতিটি পরিবর্তন আবার চালানো, আর ঠিক কাঙ্ক্ষিত মুহূর্তে থামা। Log সাধারণত কয়েক মিনিট পরপর জমা হয়, তাই সর্বশেষ restorable সময় বর্তমানের কয়েক মিনিট পেছনে থাকতে পারে। আরও একটি গুরুত্বপূর্ণ কথা: অনেক সেবায় PITR পুরোনো database বদলায় না, একটি নতুন instance বানায়। তাই endpoint বদলাবে।

নিচের ঘটনাটি কাল্পনিক। একটি বাজার অ্যাপে ভোর ২টায় snapshot হয়, আর অর্ডার আসে মিনিটে ৩টি। দুপুরে একজন অপারেটর staging ভেবে production-এ query চালালেন।

অর্ডারের সারির সংখ্যা
ঘড়ি
Live primary
Standby
নতুন instance
  1. ০২:০০, snapshot. Provider নিজে থেকে snapshot নিল, ১০,০০০ সারি। সারাদিন WAL জমা হচ্ছে।
  2. ১৪:৩১, স্বাভাবিক দিন। ৭৫১ মিনিটে মিনিটে ৩টি করে ২,২৫৩টি নতুন অর্ডার, মোট ১২,২৫৩. ১৪:৩২-এ হবে ১২,২৫৬.
  3. ১৪:৩২:০০, ভুল। WHERE ছাড়া DELETE. ১২,২৫৬টি সারি গেল। Synchronous standby-তেও সাথে সাথে ০. Replica-তে একটু পরে। কোনো কপিই বাঁচাল না।
  4. ১৪:৪০, alarm. ৮ মিনিটে ২৪টি নতুন অর্ডার এসেছে, এগুলো আসল ডেটা। Live instance মুছে ফেলা যাবে না। তাই অর্ডার নেওয়া সাময়িকভাবে থামানো হলো, আর সময়টি নোট করা হলো। শান্ত থাকাই এখন কাজ।
  5. ১৪:৪৫, restore শুরু। লক্ষ্য ১৪:৩১:০০, মানে ভুলের এক মিনিট আগে। ঠিক সময় নিয়ে সন্দেহ থাকলে আগে একটি নিরাপদ বিন্দুতে ফেরাই বুদ্ধির কাজ। S-0200 থেকে নতুন instance তৈরি হলো, ১০,০০০ সারি।
  6. ১৫:১০, log replay. WAL চলে ১৪:৩১:০০-তে থামল। ১২,২৫৩ সারি। Row count আর মোট টাকার যোগফল মিলিয়ে দেখা হলো।
  7. ১৫:২০, ফেরত আনা। পুরো app নতুন instance-এ নিলে ২৪টি নতুন অর্ডার হারাত। তাই মোছা সারিগুলো live-এ কপি করা হলো: ১২,২৫৩ + ২৪ = ১২,২৭৭.
  8. ১৫:৫০, শেষ ৩টি। ১৪:৩১ থেকে ১৪:৩২-এর ৩টি অর্ডার তখনো নেই। Audit log থেকে ঠিক সময় মিলিয়ে দ্বিতীয় restore হলো ১৪:৩১:৫৯-এ, আর ৩টি সারি কপি হলো: ১২,২৮০ = ১২,২৫৬ + ২৪. কোনো অর্ডার হারায়নি, তবে কাজ লেগেছে ৭৮ মিনিট।

Backup নিজে থেকে প্রমাণ হয় না। যে backup কখনো restore করে দেখেননি, তার ওপর ভরসা করবেন না। মাসে অন্তত একবার restore করে row count মেলান, আর সময় মাপুন। সেই সময়টাই আপনার বাস্তব RTO. Deletion protection চালু রাখুন, আর instance মোছার আগে final snapshot নিন, কারণ অনেক সেবায় instance মুছলে automated backup-ও চলে যায়। RPO, RTO আর DR-এর চারটি কৌশল থাকছে পর্ব ২৪ · Backup আর disaster recovery-তে।

৬ · Maintenance window আর major version upgrade

Patch provider লাগায়, কিন্তু কখন লাগাবে সেটি আপনি বলেন। সপ্তাহের যে সময়টি ঠিক করা থাকে, তাকে বলে maintenance window. বাংলাদেশি ব্যবহারকারীর জন্য রাত ৩টা-৪টার মতো শান্ত সময় সাধারণত ভালো। অনেক সেবায় window দিতে হয় UTC-তে, তাই বাংলাদেশ সময় থেকে ৬ ঘণ্টা বাদ দিন: রাত ৩টা মানে আগের দিনের 21:00 UTC.

OS-এর patch-এ Multi-AZ-এ provider সাধারণত আগে standby-কে patch করে, failover করে, তারপর পুরোনো primary-কে patch করে। তাই “maintenance” মানে প্রায়ই একটি ছোট failover. তবে engine version বদলালে অনেক সময় দুই কপি একসাথে upgrade হয়, যেমন RDS-এর instance-ধরনের Multi-AZ-এ। তখন কয়েক মিনিট বিভ্রাট হতে পারে, তাই নিজের সেবার নথি দেখে নিন। ওপরের সব retry-র হিসাব এখানেও খাটে।

বিষয়Minor upgradeMajor upgrade
উদাহরণPostgreSQL 16.3 → 16.4PostgreSQL 15 → 16
কী বদলায়Bug আর নিরাপত্তা সংশোধনCatalog, query planner, আচরণ
বিভ্রাটছোটIn-place হলে বেশি হতে পারে
ফেরা যায়?অনেক managed সেবায় সরাসরি ফেরা যায় না, তবে ঝুঁকি কমIn-place-এর পর সাধারণত নয়, আগের snapshot-ই ভরসা
স্বয়ংক্রিয়?চালু রাখা যায়সাধারণত আপনি শুরু করেন

Major upgrade-এর জন্য নিরাপদ ক্রম:

  1. Snapshot থেকে একটি কপি বানিয়ে সেখানে upgrade করে সময় মাপা।
  2. Extension আর driver-এর সামঞ্জস্য দেখা।
  3. আসল query-গুলো চালিয়ে plan মেলানো, কারণ নতুন planner ভিন্ন পথ নিতে পারে।
  4. Upgrade-এর পর statistics আবার তৈরি করা (PostgreSQL-এ ANALYZE).
  5. সম্ভব হলে blue-green upgrade: নতুন version-এর একটি কপি replication দিয়ে সমান রাখা, তারপর অল্প সময়ে switch করা।

৭ · Connection — যে সীমা সবার আগে ফুরায়

প্রতিটি database connection-এর দাম আছে। PostgreSQL প্রতিটি connection-এর জন্য আলাদা OS process চালায়, তাই memory আর CPU দুটোই খরচ হয়। নতুন connection খুলতে TCP, TLS আর authentication লাগে, যা একটি সাধারণ query-র চেয়ে অনেক ব্যয়বহুল। তাই database-এ max_connections নামে একটি সীমা থাকে। সাধারণ PostgreSQL-এ default ১০০, আর managed সেবায় এটি সাধারণত instance-এর memory থেকে হিসাব হয়। কিছু slot admin, replication আর monitoring-এর জন্য সংরক্ষিত থাকে।

লঞ্চঘাটে টিকিট কাউন্টার ৫টি। প্রতিটি যাত্রী নিজের জন্য একটি করে কাউন্টার সারাদিন আটকে রাখলে ষষ্ঠ যাত্রী ঢুকতেই পারবেন না, যদিও বাকিরা শুধু বসে আছেন। Connection pool মানে কাউন্টার ভাগ করে নেওয়া: যাঁর কাজ আছে তিনি দাঁড়াবেন, কাজ শেষে ছেড়ে দেবেন।

মূল হিসাব একটিই:

মোট connection = instance × pool size ≤ max_connections − সংরক্ষিত

আর সত্যিই কতটি connection ব্যস্ত, সেটি বলে Little's law: ব্যস্ত connection = প্রতি সেকেন্ডে query × একটি query-র সময়। প্রতি instance সেকেন্ডে ১০০ অনুরোধ, প্রতি অনুরোধে ৩টি query, প্রতিটি ১০ ms হলে গড়ে ১০০ × ৩ × ০.০১ = ৩টি connection ব্যস্ত। Pool ২০ হলে বাকি ১৭টি শুধু বসে থেকে memory খায়।

// Connections: app instances x pool size against max_connections. All numbers ASSUMED.
const MAX_CONN = 500, RESERVED = 20;      // slots kept for admin, replication, monitoring
const USABLE = MAX_CONN - RESERVED;
const INST_RPS = 100, QUERIES = 3, QUERY_S = 0.01;  // per instance, per request
const FN_RPS = 10;                        // one function copy: 10 requests per second
const verdict = n => n <= USABLE ? "ok" : "REJECT " + (n - USABLE);

// Little's law: connections truly busy = arrival rate x time held
const busy = INST_RPS * QUERIES * QUERY_S;
console.log("usable slots =", USABLE, "| busy per instance =", busy);

console.log("instances  pool  wanted  verdict");
for (const [inst, pool] of [[10, 20], [20, 20], [30, 20], [40, 20], [40, 12]]) {
  console.log(String(inst).padStart(9) + String(pool).padStart(6) +
    String(inst * pool).padStart(8) + "  " + verdict(inst * pool));
}
console.log("largest safe pool at 40 instances =", Math.floor(USABLE / 40));

// A proxy: many client connections share a few server connections.
const SERVER_CONN = 150;
console.log("proxy: 800 client conns ->", SERVER_CONN, "server conns; busy", 40 * busy);

// Serverless: every running copy wants its own connection when there is no proxy.
const fnBusy = FN_RPS * QUERIES * QUERY_S;
console.log("functions  direct      busy  via proxy");
for (const fn of [100, 480, 1000, 3000]) {
  const b = Math.round(fn * fnBusy);
  console.log(String(fn).padStart(9) + "  " + verdict(fn).padEnd(11) +
    String(b).padStart(4) + "  " + (b <= SERVER_CONN ? "ok" : "queues"));
}
usable slots = 480 | busy per instance = 3
instances  pool  wanted  verdict
       10    20     200  ok
       20    20     400  ok
       30    20     600  REJECT 120
       40    20     800  REJECT 320
       40    12     480  ok
largest safe pool at 40 instances = 12
proxy: 800 client conns -> 150 server conns; busy 120
functions  direct      busy  via proxy
      100  ok           30  ok
      480  ok          144  ok
     1000  REJECT 520  300  queues
     3000  REJECT 2520 900  queues

ব্যবহারযোগ্য slot ৫০০ − ২০ = ৪৮০. ২০ instance পর্যন্ত সব ঠিক। ৩০ instance-এ দরকার 600, তাই ১২০টি connection প্রত্যাখ্যাত, আর ৪০-এ ৩২০টি। অথচ প্রতিটি instance-এ গড়ে ব্যস্ত মাত্র ৩টি। Pool ১২ করলেই ৪০ instance ঠিক ৪৮০-তে বসে, আর ৪ গুণ headroom থাকে।

Proxy-তে ৮০০ client connection ভাগ করে নেয় ১৫০টি server connection, কারণ গড়ে ব্যস্ত 120. Serverless-এর সারি সবচেয়ে শিক্ষণীয়। ১,০০০ function সরাসরি এলে ৫২০টি প্রত্যাখ্যাত। Proxy দিলে প্রত্যাখ্যান থামে, কিন্তু 300টি connection ব্যস্ত থাকতে চায়, proxy-র আছে ১৫০, তাই অনুরোধ অপেক্ষায় থাকে। Proxy বসে থাকা connection কমায়, আসল কাজ কমায় না।

Pool তিন জায়গায় থাকতে পারে

  • App-এর ভেতরে: যেমন HikariCP, SQLAlchemy-র pool. সহজ, কিন্তু প্রতিটি instance-এর নিজের pool, তাই মোট সংখ্যা instance-এর সাথে বাড়ে।
  • মাঝখানের proxy: PgBouncer বা database proxy, যেমন RDS Proxy. অনেক client, অল্প server connection.
  • দুটোই: App-এ ছোট pool, মাঝে proxy. বড় সিস্টেমে এটি সাধারণ।
[databases]
appdb = host=db.internal.example port=5432 dbname=appdb

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
default_pool_size = 150
max_client_conn = 2000
server_idle_timeout = 300

এখানে pool_mode = transaction মানে transaction pooling: একটি server connection শুধু এক transaction-এর জন্য ধার দেওয়া হয়। এতে সবচেয়ে বেশি ভাগাভাগি হয়, তবে session-এর স্মৃতি থাকে না। SET, session-এর advisory lock আর LISTEN ঠিকমতো চলে না, আর prepared statement version-ভেদে সমস্যা করে। RDS Proxy-তে একই ধরনের session-অবস্থা দেখলে connection আটকে যায়, যাকে বলে pinning. তখন ভাগাভাগির লাভ কমে। উদাহরণের listen_addr চলবে শুধু private network-এ, আর সামনে firewall থাকতে হবে।

Connection storm

এবার আসল বিপদ। Connection storm মানে অল্প সময়ে একঝাঁক নতুন connection-এর চেষ্টা। সাধারণত autoscaling, deployment, failover বা serverless function-এর ঝড়ে এটি ঘটে। ধরি max_connections ৫০০, সংরক্ষিত ২০, প্রতিটি instance চালু হয়েই ২০টি connection খোলে। সংখ্যাগুলো ধরে নেওয়া।

মিনিটের শেষে
মিনিট
App instance
চাওয়া connection
খোলা connection
প্রত্যাখ্যাত
Database CPU
  1. মিনিট ০, শান্ত। ১০ × ২০ = ২০০. ব্যবহারযোগ্য ৪৮০-র অনেক নিচে। CPU ৪৫%.
  2. মিনিট ১, ভিড় শুরু। Scale out-এ ১০টি নতুন instance. প্রত্যেকে চালু হয়েই ২০টি connection খুলল, মোট ৪০০. TLS আর process তৈরির কাজে CPU হলো ৬২%, অথচ তখনো একটি বাড়তি query-ও চলেনি।
  3. মিনিট ২, সীমা পার। ৩০ × ২০ = ৬০০ চাই, কিন্তু slot ৪৮০. ১২০টি চেষ্টা ব্যর্থ। লগে এলো PostgreSQL-এর পরিচিত বার্তা too many clients already.
  4. মিনিট ৩, ঘূর্ণি। নতুন instance database পাচ্ছে না, তাই health check ব্যর্থ। Autoscaler সেগুলো বদলে আরও নতুন instance আনল। ব্যর্থ app-গুলো backoff ছাড়া প্রতি সেকেন্ডে আবার চেষ্টা করছে। প্রতিটি চেষ্টায় CPU খরচ, তাই ৯৭%.
  5. মিনিট ৪, চূড়া। Database ধীর, query-র সময় ৪০ ms থেকে ৯০০ ms, তাই connection বেশিক্ষণ আটকে থাকছে। Latency-ভিত্তিক autoscaler ভাবল ক্ষমতা কম, তাই আরও ১০টি আনল। চাওয়া ৮০০, প্রত্যাখ্যাত ৩২০, CPU ১০০%. App বাড়াতে গিয়ে সমস্যাই বাড়ল।
  6. মিনিট ৫, জরুরি সমাধান। Autoscaler থামিয়ে pool ১০ করা হলো: ৪০ × ১০ = ৪০০, ৪৮০-র নিচে। Error থামল, CPU ৭২%. ডেটাবেসকে শ্বাস নেওয়ার সুযোগ দেওয়াই প্রথম কাজ।
  7. মিনিট ৬, স্থায়ী সমাধান। মাঝে proxy বসল। App-এর দিকে আবার ৮০০ client connection, database-এ মাত্র ১৫০ server connection, CPU ৬০%. সাথে connection ধীরে খোলা, jitter-সহ backoff আর autoscaler-এর max-এর সাথে হিসাব মেলানো।

একই নিয়ম আরও দুই জায়গায় খাটে। Rolling deployment-এ পুরোনো আর নতুন instance একসাথে থাকে, তাই max-এর সাথে surge যোগ করে হিসাব করবেন। আর serverless function-এ প্রতিটি চলমান কপি আলাদা, তাই ভিড়ে কয়েকশো কপি একসাথে connection চাইতে পারে। সেখানে proxy আর function-এর concurrency সীমা, দুটোই লাগে। Function-এর দিকটি থাকছে পর্ব ৬৯ · Serverless function-এ।

৮ · Sizing, storage আর monitoring

Instance বাছার সময় CPU-র আগে memory দেখুন। Database-এর গতি অনেকটাই নির্ভর করে ব্যবহৃত ডেটা memory-তে থাকে কি না, তার ওপর। Disk থেকে পড়া memory-র চেয়ে অনেক ধীর। শুরুতে অনুমান করে ছোট আকার নিন, এক-দুই সপ্তাহ মাপুন, তারপর rightsizing করুন। Burstable ধরনের instance production-এ সতর্কভাবে ব্যবহার করুন, কারণ credit ফুরালে হঠাৎ ধীর হয়ে যায় (পর্ব ১৫)।

Storage autoscaling: Disk প্রায় ভরে গেলে storage নিজে থেকে বাড়ে। Disk ভরে যাওয়া database-এর জন্য ভয়ংকর, কারণ লেখা থেমে যেতে পারে। তাই এটি চালু রাখা ভালো, তবে সর্বোচ্চ সীমা দিন। অনেক সেবায় storage কমানো যায় না, আর দুটি বৃদ্ধির মাঝে নির্দিষ্ট বিরতি থাকে। তাই হঠাৎ চাপে এটি একা যথেষ্ট নয়। ৮০% ভরলে alarm বসান। একটি ছোট হিসাব: ৫০০ GB-র ৪০০ GB ভরা, দিনে ৫ GB বাড়ছে। তাহলে খালি ১০০ GB চলবে ১০০ ÷ ৫ = ২০ দিন।

Metricখারাপ হলে অর্থপ্রথম পদক্ষেপ
CPUIndex ছাড়া query, বা সত্যিই বেশি চাপTop query দেখা, তারপর আকার
Memory, cache hitডেটা memory-তে ধরছে নাQuery আর index, তারপর বড় instance
IOPS, disk latencyDisk-এর সীমায় ধাক্কাProvisioned IOPS, query কমানো
Connection সংখ্যাPool ভুল, leak, বা stormProxy, pool ছোট করা
Replication lagReplica পিছিয়ে, stale readReplica-র আকার, লম্বা query
Slow queryনির্দিষ্ট query ধীরEXPLAIN, index
Free storageDisk ভরছেAlarm, storage বাড়ানো, পুরোনো ডেটা সরানো

মনে রাখবেন, CPU বেশি মানেই বড় instance নয়। প্রায়ই একটি অনুপস্থিত index-ই আসল কারণ। Metric-এর মধ্যে সম্পর্ক দেখুন: connection বাড়ল, তারপর CPU, তারপর latency, এই ক্রম storm-এর চিহ্ন।

-- how many connections, and what are they doing?
SELECT state, count(*) FROM pg_stat_activity GROUP BY state;

-- on the primary: how far behind is each replica?
SELECT application_name, state, replay_lag FROM pg_stat_replication;

SHOW max_connections;

৯ · Private network আর self-managed বনাম managed খরচ

Internet-এ database নয়

Database-এর সরাসরি internet ঠিকানা থাকা উচিত নয়। Public endpoint বন্ধ রাখুন, আর instance রাখুন VPC-র private subnet-এ। Security group-এ শুধু app-এর security group থেকে database port খুলুন, কখনোই 0.0.0.0/0 নয়। Admin কাজের জন্য bastion বা session manager ব্যবহার করুন (পর্ব ১২)। সংযোগে TLS, disk-এ encryption, আর password কোডে নয়, secret manager-এ (পর্ব ৩৩)। Subnet-এর নকশা থাকছে পর্ব ২৫ · VPC আর subnet-এ, আর security group-এর গভীর আলোচনা পর্ব ২৭-এ।

নিচের কমান্ডটি একটি AWS উদাহরণ, যেখানে এই পর্বের সিদ্ধান্তগুলো একসাথে দেখা যায়। অন্য provider-এ flag-এর নাম আলাদা, ধারণা একই। এটি চালানো জরুরি নয়। চালালে টাকা লাগতে পারে।

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

# clean up after practice, or the bill keeps running
aws rds modify-db-instance --db-instance-identifier example-orders-db \
  --no-deletion-protection --apply-immediately
aws rds delete-db-instance --db-instance-identifier example-orders-db \
  --final-db-snapshot-identifier example-orders-final

Self-managed বনাম managed — হিসাব

একই কাজ নিজে দুটি VM-এ চালালে বিল কম দেখায়। তবে সেখানে backup script, patch, failover tool আর রাতের on-call-ও আপনার। তাই শুধু infrastructure নয়, মানুষের সময়ও ধরে TCO হিসাব করতে হয়। নিচের সব দাম ধরে নেওয়া। আসল দামের জন্য provider-এর pricing পাতা দেখুন।

// Self-managed vs managed, per 30-day month. Every price is ASSUMED, none is real.
const HOURS = 720;
// two nodes (primary + standby), two copies of disk, one copy of backup
const bill = (perHour, gb, premium, diskPerGb) =>
  2 * perHour * premium * HOURS + 2 * gb * diskPerGb + gb * 0.05;

console.log("size    self$  mgd$  extra$  breakeven h @ $10  @ $40");
for (const [name, perHour, gb, mgdOps] of [
  ["small", 0.10, 100, 8], ["medium", 0.40, 500, 10], ["large", 3.20, 4000, 15],
]) {
  const self = bill(perHour, gb, 1.0, 0.10);
  const mgd  = bill(perHour, gb, 1.7, 0.12);      // assume a 70% compute premium
  const extra = mgd - self;
  const hours = rate => (extra / rate + mgdOps).toFixed(0);
  console.log(name.padEnd(6) + self.toFixed(0).padStart(6) + mgd.toFixed(0).padStart(6) +
    extra.toFixed(0).padStart(8) + hours(10).padStart(19) + hours(40).padStart(7));
}
// Ops time for the self-managed side if we assume 40 hours a month at $10:
console.log("medium self total =", (bill(0.40, 500, 1, 0.10) + 40 * 10).toFixed(0),
  "| medium managed total =", (bill(0.40, 500, 1.7, 0.12) + 10 * 10).toFixed(0));
size    self$  mgd$  extra$  breakeven h @ $10  @ $40
small    169   274     105                 18     11
medium   701  1124     423                 52     21
large   5608  8994    3386                354    100
medium self total = 1101 | medium managed total = 1224

extra$ হলো managed-এর মাসিক বাড়তি infrastructure খরচ। breakeven h মানে self-managed-এ মাসে এত ঘণ্টার বেশি মানুষের কাজ লাগলে managed সস্তা। ঘণ্টায় $১০ হারে small-এ সীমা ১৮ ঘণ্টা। Patch, backup যাচাই আর on-call মিলিয়ে একটি production database মাসে ১৮ ঘণ্টার কমে চালানো কঠিন, তাই সেখানে managed প্রায় নিশ্চিত জেতে। Medium-এ ৪০ ঘণ্টা ধরলে self-managed $১২৩ সস্তা (1101 বনাম 1224), কিন্তু ঘণ্টার দাম $৪০ হলে সীমা নেমে আসে ২১ ঘণ্টায়।

Large-এ বাড়তি $৩,৩৮৬, মানে সামনে বেশ কিছু ঘণ্টা কিনতে পারেন। তাই খুব বড় আকারে কিছু দল নিজে চালানোর কথা ভাবে। তবে সেখানে দক্ষ DBA, পরীক্ষিত failover আর ২৪ ঘণ্টার on-call দরকার। এই সারণি একটি খরচ বাদ দিয়েছে, আর সেটিই সবচেয়ে বড়: একটি ভুল restore বা ব্যর্থ failover-এর দাম।

Managed-এর বিলে লুকানো দিকগুলোও দেখুন: IOPS, retention-এর বাইরের backup, cross-region কপি, আর পুরোনো version-এর বর্ধিত support ফি, যদি provider নেয়। অন্যদিকে self-managed-এ zone পেরোনো replication traffic-এর খরচ আলাদা আসতে পারে। বিলের বিস্তারিত থাকছে পর্ব ৭২ · Cloud-এর বিল-এ।

আরও গভীরে: Aurora-র নকশা বর্ণিত আছে Verbitski ও সহকর্মীদের SIGMOD ২০১৭ পেপারে। মূল কথা, network-এ পুরো data page নয়, শুধু redo log পাঠানো, আর storage node নিজেই page তৈরি করে। লেখা নিশ্চিত হয় ছয় কপির চারটিতে পৌঁছালে। Quorum-এর তত্ত্ব আছে System Design-এর quorum পর্বে, আর connection-এর আকার নিয়ে PostgreSQL wiki-র “Number Of Database Connections” পাতাটি পড়ার মতো।

পরীক্ষা ও ইন্টারভিউতে:

  • Standby আর read replica-র পার্থক্য? Standby availability-র জন্য, সাধারণত synchronous আর query নেয় না। Replica read scaling-এর জন্য, সাধারণত asynchronous.
  • Multi-AZ থাকলে backup কেন? ভুল query সব কপিতে যায়। মানুষের ভুল থেকে ফেরায় PITR.
  • Read-your-writes কীভাবে দেবেন? লেখার পর নিজের পড়া primary-তে, অথবা replica-র LSN মিলিয়ে পড়া।
  • “Too many connections” পেলে? Instance × pool গুনুন, pool ছোট করুন, proxy বসান। সীমা বাড়ানো শেষ উপায়।
  • Failover-এ app কী করবে? ছোট timeout, jitter-সহ backoff, DNS TTL মানা, মরা connection বাতিল, লেখায় idempotency key.

১০ · AI-এর যুগে managed database যাচাই

AI কয়েক সেকেন্ডে পুরো database-এর Terraform বা কমান্ড লিখে দেয়, আর সেগুলো দেখতে ঠিকঠাকই লাগে। কিন্তু তার উদাহরণগুলো প্রায়ই tutorial-এর জন্য লেখা, production-এর জন্য নয়। আর database-এ ভুলের দাম সবচেয়ে বেশি, কারণ ডেটা ফেরত আনা কঠিন।

AI যা লেখেবিপদযাচাই
publicly_accessible = true, port-এ 0.0.0.0/0Database internet-এ খোলাPrivate subnet, শুধু app-এর security group
skip_final_snapshot = trueমুছলে শেষ কপিও নেইFinal snapshot, deletion protection
Password সরাসরি কোডেSecret ফাঁসSecret manager, কোডে নয়
IAM-এ rds:* বা *ভুল হাতে সব মোছার ক্ষমতাLeast privilege
Read replica-কে HA বলাFailover-এর দিনে কিছুই হয় নাMulti-AZ, failover পরীক্ষা
Pool size ১০০, instance গোনা ছাড়াConnection stormInstance × pool, surge সহ হিসাব
Backup retention ০ বা খুব ছোটPITR নেইPlan পড়া, retention যাচাই
বানানো flag বা পুরোনো argument, engine-এ latestCommand ব্যর্থ, বা না জেনে version বদল--help, নথি, version বেঁধে রাখা
terraform destroy বা instance মোছার কমান্ড, সতর্কতা ছাড়াProduction ডেটা শেষterraform plan পড়া, আলাদা পরিবেশে পরীক্ষা
Multi-AZ, IOPS, backup-এর খরচের কথা নেইবিলে চমকনিজে হিসাব, budget alert

AI-কে নকশা লিখতে না বলে নিজের সংখ্যা দিয়ে হিসাব করাতে আর ফাঁক খুঁজতে বলুন। প্রম্পটে কোনো সত্যিকারের password, account id বা endpoint দেবেন না।

আমার একটি PostgreSQL managed database আছে। মাপা তথ্য: max_connections [৫০০], app instance সর্বোচ্চ [৪০], pool size [২০], প্রতি অনুরোধে [৩]টি query, গড় query সময় [১০] ms, প্রতি instance সেকেন্ডে [১০০] অনুরোধ, read replica [২]টি। ১. আমার connection-এর হিসাব দেখাও, rolling deployment-এর surge সহ। ২. Failover হলে আমার app-এ কত অনুরোধ ব্যর্থ হবে, কী কী ধরে নিচ্ছ তা আলাদা করে লেখো। ৩. Read-your-writes কোথায় ভাঙতে পারে? ৪. কোনো কমান্ড বা Terraform দিলে আগে বলো সেটি কী বদলাবে, downtime হবে কি না, ডেটা মুছবে কি না, খরচ বাড়বে কি না। ৫. প্রতিটি flag বা argument-এর পাশে বর্তমান নথির কোন অংশে আছে তা বলো। নিশ্চিত না হলে সেটিও লেখো। ৬. আমার কাছে password, secret বা account id চাইবে না।

চালুর আগের চেকলিস্ট

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

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

প্র ০১Multi-AZ আর একাধিক replica থাকলে backup কি সত্যিই দরকার?

হ্যাঁ, আর এর সবচেয়ে বিখ্যাত শিক্ষা এসেছে একটি প্রকাশ্য ঘটনা থেকে। ২০১৭ সালের জানুয়ারিতে GitLab.com-এর database-এ replication lag নিয়ে কাজ করার সময় একজন প্রকৌশলী ভুল server-এ ডেটা ডিরেক্টরি মুছে ফেলেন। Replica তখনই পিছিয়ে ছিল, আর তাকে আবার গড়ার কাজই চলছিল। তারপর দেখা গেল, নিয়মিত backup-এর পথগুলো ঠিকমতো কাজ করছিল না। শেষে বাঁচাল একটি প্রায় ছয় ঘণ্টা পুরোনো disk snapshot, যা অন্য কাজে নেওয়া হয়েছিল। GitLab নিজেই পুরো ঘটনা প্রকাশ করেছিল, আর সেই থেকে এটি শিল্পের পরিচিত উদাহরণ।

এখান থেকে তিনটি কথা বোঝা যায়। প্রথমত, replication একটি চলমান কপি। আপনি যা-ই করবেন, ভালো বা খারাপ, সেটিই সে অনুসরণ করবে। Durability-র প্রশ্নে সে হার্ডওয়্যারের বিপদ থেকে বাঁচায়, ইতিহাস সংরক্ষণ করে না। Backup হলো অতীতের একটি কপি, আর PITR হলো অতীতে ফেরার পথ।

দ্বিতীয়ত, backup আছে কি না সেটি প্রশ্ন নয়, restore হয় কি না সেটিই প্রশ্ন। Managed সেবা snapshot নেওয়ার কাজটি নির্ভরযোগ্য করে, কিন্তু আপনার retention, আলাদা account-এ কপি আর restore-এর সময় মাপার কাজ করে না। তৃতীয়ত, চাপের মধ্যে মানুষ ভুল করে। তাই গুরুত্বপূর্ণ কমান্ডে দ্বিতীয় জনের দেখা, production-এর আলাদা prompt রং আর পরিষ্কার runbook লাগে।

তাই retention, আলাদা account-এ কপি আর মাসিক restore-এর অনুশীলন runbook-এ লিখে রাখুন। ছোট দলে এই কাজটি একজনের নামে দেওয়া ভালো, নইলে সবাই ভাবেন অন্য কেউ দেখছেন।

মূল উপলব্ধি: Replica প্রশ্ন করে “এখন ডেটা কোথায়?”, আর backup উত্তর দেয় “ভুলের আগে ডেটা কেমন ছিল?” দুটো আলাদা বিপদ, দুটোই লাগবে।

প্র ০২Failover স্বয়ংক্রিয় হওয়াই তো ভালো। তাহলে ৪৩ সেকেন্ডের একটি network সমস্যা কীভাবে ২৪ ঘণ্টার বিভ্রাট ঘটায়?

২০১৮ সালের অক্টোবরে GitHub-এর একটি প্রকাশিত ঘটনা এর ভালো উদাহরণ। Network-এর রক্ষণাবেক্ষণে ৪৩ সেকেন্ডের মতো সংযোগ বিচ্ছিন্ন হয়। তাদের স্বয়ংক্রিয় failover tool অন্য coast-এর data center-এ MySQL primary বদলে দেয়। সংযোগ ফিরলে দেখা গেল দুই দিকেই কিছু লেখা আছে, যা অন্য দিকে নেই। ফলে সহজে উল্টানো গেল না, আর backup থেকে পুনরুদ্ধার ও replication ধরতে প্রায় এক দিন লেগে যায়। GitHub-এর নিজের বিশ্লেষণে সময়টি প্রায় ২৪ ঘণ্টা।

মূল সমস্যা হলো বিকল আর বিচ্ছিন্ন আলাদা করতে না পারা। দূর থেকে একটি node নীরব মানে সে মৃত, না পথ কাটা, সেটি বোঝা যায় না। খুব দ্রুত failover করলে সাময়িক সমস্যাতেও ডেটার ইতিহাস দুই ভাগ হতে পারে, যাকে split-brain বলে। খুব ধীরে করলে বিভ্রাট বাড়ে। এই কারণেই আমাদের stepper-এ ২০ সেকেন্ডের দেরি একটি ইচ্ছাকৃত সিদ্ধান্ত।

একই region-এ synchronous standby থাকলে কাজ অনেক সহজ, কারণ OK পাওয়া ডেটা দুই কপিতেই আছে। Provider এই সিদ্ধান্ত আপনার হয়ে সামলায়। কিন্তু region পেরোলে replication সাধারণত asynchronous, আর তখন failover মানে কিছু ডেটা হারানোর ঝুঁকি মেনে নেওয়া। তাই অনেক দল cross-region failover ইচ্ছা করেই মানুষের সিদ্ধান্তে রাখে।

বাস্তব নকশায় তাই quorum বা তৃতীয় একটি witness রাখা হয়, যাতে দুই দিকের মধ্যে কে ঠিক, সেটি একজন নিরপেক্ষ পক্ষ বলতে পারে। আর failover-এর পর পুরোনো primary-কে নিশ্চিতভাবে লেখা থেকে সরিয়ে দিতে হয়, যাকে fencing বলে।

মূল উপলব্ধি: Failover নিজেও একটি ঝুঁকিপূর্ণ পরিবর্তন। “কত দ্রুত” নয়, প্রশ্ন হলো “ভুল সংকেতে failover করলে কী হারাবেন, আর না করলে কী হারাবেন?”

প্র ০৩Aurora-ধরনের সেবা compute আর storage আলাদা করল কেন? এতে কী পাওয়া গেল, আর কী হারাল?

সাধারণ MySQL বা PostgreSQL ভাবা হয়েছিল একটি যন্ত্রের একটি disk-এর জন্য। সেখানে প্রতিটি কপি পুরো ডেটা ধারণ করে, আর প্রতিটি লেখায় log আর data page, দুটোই disk-এ যায়। Cloud-এ দেখা গেল বাধা CPU বা storage নয়, network. প্রতিটি কপিতে বড় বড় page পাঠানোই সবচেয়ে বড় খরচ।

২০১৭ সালের SIGMOD পেপারে Amazon দল জানায়, তারা network-এ মূলত redo log পাঠায়, আর storage স্তর নিজেই সেই log থেকে page বানায়। পেপারের একটি পরিচিত কথা, “the log is the database”. কপি থাকে ছয়টি, তিন AZ-এ ছড়িয়ে, আর ছয়ের চারটিতে পৌঁছালেই লেখা নিশ্চিত। Replica-রা একই storage পড়ে বলে নতুন replica বানাতে পুরো ডেটা কপি করতে হয় না, আর lag সাধারণত কম থাকে। Azure SQL Hyperscale আর AlloyDB-ও ভিন্ন ভিন্ন পথে একই দিকে গেছে।

তবে এটি বিনা মূল্যে আসে না। প্রথমত, engine-এর storage স্তর বদলানো মানে আপনি আর হুবহু open-source PostgreSQL চালাচ্ছেন না, তাই সরে যাওয়া কঠিন হতে পারে। দ্বিতীয়ত, ভিন্ন বিলের মডেল, বিশেষ করে I/O-তে, হিসাব উল্টে দিতে পারে। তৃতীয়ত, storage স্তর শেয়ার করা মানে সেটিই একটি বড় blast radius, তাই backup আর আলাদা region-এর কপি তখনো লাগে।

সাধারণ RDS বা Cloud SQL-এর পরিচিত নকশা তাই বাতিল হয়ে যায়নি। ছোট ও মাঝারি workload-এ সেটি সহজ, সস্তা আর অন্য জায়গায় সরানোও সহজ। তাই আগে নিজের চাহিদা মেপে তবেই বেছে নিন।

মূল উপলব্ধি: এই নকশা database-কে “একটি যন্ত্রের সফটওয়্যার” থেকে “একটি বিতরণ করা log সেবা”-তে রূপ দিয়েছে। Bottleneck কোথায় বদলেছে সেটি বুঝলে নকশাও বোঝা যায়।

প্র ০৪Database-এ connection বেশি রাখলে কেন throughput উল্টো কমে যায়? সীমা বাড়িয়ে দিলেই তো হয়?

ধরুন ৮ core-এর একটি database. একই সময়ে আসলে কাজ করতে পারে মোটামুটি ৮টি process. Disk-এর অপেক্ষায় থাকা process বাদে বাকিরা CPU-র জন্য লড়াই করে। প্রতি connection বাড়লে context switch বাড়ে, lock-এর লড়াই বাড়ে, আর memory-র ভাগ কমে। PostgreSQL-এ প্রতিটি connection একটি process, তাই প্রতিটির নিজের memory আছে। আবার অনেক idle connection থাকলে snapshot তৈরির মতো কাজও ধীর হতো, যা PostgreSQL ১৪-এ অনেকটা উন্নত করা হয়।

PostgreSQL wiki আর HikariCP-র “About Pool Sizing” লেখা একটি পরিচিত প্রাথমিক সূত্র দেয়: connection ≈ core × ২ + কার্যকর disk সংখ্যা। এটি নিয়ম নয়, শুরু করার জায়গা মাত্র। ৮ core-এর জন্য এর মানে মোটামুটি ২০-এর ঘরে, কয়েক হাজার নয়। HikariCP-র লেখায় Oracle-এর একটি পরীক্ষার উদাহরণও আছে, যেখানে pool ছোট করায় latency নাটকীয়ভাবে কমে।

লঞ্চঘাটের ছবিতে ফিরি। ৫টি কাউন্টারের সামনে ৫০০ জন গুঁতোগুঁতি করলে কাউন্টারের লোকেরা কাজের চেয়ে ধাক্কা সামলাতেই বেশি সময় দেন। লাইন বাইরে রাখলে, মানে pool বা proxy-তে অপেক্ষা করালে, প্রত্যেকের কাজ দ্রুত শেষ হয়। PgBouncer এই কারণেই জনপ্রিয়, যার শুরু ২০০৭ সালের দিকে Skype-এর প্রকৌশলীদের হাতে।

তাই প্রথম ধাপ সীমা বাড়ানো নয়, বরং কোন connection সত্যিই ব্যস্ত আর কোনটি idle, সেটি pg_stat_activity-তে দেখা। প্রায়ই দেখা যায়, অধিকাংশ connection কিছুই করছে না।

মূল উপলব্ধি: Connection হলো ক্ষমতা নয়, ক্ষমতা ব্যবহারের অনুমতি। সীমা বাড়ালে সমস্যা শুধু পরের ধাপে সরে যায়, তাই অপেক্ষার লাইন database-এর বাইরে রাখাই ভালো নকশা।

প্র ০৫Major version upgrade এত ভয়ের কেন? একে কি সাধারণ patch-এর মতো চালিয়ে দেওয়া যায় না?

PostgreSQL প্রতি বছর একটি major version প্রকাশ করে, আর প্রতিটি সাধারণত প্রায় পাঁচ বছর সংশোধন পায়। Minor version-এ ডেটা ফাইলের গঠন বদলায় না, তাই binary বদলে restart করলেই চলে। Major version-এ system catalog আর কিছু ক্ষেত্রে আচরণ বদলায়। তাই pg_upgrade-এর মতো tool লাগে, অথবা logical replication দিয়ে নতুন cluster ভরতে হয়।

আসল ভয় কিন্তু upgrade-এর বিভ্রাট নয়, পরের সকালের আচরণ। নতুন query planner একই query-র জন্য অন্য plan বেছে নিতে পারে। Upgrade-এর ঠিক পরে statistics না থাকলে planner প্রায় অন্ধ, আর সব query হঠাৎ ধীর হয়ে যেতে পারে। Extension-এর নতুন version লাগতে পারে। পুরোনো driver নতুন authentication-এ আটকে যেতে পারে। আর in-place upgrade-এর পর নতুন লেখা শুরু হলে সহজে ফেরার পথ থাকে না।

এই কারণে managed সেবাগুলো blue-green ধরনের পথ দিচ্ছে। Amazon RDS-এ blue/green deployment এসেছে ২০২২ সালের দিকে। ধারণাটি হলো নতুন version-এর একটি কপি replication দিয়ে সমান রাখা, আসল query দিয়ে পরীক্ষা করা, তারপর অল্প সময়ে switch করা। তবু পুরোনো version-এ বসে থাকাও ঝুঁকি। Community support শেষ হলে provider জোর করে upgrade করতে পারে, অথবা বাড়তি support ফি নিতে পারে, যা provider-ভেদে আলাদা। তাই upgrade-কে দুর্ঘটনা নয়, বছরের নিয়মিত কাজ হিসেবে ধরা ভালো।

Upgrade-এর আগে একটি rollback পরিকল্পনা লিখে রাখাও জরুরি, কারণ চাপের মধ্যে সেটি ভাবার সময় থাকে না।

মূল উপলব্ধি: Managed সেবা upgrade-এর বোতাম দেয়, upgrade-এর পরীক্ষা দেয় না। আপনার query আপনার মতো করে কেবল আপনিই যাচাই করতে পারেন।

অনুশীলন

কোনোটির জন্যই cloud account লাগবে না। সব সংখ্যা ধরে নেওয়া।

  1. Pool-এর হিসাব: max_connections ৬০০, সংরক্ষিত ৩০. Autoscaling-এর max ৩০ instance, আর rolling deployment-এ ২০% surge হয়। প্রতি instance সেকেন্ডে ৮০ অনুরোধ, প্রতি অনুরোধে ৪টি query, প্রতিটি ১৫ ms. সর্বোচ্চ নিরাপদ pool size কত? গড়ে কতটি connection ব্যস্ত? Pool যথেষ্ট কি?

    ব্যবহারযোগ্য slot ৬০০ − ৩০ = ৫৭০. Surge-সহ instance ৩০ × ১.২ = ৩৬. নিরাপদ pool ⌊৫৭০ ÷ ৩৬⌋ = ১৫.

    ব্যস্ত connection = ৮০ × ৪ × ০.০১৫ = ৪.৮. তাই pool ১৫ গড়ের প্রায় ৩ গুণ, যা সাধারণ ওঠানামার জন্য যথেষ্ট। তবে গড় আর শীর্ষ আলাদা, তাই pool-এর অপেক্ষার সময়ও মাপবেন।

  2. ফলাফল অনুমান করুন: orders টেবিলে সকাল ১০:০০-য় ১০০টি সারি, Multi-AZ চালু, একটি read replica-র lag ৩ সেকেন্ড। ক্রমে ঘটল: (ক) ১০:০৫:০০-তে ৪০টি সারি DELETE ও commit, (খ) ১০:০৬:০০-তে primary-র zone বিকল, failover সফল, (গ) ১০:১০:০০-তে ১০:০৪:০০ সময়ে PITR করে নতুন instance. বলুন: ১০:০৫:০১-এ replica কত সারি দেখায়, ১০:০৫:১০-এ কত, failover-এর পর primary-তে কত, আর নতুন instance-এ কত? Live endpoint কি বদলাবে?

    ১০:০৫:০১-এ replica ৩ সেকেন্ড পিছিয়ে, তাই ১০০. ১০:০৫:১০-এ ৬০. Synchronous standby-তে DELETE আগেই পৌঁছেছিল, তাই failover-এর পর primary-তে ৬০, ৪০টি সারি ফেরেনি।

    PITR-এর নতুন instance-এ ১০০. Live endpoint বদলায় না, live-এ ৬০-ই থাকে। নতুন instance-এর endpoint আলাদা, app নিজে থেকে সেখানে যাবে না। Replica সাধারণত নতুন primary-কে অনুসরণ করে, তবে কিছু সেবায় তাকে নতুন করে জুড়তে হতে পারে।

  3. নকশা সমালোচনা: একটি কাল্পনিক দলের পরিকল্পনা: “Single-AZ PostgreSQL, public endpoint খোলা যাতে developer-রা বাসা থেকে ঢুকতে পারেন। একটি read replica আছে, তাই HA ঠিক আছে। Backup retention ১ দিন। ৫০০টি serverless function সরাসরি connect করবে, পরে দরকার হলে সীমা বাড়ানো হবে।” অন্তত পাঁচটি সমস্যা ধরুন, আর প্রতিটির সমাধান বলুন।
    • Public endpoint: বন্ধ করুন। Private subnet, আর bastion বা session manager দিয়ে ঢোকা।
    • Replica-কে HA ভাবা: Replica asynchronous, আর নিজে থেকে দায়িত্ব নেয় না। Multi-AZ standby চালু করুন, failover পরীক্ষা করুন।
    • Single-AZ: Zone বিকল হলে সেবা বন্ধ।
    • Retention ১ দিন: সপ্তাহান্তের ভুল সোমবার ধরা পড়লে ফেরার পথ নেই। Retention বাড়ান, আলাদা account-এ কপি রাখুন, restore পরীক্ষা করুন।
    • Function-এর সরাসরি connection: ভিড়ে storm হবে। Proxy বসান, function-এর concurrency সীমা দিন।
    • “পরে সীমা বাড়ানো”: সীমা বাড়ালে memory আর CPU-র চাপ বাড়ে। আগে হিসাব, তারপর আকার।
  4. Failover আর SLO: মাসিক availability লক্ষ্য ৯৯.৯৫%, ৩০ দিনের মাস। একটি failover-এ ৬০ সেকেন্ড সব লেখা বন্ধ থাকে। মাসে সর্বোচ্চ কয়টি failover সহ্য করা যায়, যদি অন্য কোনো বিভ্রাট না থাকে? প্রতি সেকেন্ডে ১০০ অনুরোধ হলে একটি failover-এ retry ছাড়া কত অনুরোধ ব্যর্থ, আর সেটি মাসের কত শতাংশ?

    ৩০ দিন = ২৫,৯২,০০০ সেকেন্ড। অনুমোদিত বিভ্রাট ০.০৫% = ১,২৯৬ সেকেন্ড (২১.৬ মিনিট)। ১,২৯৬ ÷ ৬০ = ২১.৬, তাই সর্বোচ্চ ২১টি failover.

    একটি failover-এ ১০০ × ৬০ = ৬,০০০ অনুরোধ ব্যর্থ। মাসে মোট ১০০ × ২৫,৯২,০০০ = ২৫,৯২,০০,০০০ অনুরোধ। ৬,০০০ ÷ ২৫,৯২,০০,০০০ ≈ ০.০০২৩%. অর্থাৎ নিয়মিত maintenance-এর একটি failover SLO-তে খুব ছোট দাগ, যদি client ঠিকভাবে ফেরে।

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

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

ক্রমManaged database-এর স্বয়ংক্রিয় failover-এর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Primary-র zone বিকল হয়, চলমান লেখা উত্তর পায় না
  2. Monitor কয়েকটি health check ব্যর্থ দেখে নিশ্চিত হয়
  3. Standby crash recovery শেষ করে primary হয়
  4. Endpoint-এর DNS নতুন IP দেখায়
  5. App পুরোনো connection ফেলে নতুন IP-তে reconnect করে
  6. নতুন standby তৈরি হয়ে পুরো সুরক্ষা ফেরে

Managed database-এ Multi-AZ standby-র প্রধান উদ্দেশ্য কী?

  • পড়ার query-র চাপ ভাগ করা
  • Availability বাড়ানো আর zone বিকল হলে দায়িত্ব নেওয়া
  • ভুল DELETE থেকে ডেটা ফেরানো
  • লেখার গতি বাড়ানো

একটি অ্যাপ সব read এমন replica থেকে করে, যার lag প্রায় ৩ সেকেন্ড। ব্যবহারকারী নাম বদলে সাথে সাথে পাতা খুলে পুরোনো নাম দেখলেন। সবচেয়ে যুক্তিসঙ্গত সমাধান কোনটি?

  • Primary instance বড় করা
  • Backup retention বাড়ানো
  • লেখার পর নিজের পড়া primary-তে পাঠানো, অথবা replica-র অবস্থান মিলিয়ে পড়া
  • Connection pool বড় করা

max_connections ৫০০, সংরক্ষিত ২০. ৩০টি app instance, প্রতিটির pool ২০, আর সবাই চালু হয়েই পুরো pool খোলে। ফল কী হবে?

  • সব connection খুলবে, ৫০০-র কম লাগবে
  • Database নিজে সীমা বাড়িয়ে ৬০০ করবে
  • ঠিক ২০টি connection প্রত্যাখ্যাত হবে
  • প্রায় ১২০টি connection প্রত্যাখ্যাত হবে

Multi-AZ চালু থাকা অবস্থায় WHERE ছাড়া একটি DELETE commit হয়ে গেল। ডেটা ফেরানোর ঠিক পথ কোনটি?

  • ভুলের আগের মুহূর্তে PITR করে নতুন instance থেকে ডেটা ফেরত আনা
  • Standby-তে failover করা
  • Read replica promote করা
  • Instance reboot করা

Failover শেষ, database সুস্থ, অথচ একটি app ৫ মিনিট ধরে timeout পাচ্ছে। Restart করতেই ঠিক হয়ে গেল। সবচেয়ে সম্ভাব্য কারণ কী?

  • Database-এর backup তখনো চলছিল
  • App পুরোনো IP বা মরা connection ধরে রেখেছিল
  • Replica lag বেশি ছিল
  • Storage ভরে গিয়েছিল

PgBouncer-এর transaction pooling চালুর পর কোন আচরণে সমস্যা হওয়ার সম্ভাবনা সবচেয়ে বেশি?

  • সাধারণ SELECT query
  • একটি transaction-এর ভেতরের একাধিক INSERT
  • Session-স্তরের SET, advisory lock আর LISTEN
  • অনেক client-এর একসাথে সংযোগ

শব্দকোষ

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

মনে রাখুন

  1. Managed মানে patch, backup আর failover provider-এর; schema, query, retention, network আর খরচ আপনার।
  2. Standby availability-র জন্য, replica read-এর জন্য। একটি অন্যটির বিকল্প নয়।
  3. Failover-এ এক-দুই মিনিটের ফাঁক ধরে নিন; timeout, retry budget, DNS আর idempotency app-এর দায়।
  4. Replica ভুলও কপি করে। PITR আর পরীক্ষিত restore-ই মানুষের ভুল থেকে ফেরায়।
  5. Instance × pool ≤ ব্যবহারযোগ্য slot, surge-সহ। ভিড়ে proxy আর ধীরে connection খোলা storm থামায়।

পরের পর্বে: সব ডেটা relational table-এ মানায় না। পর্ব ২৩-এ দেখব managed NoSQL, cache আর data warehouse, আর কখন কোনটি বেছে নেবেন।

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

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