KoderKoder.ai
প্রাইসিংএন্টারপ্রাইজএডুকেশনবিনিয়োগকারীদের জন্য
লগ ইনশুরু করুন

প্রোডাক্ট

প্রাইসিংএন্টারপ্রাইজবিনিয়োগকারীদের জন্য

রিসোর্স

আমাদের সাথে যোগাযোগ করুনসহায়তাএডুকেশনব্লগ

লিগ্যাল

প্রাইভেসি পলিসিটার্মস অফ ইউজসিকিউরিটিঅ্যাকসেপ্টেবল ইউজ পলিসিঅ্যাবিউজ রিপোর্ট করুন

সোশ্যাল

LinkedInTwitter
Koder.ai
ভাষা

© 2026 Koder.ai. সর্বস্বত্ব সংরক্ষিত।

হোম›ব্লগ›জিরো-ডাউনটাইম স্কিমা পরিবর্তন: expand/contract প্যাটার্ন
৩১ আগ, ২০২৫·6 মিনিট

জিরো-ডাউনটাইম স্কিমা পরিবর্তন: expand/contract প্যাটার্ন

expand/contract প্যাটার্ন ব্যবহার করে জিরো-ডাউনটাইম স্কিমা পরিবর্তন শিখুন: নিরাপদে কলাম যোগ করুন, ব্যাচে ব্যাকফিল করুন, কম্প্যাটিবল কোড ডিপ্লয় করুন, তারপর পুরনো পাথ মুছুন।

জিরো-ডাউনটাইম স্কিমা পরিবর্তন: expand/contract প্যাটার্ন

কেন স্কিমা পরিবর্তনগুলো আউটেজ দেয়

ডাটাবেস পরিবর্তনের ফলে হওয়া ডাউনটাইম সবসময় স্পষ্ট বা পরিস্কার আউটেজের মতো নয়। ব্যবহারকারীর কাছে এটা হতে পারে এমন যে একটি পেজ অনন্তকাল লোড হচ্ছে, চেকআউট ব্যর্থ হচ্ছে, বা অ্যাপে হঠাৎ "কিছু ভুল হয়েছে" দেখা যাচ্ছে। টিমের দৃষ্টিতে এটা আসে এলার্ট, বাড়তে থাকা এরর রেট, এবং_failed writes_–এর ব্যাকলগ হিসেবে যেগুলো ক্লিনআপ দরকার।

স্কিমা পরিবর্তন ঝুঁকিপূর্ণ কারণ ডাটাবেস আপনার অ্যাপের প্রতিটি চলমান ভার্সনের দ্বারা শেয়ার করা হয়। রিলিজের সময় প্রায়ই পুরনো এবং নতুন কোড একই সময়ে চালিত থাকে (রোলিং ডিপ্লয়, একাধিক ইনস্ট্যান্স, ব্যাকগ্রাউন্ড জব)। একটি মাইগ্রেশন যা দেখতে ঠিক আছে তাও ওই ভার্সনগুলির একটিকে ভঙ্গ করতে পারে।

সামান্য সাধারণ ব্যর্থতার র‍্যাশি হল:

  • নতুন কোড এমন একটি কলামে লিখে যা তখনও নেই, ফলে সাথে সাথেই এরর হয়।
  • পুরনো কোড একটি কলাম বা টেবিল পড়ে যা মাইগ্রেশনটি রিনেম বা ড্রপ করেছে, ফলে ডিপ্লয়ের পরে ক্র্যাশ হয়।
  • একটি ব্যাকফিল বা ইনডেক্স-বিল্ড CPU বাড়ায় বা রোদের উপর লক দেয়, ফলে সাধারণ অনুরোধ ধীর হয়ে যায় বা টাইমআউট হয়ে যায়।
  • একটি "দ্রুত" কনস্ট্রেইন্ট পরিবর্তন (যেমন NOT NULL) টেবিল চেক করার সময় রাইট ব্লক করে।

এমনকি কোড যখন ঠিক থাকে, রিলিজ ব্লক হয়ে যায় কারণ বাস্তব সমস্যা হলো টাইমিং এবং ভার্সনগুলোর মধ্যকার সামঞ্জস্য।

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

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

সহজ ভাষায় expand/contract

ডাটাবেস কাজ থেকে ঘটে যাওয়া অধিকাংশ ইন্সিডেন্ট হয় কারণ অ্যাপ আশা করে ডাটাবেস তাৎক্ষণিকভাবে পরিবর্তিত হবে, কিন্তু ডাটাবেস পরিবর্তন সময় নেয়। expand/contract প্যাটার্ন এই সমস্যাটি ছোট, নিরাপদ ধাপে ভেঙ্গে দেয়।

একটি সংক্ষিপ্ত সময়ের জন্য আপনার সিস্টেম দুই "ডায়ালেক্ট" একসাথে সাপোর্ট করে। আপনি প্রথমে নতুন স্ট্রাকচার পরিচয় করান, পুরনোটা চালু রাখেন, ডেটা ধীরে ধীরে সরান, তারপর পরিশোধন করেন।

প্যাটার্নটি সহজ:

  • Expand: যা দরকার সব যোগ করুন (কলাম, টেবিল, ইনডেক্স) এমনভাবে যাতে বর্তমান অ্যাপ ভাঙে না।
  • Run both paths: এমন কোড ডিপ্লয় করুন যা পুরনো এবং নতুন স্ট্রাকচার দুটোই ব্যাবহার করতে পারে, যাতে মিশ্র ভার্সনগুলোও সঠিকভাবে চলে।
  • Contract: একবার সবকিছু নতুন স্ট্রাকচার ব্যবহার করলে পুরনো স্কিমা ও পুরনো কোড সরান।

এটি রোলিং ডিপ্লয়ের সঙ্গে সুন্দরভাবে কাজ করে। আপনি যদি ১০টি সার্ভার একটার পর একটা আপডেট করেন, তখন সাময়িকভাবে পুরনো ও নতুন ভার্সন একসাথে চলে। expand/contract একই ডাটাবেসে ঐ ওভারল্যাপে উভয়কেই সামঞ্জস্যপূর্ণ রাখে।

এটি রোলব্যাকও কম ভয়ানক করে। যদি নতুন রিলিজে বাগ থাকে, আপনি অ্যাপ রোলব্যাক করতে পারেন ডাটাবেস রোলব্যাক না করেই, কারণ expand উইন্ডো চলাকালীন পুরনো স্ট্রাকচারগুলো এখনও আছে।

উদাহরণ: আপনি PostgreSQL-এ full_name কে first_name এবং last_name-এ ভাগ করতে চান। আপনি প্রথমে নতুন কলামগুলো যোগ করেন (expand), এমন কোড শিপ করেন যা দুই শেপেই পড়তে ও লিখতে পারে, পুরনো রো ব্যাকফিল করেন, তারপর full_name ড্রপ করেন যখন নিশ্চিত হন কিছুই তার উপর নির্ভর করছে না (contract)।

"Expand" সাধারণত কী অন্তর্ভুক্ত করে

Expand ফেজটি নতুন অপশন যোগ করার কথা বলে, পুরনো অপশনগুলি সরানোর নয়।

সাধারণ প্রথম পদক্ষেপ হচ্ছে নতুন কলাম যোগ করা। PostgreSQL-এ সাধারণত এটি nullable এবং কোন ডিফল্ট ছাড়া যোগ করাই নিরাপদ। নন-নাল কলাম ডিফল্ট সহ যোগ করলে টেবিল রিরাইট বা ভারী লক ট্রিগার করতে পারে, যা Postgres ভার্সন এবং পরিবর্তনের উপর নির্ভর করে। নিরাপদ ধাপগুলি হলো: nullable যোগ করা, সহনশীল কোড ডিপ্লয় করা, ব্যাকফিল করা, তারপর পরে NOT NULL বাধ্য করা।

ইনডেক্সও সতর্কতার দাবি রাখে। সাধারণ ইনডেক্স তৈরি করলে আপনি প্রত্যাশার তুলনায় বেশি সময় ধরে রাইট ব্লক হতে পারেন। যতক্ষণ সম্ভব concurrent index creation ব্যবহার করুন যাতে রিড ও রাইট অনেকটুকু চালু থাকে। এটা বেশি সময় নেবে, কিন্তু রিলিজ বন্ধ করে দেওয়া লক এড়াতে সাহায্য করবে।

Expand নতুন টেবিল যোগ করাও হতে পারে। যদি আপনি একক কলাম থেকে many-to-many রিলেশনশিপে যাচ্ছেন, আপনি একটি join টেবিল যোগ করতে পারেন এবং একই সময়ে পুরনো কলাম বজায় রাখতে পারেন। পুরনো পথ কাজ চালিয়ে যাবে যতক্ষণ নতুন স্ট্রাকচার ডেটা সংগ্রহ শুরু করে।

প্র্যাকটিক্যালি expand প্রায়ই অন্তর্ভুক্ত করে:

  • নতুন nullable কলাম বা নতুন টেবিল পুরনোগুলোর পাশে যোগ করা
  • যেখানে সম্ভব non-blocking ভাবে ইনডেক্স যোগ করা
  • ফিচার ফ্ল্যাগ ব্যবহার করে কখন নতুন রিড বা রাইট চালু হবে সেটা নিয়ন্ত্রণ করা
  • প্রয়োজন হলে পুরনো ও নতুন ফিল্ড দুটোতেই লেখা (dual-write)
  • রিডগুলো ব্যাকওয়ার্ড-কম্প্যাটিবল রাখা (পুরানো, নতুন, বা fallback)

Expand শেষ হলে পুরনো এবং নতুন অ্যাপ ভার্সনগুলো অনায়াসে একসাথে চলতে সক্ষম হওয়া উচিত।

এমন কোড ডিপ্লয় করা যা সামঞ্জস্য রাখে

অধিকাংশ রিলিজের ব্যথা মাঝখানে ঘটে: কিছু সার্ভার নতুন কোড চলছে, কিছু এখনও পুরনো কোডে, যখন ডাটাবেস ইতিমধ্যেই পরিবর্তনশীল। আপনার লক্ষ্য সরল: রোলআউটের যেকোনো ভার্সনই পুরনো এবং বিস্তৃত—উভয়—স্কিমার সাথে কাজ করবে।

একটি সাধারণ পদ্ধতি হলো dual-write। যদি আপনি একটি নতুন কলাম যোগ করেন, নতুন অ্যাপ উভয়—পুরনো ও নতুন—কলামে লেখে। পুরনো অ্যাপগুলো কেবল পুরনো কলামে লেখাই করবে, যেটা ঠিক আছে কারণ তা এখনও আছে। প্রথমে নতুন কলাম optional রাখুন, এবং কঠোর কনস্ট্রেইন্ট পরে চালু করুন যতক্ষণ না সব লেখক আপগ্রেড হয়।

রিড সাধারণত রাইটের চেয়ে সাবধানে স্যুইচ করা হয়। প্রথমেই পুরনো কলামে রিড রাখতে পারেন (যেটা আপনি জানেন পুরোপুরি ভরা আছে)। ব্যাকফিল ও যাচাইয়ের পরে রিডগুলো নতুন কলামকে প্রাধান্য দেবে, এবং নতুনটি না থাকলে পুরনোতে fallback করবে।

ডাটাবেসের নিচে থাকা অবস্থায়ও আপনার API আউটপুট স্থিতিশীল রাখুন। এমনকি আপনি একটি নতুন অভ্যন্তরীণ ফিল্ড পরিচয় করালেও, সমস্ত কনজিউমার প্রস্তুত না হওয়া পর্যন্ত response shape পরিবর্তন এড়ান (ওয়েব, মোবাইল, ইন্টিগ্রেশন)।

রোলব্যাক-ফ্রেন্ডলি রোলআউট প্রায়শই এমন:

  • Release 1: নতুন কলাম যোগ করা এবং এমন কোড শিপ করা যা পুরনো ডেটা পড়তে পারে এবং উভয় কলামে লিখে।
  • Release 2: বিদ্যমান রো ব্যাকফিল করা, তারপর এমন কোড শিপ করা যা নতুন কলাম প্রাধান্য দেয় কিন্তু fallback রাখতে পারে।
  • Release 3: পুরনো কলামে লেখা বন্ধ করা (তবে এটি রাখুন)।
  • Release 4: পুরনো রিড remove করা, তারপর পুরনো কলাম ড্রপ করা।

মূল ধারণা হলো প্রথম অপ্রত্যাহার যোগটি হচ্ছে পুরনো স্ট্রাকচারগুলো ড্রপ করা, তাই আপনি এটিকে শেষে পর্যন্ত বিলম্ব করেন।

ব্যাকফিল নিরাপদে করা (ডিবি ওভারলোড না করে)

Ship code that stays compatible
Generate a React plus Go app and keep migrations aligned with your rollout steps.
Create Project

ব্যাকফিল হচ্ছে যেখানে অনেক "জিরো-ডাউনটাইম" স্কিমা পরিবর্তন ভুল হয়ে যায়। আপনি নতুন কলাম পুরনো রো গুলো ভরতে চান লম্বা লক, ধীর কুয়েরি বা আকস্মিক লোড স্পাইক ছাড়া।

ব্যাচিং গুরুত্বপূর্ণ। এমন ব্যাচ লক্ষ্য করুন যা দ্রুত শেষ হবে (সেকেন্ডসে, মিনিটে নয়)। যদি প্রতিটি ব্যাচ ছোট হয়, আপনি জব থামাতে, পুনরায় শুরু করতে এবং টিউন করতে পারবেন রিলিজ ব্লক করা ছাড়াই।

প্রগতি ট্র্যাক করতে স্থিতিশীল কুর্সর ব্যবহার করুন। PostgreSQL-এ সেটি প্রায়শই প্রাইমারি কী। আইডিতে অর্ডারে প্রক্রিয়া করুন এবং শেষ যে id আপনি সম্পন্ন করেছেন তা সংরক্ষণ করুন, অথবা id রেঞ্জে কাজ করুন। এটা জব রিস্টার্ট হলে ব্যয়বহুল ফুল-টেবিল স্ক্যান এড়ায়।

এখানে একটি সহজ প্যাটার্ন:

UPDATE my_table
SET new_col = ...
WHERE new_col IS NULL
  AND id > $last_id
ORDER BY id
LIMIT 1000;

আপডেট কন্ডিশনাল রাখুন (উদাহরণস্বরূপ, WHERE new_col IS NULL) যাতে জব idempotent হয়। রিরান শুধু সেই রো গুলো টাচ করে যেগুলো এখনও কাজের প্রয়োজন, যা অপ্রয়োজনীয় রাইট কমায়।

ব্যাকফিল চলাকালীন নতুন ডেটা আসার পরিকল্পনা করুন। সাধারণ আদেশ হচ্ছে:

  • প্রথমে অ্যাপ কোড আপডেট করুন যাতে নতুন রাইটগুলোও নতুন ফিল্ড ভরায়।
  • ইতিহাসে থাকা রো গুলো ব্যাচে ব্যাচে ব্যাকফিল করুন।
  • সাম্প্রতিক রো গুলোর জন্য একটি দ্রুত catch-up লুপ চালান।
  • প্রয়োজনে একটি গার্ডরেল (যেমন ট্রিগার বা ডিফল্ট) যোগ করুন যাতে নতুন NULL এড়ানো যায়।

ভাল একটি ব্যাকফিল ক্লান্তিকর: স্থির, মাপযোগ্য, এবং ডাটাবেস গরম হলে সহজে থামানো যায়।

নিশ্চিত করা যে মাইগ্রেশন באמת সম্পন্ন

সবচেয়ে ঝুঁকিপূর্ণ মুহূর্তটি নতুন কলাম যোগ করা নয়। এটা সিদ্ধান্ত নেওয়া যে আপনি এখন এটিতে নির্ভর করতে পারবেন।

Contract-এ যাওয়ার আগে দুটি বিষয় প্রমাণ করুন: নতুন ডেটা সম্পূর্ণ, এবং প্রোডাকশন এটিকে নিরাপদে পড়ছে।

শুরুতে দ্রুত ও পুনরায় চালনাযোগ্য সম্পূর্ণতা চেকগুলো চালান:

  • নিশ্চিত করুন নতুন কলামে অপ্রত্যাশিত NULL নেই।
  • যাচাই করুন কত রো উপযুক্ত ছিল বনাম কতটা ভরা হয়েছে।
  • কিছু ID-এ স্পট-চেক করে পুরনো বনাম নতুন মান তুলনা করুন।
  • এজ কেস টেস্ট করুন (খালি স্ট্রিং, শূন্য, খুব পুরনো রেকর্ড)।
  • পরবর্তীতে আবার একই চেক চালান যাতে নিশ্চিত হওয়া যায় কিছু drift হয়নি।

আপনি যদি dual-writing করে থাকেন, একটি consistency চেক যোগ করুন যাতে নিঃশব্দ বাগ ধরা যায়। উদাহরণস্বরূপ, প্রতি ঘণ্টায় এমন একটি কুয়েরি চালান যা old_value <> new_value দেখায় এবং যদি ফলাফল শূন্য না হয় তবে এলার্ট করুন। এটি প্রায়ই দ্রুততম উপায় যে কোনো লেখক এখনও কেবল পুরনো কলাম আপডেট করছে কিনা খুঁজে বের করার।

মাইগ্রেশন চলাকালীন প্রোডাকশন সিগন্যাল নজর করুন। যদি কুয়েরি টাইম বা লক ওয়েট spike করে, এমনকি আপনার "নিরাপদ" যাচাই কুয়েরি গুলোই লোড বাড়াচ্ছে হতে পারে। ডিপ্লয়ের ঠিক পরে নতুন কলাম পড়া পথগুলোর জন্য এরর রেট দেখুন।

কতক্ষণ দুটো পথ রাখা উচিত? অন্তত এক পূর্ণ রিলিজ সাইকেল এবং এক ব্যাকফিল রিরান টিকে বাঁচানোর মতো সময়। অনেক দল ১–২ সপ্তাহ রাখে, অথবা যতক্ষণ না তারা নিশ্চিত হয় কোন পুরনো অ্যাপ ভার্সন আর চলছে না।

Contract ফেজ: পুরনো পথ সরানো

Contract হল সেই জায়গা যেখানে টিমরা নার্ভাস হয় কারণ এটা প্রতীয়মান হয়ে যায় ফিরে যাওয়ার পথ নেই। যদি expand ঠিকমতো করা হয়, contract বেশিরভাগই ক্লিনআপ এবং আপনি এটিকে ছোট, নিম্ন-ঝুঁকির ধাপে করতে পারবেন।

মুহূর্তটি সাবধানে বেছে নিন। ব্যাকফিল শেষ হবার ঠিক পরে কিছুই ড্রপ করবেন না। অন্তত একটি পূর্ণ রিলিজ সাইকেল দিন যাতে বিলম্বী জব ও এজ কেসগুলো নিজকে প্রদর্শন করতে পারে।

নিরাপদ contract সিকোয়েন্স সাধারণত এমন:

  • dual-write বন্ধ করুন এবং নিশ্চিত করুন নতুন লেখাগুলো কেবল নতুন কলামে যাচ্ছে।
  • অ্যাপ থেকে পুরনো রিড সরান যাতে fallback চলে যায়।
  • পুরনো স্কিমা রেফারেন্স করে এমন ডেড কোড, ফিচার ফ্ল্যাগ এবং ব্যাকগ্রাউন্ড জব মুছুন।
  • অস্থায়ী ট্রিগার, সিঙ্ক জব বা কম্প্যাটিবিলিটি ভিউ মুছুন।
  • পুরনো ইনডেক্স এবং কনস্ট্রেইন্ট মুছুন, তারপর পুরনো কলাম ড্রপ করুন।

যদি পারেন, contract কে দুই রিলিজে বিভক্ত করুন: একটি যা কোড রেফারেন্স মুছে ফেলে (অতিরিক্ত লগিং সহ), এবং পরে একটি যা ডাটাবেস অবজেক্ট সরায়। এই বিভাজন রোলব্যাক ও ট্রাবলশুটিংকে অনেক সহজ করে।

PostgreSQL-এ এখানে বিশেষ বিষয় রয়েছে। কলাম ড্রপ করা বেশিরভাগই মেটাডাটা পরিবর্তন, কিন্তু এটি সামান্য ACCESS EXCLUSIVE লক নেয়। একটি শান্ত উইন্ডোর পরিকল্পনা করুন এবং মাইগ্রেশন দ্রুত রাখুন। যদি আপনি অতিরিক্ত ইনডেক্স তৈরি করে থাকেন, সেগুলো DROP INDEX CONCURRENTLY দিয়ে মুছতে পছন্দ করুন যাতে রাইট ব্লক না হয় (এটি ট্রান্স্যাকশন ব্লকে চালানো যায় না, তাই আপনার মাইগ্রেশন টুলিং-এ সাপোর্ট থাকতে হবে)।

সাধারণ ভুল এবং ফাঁদ

Plan safer schema changes
Turn your expand-contract plan into concrete tasks and checkpoints before you touch production.
Start Free

জিরো-ডাউনটাইম মাইগ্রেশন ব্যর্থ হয় যখন ডাটাবেস এবং অ্যাপ কি অনুমোদিত/অনুমোদিত সে ব্যাপারে একমত না থাকে। প্যাটার্নটি কাজ করে কেবল যদি প্রতিটি মধ্যবর্তী অবস্থা পুরনো কোড ও নতুন কোড—উভয়ের জন্য নিরাপদ হয়।

এমন ফাঁদগুলো যা প্রোডাকশন ভেঙে দেয়

এই ভুলগুলো প্রায়ই দেখা যায়:

  • পুরনো অ্যাপ ভার্সন এখনও নতুন ফিল্ড ছাড়া রো লিখতে পারলে খুব তাড়াতাড়ি NOT NULL যোগ করা।
  • একটি বিশাল টেবিল এক ট্রানজাকশনে ব্যাকফিল করা, যা লক ধরে রাখে, টেবিল ব্লোট করে এবং টাইমআউট ঘটায়।
  • ডিফল্টকে বিনামূল্যে ধরা; PostgreSQL-এ কিছু ডিফল্ট টেবিল রিরাইট ট্রিগার করে।
  • রাইটসভরূপে নির্ভরযোগ্যভাবে populate না হওয়া পর্যন্ত রিডগুলো নতুন কলামে স্যুইচ করা।
  • অন্যান্য লেখক/পাঠকের কথা ভুলে যাওয়া (ক্রন জব, ওয়ার্কার, এক্সপোর্ট, রিপোর্টিং কুয়েরি)।

একটি বাস্তবসম্মত দৃশ্য: আপনি API থেকে full_name লিখে দিতে শুরু করেছেন, কিন্তু একটি ব্যাকগ্রাউন্ড জব এখনও কেবল first_name এবং last_name সেট করে। এটি রাতে চলে, এমন রো ইনসার্ট করে যার full_name = NULL, এবং পরে কোড ধরে নেয় full_name সবসময় আছে।

কিভাবে মাঝখানে আটকে যাওয়া এড়াবেন

প্রতিটি ধাপকে এমনভাবে দেখুন যেন এটি দিনগুলো চলতে পারে এমন একটি রিলিজ:

  • ট্রানজিশনের সময় নতুন কলাম nullable রাখুন, এবং প্রথমে কোডে required enforce করুন।
  • ছোট ব্যাচে ব্যাকফিল করুন, বিরতি-সহ, এবং DB লোড মনিটর করুন।
  • কোডকে সহনশীল রাখুন: দুই পথই পড়ুন, প্রয়োজন হলে দুই পথে লিখুন, অনুপস্থিত মান খেয়াল করুন।
  • টেবিল টাচ করে এমন প্রতিটি স্থানের অডিট করুন, ওয়ার্কার ও রিপোর্টিং সহ।

প্রতিটি রিলিজের আগে দ্রুত চেকলিস্ট

একটি পুনরাবৃত্ত চেকলিস্ট আপনাকে এমন কোড শিপ করা থেকে রোধ করে যা কেবল এক ডাটাবেস স্টেটেই কাজ করে।

ডিপ্লয়ের আগে নিশ্চিত করুন ডাটাবেস ইতিমধ্যেই expanded অংশগুলো আছে (নতুন কলাম/টেবিল, ইনডেক্স যা low-lock ভাবে তৈরি করা হয়েছে)। তারপর নিশ্চিত করুন অ্যাপ সহনশীল: এটি পুরনো শেপ, বিস্তৃত শেপ এবং হাফ-ব্যাকফিল অবস্থায় কাজ করবে।

চেকলিস্ট সংক্ষিপ্ত রাখুন:

  • Expansion আছে: নতুন স্কিমা অবজেক্টগুলো আছে এবং low-lock ভাবে যোগ করা হয়েছে।
  • কম্প্যাটিবিলিটি বাস্তব: অ্যাপ পুরনো ও বিস্তৃত স্কিমা—উভয়ের সাথেই চলে, ওয়ার্কার এবং অ্যাডমিন পাথ সহ।
  • ব্যাকফিল নিয়ন্ত্রিত: ছোট ব্যাচ, paus-able, প্রাথমিক প্রগতি মেট্রিকস সহ।
  • রিড সুইচ পরিকল্পিত: কবে রিড স্যুইচ করবেন ও ফল খারাপ হলে কিভাবে রোলব্যাক করবেন সেটা জানেন।
  • কন্ট্রাক্ট বিলম্বিত: পুরনো অবজেক্ট ড্রপ করার আগ পর্যন্ত অন্তত এক বা দুই রিলিজ সাইকেল অপেক্ষা করুন।

একটি মাইগ্রেশন তখনই শেষ হয়েছে যখন রিডগুলো নতুন ডেটা ব্যবহার করছে, রাইটগুলো আর পুরনো ডেটা রাখছে না, এবং আপনি ব্যাকফিলটি অন্তত একটি সাধারণ চেক (কাউন্ট বা স্যাম্পলিং) দিয়ে যাচাই করেছেন।

বাস্তবসম্মত উদাহরণ: একটি কলাম বদলে ফেলুন ডাউনটাইম ছাড়া

Use Planning Mode for migrations
Map releases, backfills, and verification queries in Koder.ai Planning Mode.
Try Planning

ধরা যাক আপনার PostgreSQL customers টেবিলে একটি phone কলাম আছে যা বিশৃঙ্খল মান রাখে। আপনি এটিকে phone_e164 দিয়ে প্রতিস্থাপন করতে চান, কিন্তু আপনি রিলিজ ব্লক করতে বা অ্যাপ বন্ধ করতে পারবেন না।

একটি পরিষ্কার expand/contract সিকোয়েন্স এমন দেখায়:

  • Expand: phone_e164 nullable হিসেবে যোগ করুন, কোন ডিফল্ট ছাড়াই, এবং কঠোর কনস্ট্রেইন্ট পরে যোগ করবেন না।
  • Compatible deploy: কোড আপডেট করুন যাতে দুটোতেই phone এবং phone_e164-এ লেখা হয়, কিন্তু রিডগুলো phone-এ রাখুন যাতে ব্যবহারকারীর জন্য কিছুই পরিবর্তন না হয়।
  • Backfill: বিদ্যমান রো ছোট ব্যাচে রূপান্তর করুন (উদাহরণ স্বরূপ, একবারে 1,000)।
  • Switch reads: কোড ডিপ্লয় করুন যা প্রথমে phone_e164 পড়ে, এবং যদি তা NULL থাকে তবে phone-এ fallback করে।
  • Contract: একবার নিশ্চিত হল সবকিছু phone_e164 ব্যবহার করছে, fallback সরান, phone ড্রপ করুন, তারপর প্রয়োজন হলে কঠোর কনস্ট্রেইন্ট যোগ করুন।

প্রত্যেক ধাপ পিছনে-কম্প্যাটিবল হলে রোলব্যাক সহজ থাকে। যদি রিড স্যুইচ সমস্যা করে, অ্যাপ রোলব্যাক করুন — ডাটাবেসে উভয় কলামই থাকবে। যদি ব্যাকফিল লোড spike করে, জব থামান, ব্যাচ সাইজ কমান এবং পরে চালিয়ে দিন।

টিমের সঙ্গতি রাখার জন্য পরিকল্পনাটি এক জায়গায় ডকুমেন্ট করুন: সঠিক SQL, কোন রিলিজে রিড ফ্লিপ হবে, সম্পন্নতা কীভাবে পরিমাপ করবেন (যেমন phone_e164 এর non-NULL শতাংশ), এবং প্রত্যেক স্টেপের মালিক কে।

পরবর্তী ধাপ: এটিকে পুনরাবৃত্তযোগ্য করুন

Expand/contract তখনই সেরা কাজ করে যখন এটি রুটিনের মতো লাগে। একটি সংক্ষিপ্ত রুনবুক লিখুন যা আপনার টিম প্রতিটি স্কিমা পরিবর্তনের জন্য পুনঃব্যবহার করতে পারে, সম্ভব হলে এক পৃষ্ঠার মত এবং যথেষ্ট নির্দিষ্ট যাতে একটি নতুন সহকর্মী অনুসরণ করতে পারে।

একটি ব্যবহারিক টেমপ্লেট অন্তর্ভুক্ত করবে:

  • Expand (নির্দিষ্ট মাইগ্রেশন)
  • কোড পরিবর্তন (কোথায় ব্যাকওয়ার্ড কম্প্যাটিবিলিটি রাখতে হবে, কোথায় dual-read/dual-write ব্যবহার হবে)
  • Backfill (ব্যাচ সাইজ, রেট লিমিট, pause/resume)
  • Verify (যে কুয়েরি ও মেট্রিকস সঠিকতা প্রমাণ করবে)
  • Contract (কি কবে সরানো হবে)

আগে থেকেই মালিকানা ঠিক করুন। "প্রত্যেকে ভাবছিল কেউ অন্য কেউ contract করবে"—এই ভাবেই পুরনো কলাম ও ফিচার ফ্ল্যাগ মাস দু’মাস টিকে যায়।

এven যদি ব্যাকফিল অনলাইন চলে, ট্রাফিক কম থাকা সময়টা বেছে নিন। ব্যাচ ছোট রাখা, DB লোড নজর রাখা এবং ল্যাটেন্সি বেড়ে গেলে দ্রুত বন্ধ করা সহজ হয়।

আপনি যদি Koder.ai (koder.ai) দিয়ে বিল্ড ও ডিপ্লয় করে থাকেন, Planning Mode আপনার ফেজ ও চেকপয়েন্ট ম্যাপ করতে উপকারী হতে পারে। একই সামঞ্জস্য নিয়ম প্রযোজ্য, কিন্তু ধাপগুলো লিখে রাখা আপনাকে সেই বোরিং কিন্তু জরুরি কাজগুলো বাদ না দিতে সাহায্য করবে।

সাধারণ প্রশ্ন

Why do schema changes cause outages even when the SQL looks correct?

কারণ আপনার ডাটাবেস আপনার অ্যাপের সব চলমান ভার্সন দ্বারা শেয়ার করা হয়। রোলিং ডিপ্লয় এবং ব্যাকগ্রাউন্ড জব চলাকালে পুরনো এবং নতুন কোড একসাথে হতে পারে, এবং যেকোনো মাইগ্রেশন যা নাম পরিবর্তন করে, কলাম বাদ দেয় বা কনস্ট্রেইন্ট যোগ করে তা সেই নির্দিষ্ট স্কিমা স্টেটে না থাকা কোনো ভার্সনকে ভেঙে দিতে পারে।

What does “zero-downtime schema change” really mean?

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

What’s the difference between the expand and contract phases?

Expand ফেজে আপনি নতুন কলাম, টেবিল বা ইনডেক্স যোগ করেন যাতে বর্তমান অ্যাপের কোনো দরকারী অংশ মুছে না যায়। Contract হচ্ছে ক্লিনআপ ফেজ যেখানে নতুন পথ পুরোপুরি কাজ করার প্রমাণ পেলে পুরনো কলাম, পুরনো রিড/রাইট এবং অস্থায়ী সিঙ্ক লজিক মুছে ফেলা হয়।

What’s the safest way to add a new column in PostgreSQL?

শুরুতে nullable ও কোন ডিফল্ট ছাড়া কলাম যোগ করা সাধারণত সবচেয়ে নিরাপদ, কারণ এটি ভারী লক বা টেবিল রিরাইট এড়ায় এবং পুরনো কোড কাজ চালাতে পারে। পরে কোড ডিপ্লয় করে কলাম অনুপস্থিত বা NULL থাকলে তা সামলাতে হবে, ব্যাকফিল ধীরে ধীরে করা হবে, এবং পরে NOT NULL-এর মতো কনস্ট্রেইন্ট কড়া করা হবে।

When should I use dual-write, and what does it do?

যখন ট্রানজিশনে নতুন অ্যাপ ভার্সন একইসঙ্গে পুরনো ইনস্ট্যান্স চলতে পারে, তখন নতুন ভার্সন পুরনো ফিল্ড এবং নতুন ফিল্ড—দুটোতেও লেখে। এতে ডেটা কনসিস্টেন্ট থাকে যতক্ষণ না সব লেখক আপগ্রেড হয়।

How do I backfill data without slowing down production?

ছোট ব্যাচে ব্যাকফিল করুন যাতে প্রতিটি ব্যাচ দ্রুত শেষ হয়, এবং প্রতিটি ব্যাচ idempotent রাখুন যাতে পুনরায় চালালে শুধুমাত্র এখনও কাজ করা rows-গুলোই আপডেট হয়। কুয়েরি টাইম, লক ওয়েট এবং রিপ্লিকেশন ল্যাগ দেখুন এবং ডাটাবেস গরম হলে জব থামাতে বা ব্যাচ সাইজ কমাতে প্রস্তুত থাকুন।

How can I verify the migration is actually done before dropping anything?

প্রথমত, নতুন কলামে কয়টি NULL আছে তা চেক করে সম্পূর্ণতার প্রমাণ পান। তারপর নমুনা বা কস্ট-সস্তা কনসিস্টেন্সি চেক চালান যা পুরানো ও নতুন মান মিলছে কিনা দেখায়। ডিপ্লয়ের ঠিক পরে প্রোডাকশন এরর দেখুন যাতে কোন কোড-পাথ ভুল স্কিমা ব্যবহার করছে কিনা ধরা যায়।

What are the most common migration steps that break production?

NOT NULL বা নতুন কনস্ট্রেইন্ট খুব তাড়াতাড়ি যোগ করা, বড় টেবিল এক ট্রানজাকশনে ব্যাকফিল করা, ডিফল্টকে বিনামূল্যে ধরে নেওয়া (কিছু ডিফল্ট table rewrite ট্রিগার করে), এবং রিডগুলো নতুন কলামে স্যুইচ করা আগে যখন রাইটস এখনও ভর্তি করছে না—এইগুলো সাধারণ ভুল।

When is it safe to do the contract step and drop the old column?

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

Do I always need expand/contract, or can I just take a maintenance window?

যদি আপনি একটি রক্ষণাবেক্ষণের উইন্ডো সহ মাইগ্রেশন মেনে নিতে পারেন এবং ট্রাফিক কম থাকে তবে এক-চোখে মাইগ্রেশনও ঠিক আছে। কিন্তু যদি বাস্তব ব্যবহারকারী, বহু অ্যাপ ইনস্ট্যান্স, ব্যাকগ্রাউন্ড ওয়ার্কার বা SLA থাকে, তাহলে expand/contract সাধারণত অতিরিক্ত ধাপগুলোর মূল্য রাখে। Koder.ai Planning Mode-এ ধাপগুলো আগে থেকে লিখে রাখা আপনাকে ‘বোরিং’ ধাপগুলো বাদ না দিতে সাহায্য করবে।

সূচিপত্র
কেন স্কিমা পরিবর্তনগুলো আউটেজ দেয়সহজ ভাষায় expand/contract"Expand" সাধারণত কী অন্তর্ভুক্ত করেএমন কোড ডিপ্লয় করা যা সামঞ্জস্য রাখেব্যাকফিল নিরাপদে করা (ডিবি ওভারলোড না করে)নিশ্চিত করা যে মাইগ্রেশন באמת সম্পন্নContract ফেজ: পুরনো পথ সরানোসাধারণ ভুল এবং ফাঁদপ্রতিটি রিলিজের আগে দ্রুত চেকলিস্টবাস্তবসম্মত উদাহরণ: একটি কলাম বদলে ফেলুন ডাউনটাইম ছাড়াপরবর্তী ধাপ: এটিকে পুনরাবৃত্তযোগ্য করুনসাধারণ প্রশ্ন
শেয়ার
Koder.ai
Koder দিয়ে আপনার নিজের অ্যাপ তৈরি করুন আজই!

Koder-এর শক্তি বুঝতে সবচেয়ে ভালো উপায় হলো নিজে দেখা।

বিনামূল্যে শুরু করুনডেমো বুক করুন