মাল্টি-রিজিয়নে উপলব্ধতার জন্য PostgreSQL বনাম CockroachDB
PostgreSQL বনাম CockroachDB: নিশ্চিততা, ল্যাটেন্সি, স্কিমা পরিবর্তন ও আগেভাগে মাল্টি-রিজিয়নে যাওয়ার বাস্তব অপারেশনাল খরচ—একটি ব্যবহারিক তুলনা।

আপনি আসলে কোন সমস্যাটির সমাধান খুঁজছেন?
“মাল্টি-রিজিয়ন উপলব্ধতা” বিভিন্ন উদ্দেশ্য বোঝাতে ব্যবহৃত হয়। এই উদ্দেশ্যগুলো মিশে গেলে টিমগুলো ভুল ডাটাবেস বেছে নেয়।
PostgreSQL ও CockroachDB তুলনার আগে লিখে রাখুন (1) আপনি কোন সুনির্দিষ্ট ব্যর্থতা থেকে বেঁচে থাকতে চান এবং (2) সেই ব্যর্থতার সময় ব্যবহারকারীরা কী অভিজ্ঞতা পাবে।
অধিকাংশ টিম কিছু মিশ্র লক্ষ্যই তাড়া করে:
- একটি রিজিয়ন ডাউন হলে উচ্চতর আপটাইম (ফেইলওভার)
- প্রধান রিজিয়ন থেকে দূরে থাকা ব্যবহারকারীদের জন্য দ্রুত প্রতিক্রিয়া (কম ল্যাটেন্সি)
- ভৌগোলোিক নিয়মের কারণে ডেটার অঞ্চলভিত্তিক নিয়ন্ত্রণ (locality বা residency)
- শুধু ‘হ্যাপি-পাথ’ টেস্ট নয়, লোডের অধীনে পূর্বানুমেয় আচরণ
অবশ্যই লক্ষ্যটি সরল: অন্য মহাদেশে থাকা একজন কাস্টমারও দ্রুত এবং সঠিক ফল পাবে।
কঠিনো হচ্ছে “দ্রুত” এবং “সঠিক” একসাথে বজায় রাখা যখন আপনি লেখাগুলো বিভিন্ন রিজিয়নে ছড়ান। শক্ত কনসিস্টেন্সি সাধারণত বেশি ক্রস-রিজিয়ন সমন্বয় দাবি করে, এবং সেটাই ল্যাটেন্সি বাড়ায়। ল্যাটেন্সি কমাতে কাছের কপি থেকে পড়া বা অ্যাসিঙ্ক্রোনাস রেপ্লিকেশন ব্যবহার করলে স্টেল রিড বা কনফ্লিক্ট হ্যান্ডলিং আপনার দায় হবে।
একটি বাস্তব উদাহরণ: জার্মানিতে একজন ব্যবহারকারী শিপিং ঠিকানা আপডেট করে এবং সঙ্গে সঙ্গেই চেকআউট করে। যদি চেকআউট US রেপ্লিকা থেকে পড়ে এবং সেটা কয়েক সেকেন্ড পিছিয়ে থাকে, তাহলে অর্ডার পুরনো ঠিকানাই ব্যবহার করতে পারে। কিছু প্রোডাক্ট স্পষ্ট UX ও রিট্রাই দিয়ে তা সহ্য করতে পারে। অন্যদের (পেমেন্ট, ইনভেন্টরি, কমপ্লায়েন্স) এটা সহ্যযোগ্য নয়।
সর্বজনীন সেরা পছন্দ নেই। সঠিক উত্তর নির্ভর করে কী কখনো ভুল হতে পারে না, কী একটু ধীর হতে পারে এবং আপনার টিম প্রতিদিন কতটা অপারেশনাল জটিলতা সামলাতে পারে।
“একাধিক রিজিয়নে উপলব্ধ” এর দুটি দৃষ্টিভঙ্গি
PostgreSQL বনাম CockroachDB তুলনার সময় মানুষ প্রায়ই দুইটি ভিন্ন ডিজাইন তুলনা করে।
PostgreSQL-এ সবচেয়ে সাধারণ সেটআপ হলো single-primary। একটি রিজিয়ন হল ‘হোম’ যেখানে লেখাগুলি ঘটে। অন্য রিজিয়নে read replica থাকে যা প্রাইমারির পরিবর্তনগুলো কপি করে। যদি প্রাইমারি রিজিয়ন ব্যর্থ হয়, আপনি অন্যত্র একটি রিপ্লিকাকে প্রোমোট করে অ্যাপকে সেখানে নির্দেশ দেন। ভালোভাবে করলে এটি ভালভাবে কাজ করে, তবে সিস্টেমটি এখনও একটিই প্রধান লেখার অবস্থানে কেন্দ্রীভূত এবং একটি পরিকল্পিত ফেইলওভার প্ল্যান থাকে।
CockroachDB-এর মতো distributed SQL সিস্টেমগুলোর ক্ষেত্রে ডাটাবেসটা প্রথম থেকেই রিজিয়নগুলোর ওপর ডেটা ও দায়িত্ব ছড়িয়ে দেয়ার মতো ডিজাইন করা। ডেটা একাধিক নোডে কপি হয় এবং ক্লাস্টার লেখাগুলোর অর্ডারে একমত হয়। আপনি নির্দিষ্ট ডেটা ব্যবহারকারীর কাছে নিকট স্থাপন করতে পারেন যখন এক যৌক্তিক ডাটাবেস বজায় থাকে।
অ্যাপ টিমের জন্য পরিবর্তনটি SQL সিনট্যাক্সের চেয়ে প্রত্যাশার দিকে বেশি:
- Writes: PostgreSQL লেখাগুলো প্রাইমারির কাছাকাছি দ্রুত। CockroachDB-তে লেখাগুলো প্রায়ই একাধিক রেপ্লিকার সম্মতিও প্রয়োজন, যা ক্রস-রিজিয়ন নিশ্চিতকরণও অন্তর্ভুক্ত করতে পারে।
- Reads: PostgreSQL লোকাল রেপ্লিকা থেকে রিড সার্ভ করতে পারে (স্টেলনেস ট্রেডঅফ দিয়ে)। CockroachDB কনসিস্টেন্ট রিড দিতে পারে, তবে ডেটা কোথায় রাখা আছে তার ওপর নির্ভর করে সমন্বয় খরচ দিতে হতে পারে।
- Failures: PostgreSQL ফেইলওভার হলো একটি সুইচ যা আপনি ট্রিগার ও ম্যানেজ করেন। CockroachDB কিছু রিজিয়ন ব্যর্থতা সহ্য করার জন্য তৈরি, কিন্তু সেটি তার রেপ্লিকেশন ও কোয়োরাম নিয়মের মধ্যে সীমাবদ্ধ।
গোপন চাহিদা হলো ব্যর্থতার সময় সঠিকতা। যদি আপনি স্বল্প সময়ের স্টেল রিড বা ফেইলওভারের সময় ছোট লেখার বিরতি সহ্য করতে পারেন, single-primary PostgreSQL ভালো ফিট হতে পারে। যদি রিজিয়ন ডাউন থাকাকালীন সিস্টেমটি সঠিক ও লিখনযোগ্য থাকতে হবে, তাহলে আপনি একটি বিতরণকৃত ডাটাবেসের সমন্বয় খরচ মেনে নিচ্ছেন।
কনসিস্টেন্সি গ্যারান্টি: আপনি কীতে নির্ভর করতে পারেন
সহজ কথায় কনসিস্টেন্সি: কেউ যখন রেকর্ড আপডেট করে, তখন অন্য সবাই একই সত্য দেখতে পাওয়া দরকার।
PostgreSQL-এ শক্ত কনসিস্টেন্সি সবচেয়ে সহজ হয় যখন আপনার অ্যাপ একটিই প্রাইমারির সাথে কথা বলে। পড়া ও লেখা এক জায়গায় হওয়ায় ট্রাঞ্জ্যাকশনগুলো পূর্বানুমেয়ভাবে আচরণ করে। আপনি অন্যান্য অঞ্চলে রেপ্লিকা যোগ করতে পারেন পড়া দ্রুত করতে, কিন্তু তখন সিদ্ধান্ত নিতে হবে কখন সামান্য স্টেইল ডেটা পড়া গ্রহণযোগ্য।
CockroachDB ও অন্যান্য বিতরণকৃত SQL সিস্টেমে শক্ত কনসিস্টেন্সিও সম্ভব, কিন্তু যখন আপনি ডেটা বহু দূরে থাকা রিজিয়নে ছড়ান এটি আরও ব্যয়বহুল হয়। এমন লেখাগুলো যা রিজিয়নজুড়ে কনসিস্টেন্ট থাকতে হবে নোডগুলোর মধ্যে সমন্বয় দাবি করে। যত বেশি দূরে রিজিয়নগুলো, সমন্বয়ের সময় তত বাড়ে। বিশেষত যখন একটি ট্রাঞ্জ্যাকশন বিভিন্ন রিজিয়নে থাকা সারিতে টাচ করে, আপনি সাধারণত ধীর লেখা ও ট্রাঞ্জ্যাকশন অনুভব করবেন।
উভয় সিস্টেমই serializable ট্রাঞ্জ্যাকশন সাপোর্ট করতে পারে (একাধিক পরিবর্তন এমনভাবে কাজ করবে যেন তারা এক-এক করে ঘটেছে)। পার্থক্য কাজটি কোথায় করা হচ্ছে: PostgreSQL বেশিরভাগ খরচ এক রিজিয়নের ভেতরেই বহন করে, যখন বিতরণকৃত সিস্টেম হয়তো রিজিয়নগুলোর ওপরে খরচ ভাগ করে তোলে।
কয়েকটি প্রশ্ন ট্রেডঅফগুলো স্পষ্ট করে:
- ব্যবহারকারীরা কি কখনো স্টেইল রিড দেখবেন, এমনকি কয়েক সেকেন্ডও?
- দুইটি রিজিয়ন কি স্বাধীনভাবে লেখাগুলো গ্রহণ করতে পারবে, নাকি প্রতিটি লেখা গ্লোবালি একমত হতে হবে?
- একই রেকর্ড দুইজন একসঙ্গে সম্পাদনা করলে কী হয়? আপনি কনফ্লিক্ট অনুমোদন করবেন?
- কোন কাজগুলো প্রতিবার সঠিক হতে হবে (পেমেন্ট, পারমিশন) বনাম কোনগুলো "শেষে ঠিক হবে" (অ্যানালিটিক্স)?
- আপনি কি একটি গ্লোবাল ট্রুথ চান, নাকি কিছু ডেটার জন্য "লোকাল ট্রুথ" গ্রহণযোগ্য?
ল্যাটেন্সি প্রত্যাশা: ব্যবহারকারীরা কী অনুভব করবে
একটি কাজে লাগার মত মানসিক মডেল: দূরত্ব সময় বাড়ায়, এবং সমন্বয় আরও সময় যোগ করে। দূরত্ব পদার্থবিজ্ঞান; সমন্বয় মানে ডাটাবেস অন্য নোডগুলোর সাথে একমত হওয়ার জন্য অপেক্ষা করছে।
একক-রিজিয়ন PostgreSQL সেটআপে বেশিরভাগ কাজ কাছাকাছি ঘটে। পড়া ও লেখা প্রায়ই আপনার অ্যাপ থেকে ডাটাবেসে এক রাউন্ড ট্রিপে সম্পন্ন হয়। যদি আপনি অন্য রিজিয়নে একটি রিড রেপ্লিকা রাখেন, পড়াগুলো লোকাল হতে পারে, তবে লেখাগুলো এখনও প্রাইমারিতে যায় এবং রেপ্লিকাগুলো সর্বদা কিছুটা পিছিয়ে থাকবে।
CockroachDB-র মত বিতরণকৃত সিস্টেমে ডেটা রিজিয়ন জুড়ে ছড়ানো থাকে। যেসব ডেটা নিকটস্থ থাকে সেগুলো পড়তে দ্রুত লাগতে পারে। কিন্তু অনেক লেখাই একটি সংখ্যাগরিষ্ঠ রেপ্লিকার নিশ্চিতকরণ চাইবে। যদি আপনার ডেটা মহাদেশ জুড়ে প্রতিলিপি করা থাকে, একটি সাধারণ লেখা ক্রস-রিজিয়ন স্বীকৃতি চাইতে পারে।
গড় ল্যাটেন্সি নয়, p95 ল্যাটেন্সির দিকে লক্ষ্য রাখুন (সবচেয়ে ধীর 5% অনুরোধ)। ব্যবহারকারীরা ওই বিরতিরাই লক্ষ্য করে। একটি পেজ যা সাধারণত 120 ms-এ লোড হয় কিন্তু দিনে কয়েকবার 800 ms হয়, সেটি খারাপ অভিজ্ঞতা দেয়, এমনকি গড় ঠিকঠাক দেখালেও।
“দ্রুত” কী তা আপনার ওয়ার্কলোডের উপর নির্ভর করে। লেখাভিত্তিক অ্যাপগুলো সাধারণত সমন্বয় খরচ বেশি অনুভব করে। পড়াভিত্তিক অ্যাপগুলো তখন ভাল করে যখন পড়াগুলো লোকাল। বড় ট্রাঞ্জ্যাকশন, বহু-ধাপের ওয়ার্কফ্লো, এবং “হট” সারি (একই রেকর্ডে অনেক ব্যবহারকারী আপডেট) ল্যাটেন্সি বাড়ায়।
PostgreSQL বনাম CockroachDB মূল্যায়ন করার সময় আপনার শীর্ষ ব্যবহারকারী অ্যাকশনগুলো (সাইনআপ, চেকআউট, সার্চ, অ্যাডমিন আপডেট) যেখানে ডেটা আছে এবং প্রতিটি ট্রাঞ্জ্যাকশনে কতগুলো রিজিয়ন সম্মত হওয়া দরকার তা ম্যাপ করুন। এই অনুশীলনটি জেনেরিক বেঞ্চমার্কের চেয়ে ব্যবহারকারীরা কী অনুভব করবে তা ভালোভাবে ভবিষ্যদ্বাণী করবে।
অপারেশনাল ট্রেডঅফ: প্রতিদিন আপনি কী চালাবেন
ফিচার লিস্টগুলো তার চেয়ে কম গুরুত্বপূর্ণ যা আপনাকে রাত 2টায় জাগিয়ে তোলে এবং আপনার টিমকে প্রতিদিন কি করতে হয়।
PostgreSQL অপারেশনগুলো পরিচিত এবং পূর্বানুমেয়। মাল্টি-রিজিয়ন সাধারণত মানে আপনি কিছু সহায়ক অংশও পরিচালনা করবেন: রেপ্লিকা, ফেইলওভার টুলিং, বা অ্যাপ-লেভেল রিজিয়ন ক্লাস্টার। কাজটি প্রায়ই পরিকল্পনা প্রমাণ করার (ফেইলওভার ড্রিল, রিস্টোর) উপর ভিত্তি করে থাকে, না কেবল দৈনন্দিন কোয়েরি টিউনিংয়ের উপরে।
CockroachDB মাল্টি-রিজিয়ন গল্পের অনেকটাই ডাটাবেসের ভেতর টেনে আনে। এতে বাইরে থাকা উপাদানগুলোর সংখ্যা কমতে পারে, কিন্তু এর মানে আপনি একটি বিতরণকৃত সিস্টেম বুঝতে হবে: নোডের স্বাস্থ্য, রেপ্লিকেশন, রিব্যালান্সিং, এবং ক্লাস্টার স্ট্রেসে কী করে।
বাস্তবে, টিমগুলো যে একই মূল কাজগুলো করে শেষ চলে আসে দুটি সেটআপেই:
- আপগ্রেড পরিকল্পনা ও ড্রাইভারের ভ্যালিডেশন, মনিটরিং ও অটোমেশন
- ব্যাকআপ নেওয়া এবং রিস্টোর টেস্ট চালানো (শুধু ব্যাকআপ আছে বলা নয়)
- ফেইলওভার অনুশীলন করা এবং সুনির্দিষ্ট রুনবুক লিখে রাখা
- স্লো কোয়েরি তদন্ত এবং “খারাপ কোয়েরি” বনাম ক্রস-রিজিয়ন ল্যাটেন্সি আলাদা করা
- স্টোরেজ বৃদ্ধি ও দীর্ঘমেয়াদি কম্প্যাকশনের নজর রাখা
ফেইলিওর মোডগুলো আলাদা অনুভব করে। PostgreSQL-এ একটি রিজিয়ন আউটেজ প্রায়ই এক পরিকল্পিত ফেইলওভার ট্রিগার করে। আপনি কিছু সময়ের জন্য রিড-অনলি মোড, বাড়তি ল্যাটেন্সি, বা কার্যকারিতার সংকোচ মেনে নিতে পারেন। বিতরণকৃত ডাটাবেসে কঠিন ঘটনাটি প্রায়ই নেটওয়ার্ক স্প্লিট; সিস্টেম কনসিস্টেন্সি রক্ষা করতে কিছু লেখাকে অস্বীকার করতে পারে যতক্ষণ না কোয়োরাম ফিরে পায়।
অবজারভেবিলিটি ও পরিবর্তনও আসে। একক প্রাইমারিতে আপনি সাধারণত জিজ্ঞেস করবেন, “কেন এই কোয়েরি ধীর?” বিতরণকৃত ক্লাস্টারে আপনি জিজ্ঞেস করবেন, “এই ডেটা কোথায় ল্যান্ড করেছে, এবং কেন কোয়েরি রিজিয়ন ক্রস করেছে?”
খরচ দুইভাবে বাড়ে—স্পষ্ট এবং অস্পষ্ট। দ্বিতীয় রিজিয়ন যোগ করলে নোড সংখ্যা বাড়ে, কিন্তু মনিটরিং, ইনসিডেন্ট জটিলতা এবং প্রোডাক্ট টিমকে ল্যাটেন্সি ও ব্যর্থতা আচরণ ব্যাখ্যা করার সময়ও বাড়ে।
বিতরণকৃত সেটআপে স্কিমা পরিবর্তন ও মাইগ্রেশন
স্কিমা পরিবর্তন মানে আপনার ডেটার গঠন পরিবর্তন: একটি কলাম যোগ করা, একটি ফিল্ডের নাম পরিবর্তন, টাইপ বদলানো (int থেকে string), একটি ইনডেক্স যোগ করা, বা নতুন টেবিল তৈরি করা।
PostgreSQL-এ মাইগ্রেশনগুলো দ্রুত হতে পারে, কিন্তু ঝুঁকি প্রায়ই লক সময় ও লেখাকে ব্লক করা। কিছু পরিবর্তন পুরো টেবিল পুনরায় লিখে বা প্রত্যাশিতের চেয়ে বেশি লক ধরে রাখতে পারে, যা পিক ট্র্যাফিকে একটি স্বাভাবিক ডিপ্লয়কে ইনসিডেন্টে পরিণত করে।
বিতরণকৃত ডাটাবেসে ঝুঁকি শিফট হয়। অনলাইন স্কিমা চেঞ্জ সাপোর্ট থাকলেও, পরিবর্তনগুলো নোডজুড়ে সম্মত হওয়া ও রিজিয়নে প্রতিলিপি হওয়া দরকার। “সরল” পরিবর্তনগুলোও রোলআউট করতে বেশি সময় নিতে পারে এবং প্রত্যেক রিজিয়নে লেগ, হটস্পট এবং কোয়েরি প্ল্যান সার্ভেইল করতে সময় লাগতে পারে। আপনি ডিপ্লয় শেষ করে এখনও প্রতিটি রিজিয়নে লাগ, হটস্পট ও কনসিস্টেন্সি পর্যবেক্ষণে সময় কাটাতে পারেন।
কিছু অভ্যাস মাইগ্রেশনগুলোকে বিরক্তিকর হওয়া থেকে রক্ষা করে:
- প্রথমে অ্যাডিটিভ পরিবর্তন পছন্দ করুন (নতুন কলাম, নতুন টেবল)। পরবর্তী রিলিজে পড়া ও লেখা স্যুইচ করুন। পরে পুরনো ফিল্ড মুছুন।
- প্রতিটি মাইগ্রেশন ছোট রাখুন যাতে দ্রুত রোলব্যাক করা যায়।
- সম্ভব হলে টাইপ ইন-প্লেস পরিবর্তন এড়ান; নতুন কলামে ব্যাকফিল করুন।
- ইনডেক্সকে দ্রুত টুইক হিসেব না দেখে একটি ফিচার রোলআউট হিসেবে ভাবুন।
- বাস্তব ডেটা সাইজ সহ মাইগ্রেশন অনুশীলন করুন, খালি টেস্ট ডাটাবেস নয়।
উদাহরণ: আপনি EU ব্যবহারকারীদের জন্য preferred_language যোগ করেন। কলাম যোগ করুন, এক রিলিজে পুরানো ও নতুন ফিল্ড উভয় লেখুন, তারপর UI-কে নতুন ফিল্ড পড়তে আপডেট করুন, এবং শেষে পরিষ্কার করুন। মাল্টি-রিজিয়ন সেটআপে স্টেজড রোলআউট রিজিয়নগুলো আলাদা গতিতে ক্যাচ-আপ করলে অপ্রত্যাশিততা কমায়।
আগেভাগে বিতরণকৃত হওয়ার বাস্তব খরচ
শুধু ডাটাবেস বাছাই নয়—এটি কিভাবে দ্রুত আপনি শিপ করবেন, প্রোডাকশনে কত বার অপ্রত্যাশ্যতা হবে, এবং আপনার টিম কতটা সময় সিস্টেম স্থিতিশীল রাখায় ব্যয় করবে তা বদলে দেয়।
যদি আপনি একটি একক-প্রাইমারির রিজিয়ন দিয়ে আপনার লক্ষ্য পূরণ করতে পারেন, সাধারণত সরল থাকা শুরুতে জিতবে। কম কম্পোনেন্ট, স্পষ্ট ব্যর্থতা, এবং দ্রুত ডিবাগিং—এসব সুবিধা আছে। হায়ার করাও সহজ কারণ PostgreSQL অভিজ্ঞতা সাধারণ। লোকাল ডেভ এবং CI সাধারণত সরল।
টিমগুলো প্রায়ই কেন্দ্রীভূত থেকে শুরু করে কারণ এটি দ্রুত ইটারেশন, সহজ রোলব্যাক এবং পূর্বানুমেয় পারফরম্যান্স দেয়। অন-কলও সহজ হয় যখন সিস্টেমে কম চলমান অংশ থাকে।
আগেভাগে বিতরণকৃত হওয়াও সঠিক সিদ্ধান্ত হতে পারে যখন প্রয়োজন বাস্তব এবং অমীমাংসিত: রিজিয়ন জুড়ে কঠোর আপটাইম টার্গেট, আইনি রেসিডেন্সি চাহিদা, বা এমন একটি গ্লোবাল ইউজারবেস যেখানে ল্যাটেন্সি সরাসরি রাজস্বে প্রভাব ফেলে।
জটিলতার ট্যাক্স ছোটভাবে শুরু করে কিন্তু যোগে যোগে বেড়ে যায়: ফিচার কাজ করতে বেশি সময় নেয় কারণ আপনাকে মাল্টি-রিজিয়ন আচরণ বিবেচনা করতে হবে, টেস্টগুলোতে আরও ফেইলিওর মোড কভার করতে হয়, এবং ইনসিডেন্টগুলো দীর্ঘ হয় কারণ রুটকারণ টাইমিং, রেপ্লিকেশন বা কনসেনসাস জটিলতাই হতে পারে—“ডাটাবেস ডাউন” নয়। এমনকি মৌলিক স্কিমা পরিবর্তনও আরও সাবধানতা দাবি করে।
একটি কার্যকর নীতি: আগে চাহিদা যাচাই করুন, তারপর যখন ব্যথা পরিমাপযোগ্য হয় তখন বিতরণে যান। সাধারণ ট্রিগারগুলো: একটি রিজিয়নে SLO মিস হওয়া, ল্যাটেন্সির কারণে ধারাবাহিক ব্যবহারকারী হারানো, বা কপ্লায়েন্স রিকোয়ারমেন্ট যা ডিল ব্লক করে।
আপনি AppMaster-এর মত টুল দিয়ে নির্মাণ করলে, সরল ডিপ্লয় দিয়ে শুরু করে ওয়ার্কফ্লো ও ডেটা মডেল রিফাইন করার সময় পরে মাল্টি-রিজিয়ন পরিকল্পনায় যাওয়া সহজ হয়।
তাদের মধ্যে বেছে নেওয়ার ধাপে ধাপে উপায়
“মাল্টি-রিজিয়ন” কিছু সংখ্যায় এবং কিছু ইউজার ফ্লোতে পরিণত হলে স্পষ্ট হয়।
ধাপে ধাপে
- সহজ কথায় RPO ও RTO লিখে নিন। উদাহরণ: “এক রিজিয়ন মারা গেলে আমরা সর্বোচ্চ 1 মিনিট ডেটা হারাতে পারি (RPO), এবং 15 মিনিটে ফিরে আসতে হবে (RTO)।” যদি আপনি কমিট হওয়া লেখাগুলো কখনো হারাতে পারবেন না বলে থাকেন, সেটা স্পষ্টভাবে বলুন।
- ব্যবহারকারীরা কোথায় আছেন ম্যাপ করুন, এবং লিখা-সমালোচক অ্যাকশনগুলো চিহ্নিত করুন। আপনার রিজিয়নগুলো তালিকায় লিখুন ও শীর্ষ অ্যাকশনগুলি: সাইন-আপ, চেকআউট, পাসওয়ার্ড রিসেট, একটি মন্তব্য পোস্ট করা, ফিড দেখা। সব লেখাই সমান গুরুত্বপূর্ণ নয়।
- ফিচারভিত্তিক কনসিস্টেন্সি চাহিদা নির্ধারণ করুন। পেমেন্ট, ইনভেন্টরি, অ্যাকাউন্ট ব্যালান্স সাধারণত কঠোর সঠিকতা দাবী করে। ফিড, অ্যানালিটিক্স, এবং “last seen” প্রায়শই সামান্য বিলম্ব সহ্য করে।
- একটি ল্যাটেন্সি বাজেট সেট করুন এবং লক্ষ্য রিজিয়ন থেকে টেস্ট করুন। সিদ্ধান্ত নিন “যা যথেষ্ট দ্রুত” মানে কী (উদাহরণ: প্রধান অ্যাকশনের জন্য 200 থেকে 400 ms), তারপর লক্ষ্য রিজিয়নগুলো থেকে রাউন্ড-ট্রিপ সময় মাপুন।
- এমন একটি অপারেটিং মডেল নির্বাচন করুন যা আপনার টিম সহ করতে পারে। অন-কল সময়, ডাটাবেস স্কিল, এবং জটিলতা সহ্য করার ক্ষমতা সম্পর্কে সৎ থাকুন।
একটি দ্রুত উদাহরণ
যদি অধিকাংশ ব্যবহারকারী US-এ এবং EU-এ খুব ছোট অংশ থাকে, আপনি সম্ভবত এক প্রাইমারি রিজিয়নে লেখাগুলো রাখবেন, রিকভারি টার্গেট কঠোর করবেন, এবং নন-ক্রিটিক্যাল স্ক্রিনের জন্য EU রিড অপ্টিমাইজেশন যোগ করবেন। যদি EU-তে লিখাভাব বেশি হয় এবং UX উন্নত করা আবশ্যক হয়, তাহলে EU সার্ভিস লেয়ার বা কিউ বিবেচনা করুন যাতে UI প্রতিক্রিয়াশীল থাকে। যখন কোর টেবিলগুলো (অ্যাকাউন্ট, বিলিং, পারমিশন) মাল্টি-রিজিয়ন কনসিস্টেন্ট হওয়া প্রয়োজন হবে তখন ডাটাবেস পছন্দ পুনঃবিবেচনা করুন।
AppMaster-এ নির্মাণ করলে ভিজ্যুয়াল বিজনেস প্রসেসে লজিক রাখলে ভবিষ্যতে ডিপ্লয়মেন্ট রিজিয়ন বা ডাটাবেস স্ট্র্যাটেজি পরিবর্তন তুলনামূলকভাবে কম ব্যথাদায়ক হয়।
উদাহরণ পরিস্থিতি: একই প্রোডাক্টে US ও EU কাস্টমার
একটি B2B SaaS কল্পনা করুন যেখানে একটি অ্যাকাউন্টে নিউ ইয়র্ক ও বার্লিনের টিমমেট আছে। সবাই একই টিকিট, ইনভয়েস, এবং ব্যবহার সীমা দেখে। বিলিং শেয়ার্ড, তাই একটি পেমেন্ট ইভেন্ট পুরো অ্যাকাউন্টের অ্যাক্সেসে সঙ্গে সঙ্গেই প্রভাব ফেলা উচিত।
PostgreSQL-এ একটি সাধারণ সেটআপ হলো US-এ একটি প্রাইমারি ডাটাবেস এবং EU-তে রিড রেপ্লিকা। US ব্যবহারকারীরা দ্রুত রিড এবং রাইট পায়। EU ব্যবহারকারীরা লোকালি পড়তে পায়, কিন্তু যা এখনই সঠিক থাকা দরকার (বর্তমান প্ল্যান, সর্বশেষ পারমিশন, ইনভয়েস স্ট্যাটাস) প্রায়শই US প্রাইমারিতে পৌঁছাতে হবে। EU-রিড যদি রেপ্লিকা থেকে আসে, আপনি মেনে নেবেন যে এটা দেরিতে আপডেট হতে পারে—কখনও দেখা যেতে পারে যে বার্লিনের একজন ফাইন্যান্স অ্যাডমিন ইনভয়েস পরিশোধ করে, রিফ্রেশ করেও এখনও "পাস্ট ডিউ" দেখছে।
CockroachDB-এর মত মাল্টি-রিজিয়ন বিতরণকৃত ডাটাবেসে আপনি ডেটা উভয় অঞ্চলের কাছাকাছি রাখতে পারেন যখন একটি যৌক্তিক ডাটাবেস বজায় থাকে। ট্রেডঅফ হলো অনেক লেখা এবং কিছু পড়াও রিজিয়নগুলোর মধ্যে সমন্বয় চাইবে যাতে কনসিস্টেন্সি থাকে। সেই অতিরিক্ত ক্রস-রিজিয়ন রাউন্ড-ট্রিপটি সাধারণ পথের অংশ হয়ে যায়, বিশেষত শেয়ার করা রেকর্ডগুলোর ক্ষেত্রে যেমন অ্যাকাউন্ট সেটিংস ও বিলিং।
একটি ধাপে পরিকল্পনা যা প্রায়ই কাজ করে:
- এক রিজিয়ন ও একটি PostgreSQL প্রাইমারির সাথে শুরু করুন, তারপর মাপুন ব্যবহারকারী ও লেখাগুলো আসলে কোথায়।
- রিপোর্টিং ও নন-ক্রিটিক্যাল স্ক্রিনের জন্য EU রিড রেপ্লিকা যোগ করুন।
- যদি EU-এ write-heavy ফ্লো UX প্রয়োজন হয়, একটি EU সার্ভিস লেয়ার বা কিউ বিবেচনা করুন যাতে UI প্রতিক্রিয়াশীল থাকে।
- যখন কোর টেবিলগুলো মাল্টি-রিজিয়ন কনসিস্টেন্ট হওয়া দরকার, তখন ডাটাবেস পছন্দ পুনর্বিবেচনা করুন।
AppMaster-এ নির্মাণ করলে ভিজ্যুয়াল বিজনেস প্রসেসে লজিক রাখলে ভবিষ্যতে ডিপ্লয়মেন্ট রিজিয়ন বা ডাটাবেস স্ট্র্যাটেজি বদলানো তুলনামূলকভাবে কম কষ্টকর হয়।
টিমগুলো যে সাধারণ ভুলগুলো করে
সবচেয়ে বড় ভুলটি হলো ধরে নেওয়া যে “মাল্টি-রিজিয়ন” স্বয়ংক্রিয়ভাবে সবাইকে দ্রুত করে দেয়। বিতরণকৃত ডাটাবেস পদার্থবিজ্ঞানের চ্যালেঞ্জ পাশ কাটাতে পারে না—যদি একটি ট্রাঞ্জ্যাকশনকে দুই দূরবর্তী জায়গায় নিশ্চিত করতে হয়, রাউন্ড-ট্রিপ সময় প্রতিটি লেখায়ই প্রতিফলিত হবে।
আরেকটা ফাঁদ হলো কনসিস্টেন্সি প্রত্যাশাগুলো মিশিয়ে ফেলা। টিমরা ব্যালান্স, ইনভেন্টরি, পারমিশনগুলোর জন্য কঠোর সঠিকতা চায়, কিন্তু অন্য অংশকে “আদর্শত কাছাকাছি” ধরে নেয়। ফলস্বরূপ ব্যবহারকারী একটি স্ক্রিনে এক মান দেখে আর পরের ধাপে অন্য মান।
দৃষ্টি রাখার প্যাটার্নগুলো:
- প্রত্যাশা করা যে সব লেখাই লোকাল মনে হবে এমনকি যখন সেগুলো ক্রস-রিজিয়ন সম্মতি চায়
- eventual consistency-কে UI নিযে সামান্য বিষয় ধরে নেওয়া এবং পরে দেখা যে এটি ব্যবসায়িক নিয়ম ভেঙে দিচ্ছে (রিফান্ড, কোটা, অ্যাক্সেস কন্ট্রোল)
- প্রথম ইনসিডেন্টের পর অপারেশনাল বাস্তবতা শেখা (ব্যাকআপ, আপগ্রেড, নোড স্বাস্থ্য, রিজিয়ন ব্যর্থতা)
- যখন লগ ও ডেটা রিজিয়ন জুড়ে থাকে তখন স্লো ট্রাঞ্জ্যাকশন ডিবাগ করতে কতো সময় লাগে তা অবমূল্যায়ন করা
- প্রথম সিদ্ধান্তটিকে চিরস্থায়ী ধরে নেয়া না; পরিবর্তনের পথ প্ল্যান না করা
মাইগ্রেশনগুলো অতিরিক্ত মনোযোগ দাবি করে কারণ প্রোডাক্ট দ্রুত বাড়ার সময় এগুলো বেশি ঘটা/ঝুঁকিপূর্ণ হয়। একক নোডে সহজ একটি স্কিমা চেঞ্জ বহু নোড ও রিজিয়নে একসঙ্গে সঠিক রাখলে ঝুঁকিপূর্ণ হতে পারে।
প্রথম ডাটাবেস পছন্দকে একটি ধাপ হিসেবে বিবেচনা করুন, একেবারে স্থায়ী সিদ্ধান্ত নয়। AppMaster দিয়ে আপনি দ্রুত ওয়র্কফ্লো ও ডেটা মডেল প্রটোটাইপ করে বাস্তব ল্যাটেন্সি ও ব্যর্থতা আচরণ যাচাই করতে পারেন, তারপর প্রয়োজন হলে বিতরণে যান।
চূড়ান্ত সিদ্ধান্ত গ্রহণের আগে দ্রুত চেকলিস্ট
একটি নির্দেশ নির্দিষ্ট করুন যে “ভালো” মানে কী আপনার প্রোডাক্টের জন্য। মাল্টি-রিজিয়ন সেটআপ বাস্তব সমস্যা সমাধান করতে পারে, কিন্তু এগুলো ল্যাটেন্সি, কনসিস্টেন্সি এবং অপারেশনের উপর চলমান সিদ্ধান্ত চাপবে।
চেকলিস্ট সংক্ষেপে:
- আপনার শীর্ষ 3 ইউজার অ্যাকশন শনাক্ত করুন (উদাহরণ: সাইন-ইন, চেকআউট, শেয়ার্ড রেকর্ড আপডেট) এবং ঐ ব্যবহারকারীরা কোথায় আছে।
- স্থির করুন কোনগুলো রিজিয়ন জুড়ে শক্ত কনসিস্টেন্ট থাকতে হবে ও কোনগুলো বিলম্ব সহ্য করতে পারে।
- স্পষ্টভাবে আপনার ব্যর্থতা কাহিনী লিখুন: “যদি রিজিয়ন X 1 ঘণ্টা ডাউন থাকে, তাহলে Y অঞ্চলের ব্যবহারকারী A ও B করতে পারবে, কিন্তু C করতে পারবে না।”
- ব্যাকআপ, রিস্টোর টেস্টিং, আপগ্রেড ও মনিটরিং-এর মালিক নির্ধারণ করুন।
- একটি স্কিমা পরিবর্তন পরিকল্পনা খসড়া করুন যা স্টেজড রোলআউট বজায় রাখে যাতে অ্যাপ সামঞ্জস্যপূর্ণ থাকে।
যদি আপনি AppMaster-এর মত নো-কোড প্ল্যাটফর্ম ব্যবহার করেন, এই চেকলিস্টটি বিল্ড নোটে আগে রাখতে হবে—এতে ডেটা মডেল, বিজনেস লজিক ও রোলআউট ধাপে ধাপে সঙ্গত থাকে যখন চাহিদা বদলে যায়।
পরবর্তী পদক্ষেপ: আপনার অনুমানগুলো পরীক্ষা করে একটি বিল্ড পথ নির্বাচন করুন
বেশিরভাগ টিমকে প্রথম দিনেই বিতরণকৃত ডাটাবেসের প্রয়োজন নেই। তাদের প্রয়োজন সাধারণত পূর্বানুমেয় আচরণ, সরল অপারেশন, এবং স্পষ্ট বৃদ্ধি পাথ।
এই সিদ্ধান্ত সাধারণত একটি প্রশ্নে অবতীর্ণ হয়: কী আপনি কোর ওয়ার্কফ্লোতে একাধিক রিজিয়নে সঠিক, সক্রিয় লেখার প্রয়োজন?
- যদি আপনি এক প্রাইমারি রিজিয়ন রেখে রেপ্লিকা, ক্যাশ বা রিড-অনলি কপিগুলো ব্যবহার করতে পারেন, PostgreSQL প্রায়ই ভালো ফিট।
- যদি আপনি প্রকৃতপক্ষে মাল্টি-রিজিয়ন লেখার সঙ্গে শক্ত কনসিস্টেন্সি চান, বিতরণকৃত SQL মিলতে পারে, তবে উচ্চতর বেসলাইন ল্যাটেন্সি ও অপারেশনাল জটিলতা মেনে নিতে হবে।
আপনার পছন্দ পরীক্ষার জন্য একটি ফোকাসড প্রুফ পরিকল্পনা উপকারী।
একটি ছোট প্রুফ প্ল্যান (1-2 দিন)
- প্রতিটি লক্ষ রিজিয়ন থেকে p95 ল্যাটেন্সি মাপুন (পড়া ও লেখা)।
- একটি ব্যর্থতা মোড সিমুলেট করুন (একটি নোড বন্ধ করা, একটি রিজিয়ন ব্লক করা, বা ইন্টার-রিজিয়ন ট্রাফিক নিষ্ক্রিয় করা) এবং নোট করুন কী ভেঙে যায়।
- 2-3টি ক্রিটিক্যাল ট্রাঞ্জ্যাকশন এন্ড-টু-এন্ড চালান (সাইনআপ, চেকআউট, প্রোফাইল আপডেট) এবং রিট্রাই, টাইমআউট, ও ব্যবহারকারী-দৃশ্যমান ত্রুটি লক্ষ্য করুন।
- একটি প্রায়শই করা স্কিমা পরিবর্তন চেষ্টা করুন (কলাম যোগ, ইনডেক্স যোগ)। সময় নিন এবং দেখুন এটি কী ব্লক করে।
পরবর্তীতে ডেটা মালিকানা লিখে রাখুন। কোন রিজিয়ন কোন কাস্টমার রেকর্ড “মালিকানায় রাখে”? কোন টেবিলগুলো শক্ত কনসিস্টেন্ট হতে হবে, এবং কোনগুলো eventual consistent (যেমন অ্যানালিটিক্স ইভেন্ট)? এছাড়া নির্ধারণ করুন কী পর্যবেক্ষণে পরে মাইগ্রেশন ট্রিগার হবে, কিভাবে ব্যাকফিল করবেন, এবং কিভাবে রোলব্যাক করবেন।
একটি সাধারণ বিল্ড পাথ হলো PostgreSQL-এ শুরু করা, স্কিমা পরিষ্কার রাখা (স্পষ্ট প্রাইমারি কী, কম ক্রস-টেবিল রাইট হটস্পট), এবং এমনভাবে ডিজাইন করা যাতে রিজিয়ন-নির্দিষ্ট ডেটা পরে সহজে আলাদা করা যায়।
যদি আপনি AppMaster ব্যবহার করেন, আপনি Data Designer-এ একটি PostgreSQL স্কিমা মডেল করতে পারেন এবং প্রোডাকশন-রেডি অ্যাপ জেনারেট করে ডিপ্লয় করতে পারেন যতক্ষণ না মাল্টি-রিজিয়ন লেখার প্রয়োজন বাস্তবে প্রমাণিত হয়। AppMaster on appmaster.io একটি সরল উপায় প্রদান করে পূর্ণ স্ট্যাক প্রোটোটাইপ করতে, ফলে জটিল মাল্টি-রিজিয়ন আর্কিটেকচারে অপ্রয়োজনীয়ভাবে আগেভাগে কমিট করা এড়ানো যায়।
প্রশ্নোত্তর
শুরুতে লিখে নিন আপনি কোন সুনির্দিষ্ট ব্যর্থতা থেকে 살아 রাখতে চান (একটি সম্পূর্ণ রিজিয়ন ডাউন, একটি ডাটাবেস নোডের ক্ষতি, না কি ইন্টার-রিজিয়ন নেটওয়ার্ক বিচ্ছেদ) এবং সেই ঘটনায় ব্যবহারকারীরা কী করতে পারবে। তারপর RPO (কত ডেটা হারানো যায়) ও RTO (কত দ্রুত পুনরুদ্ধার করতে হবে) পরিষ্কারভাবে নির্ধারণ করুন। এগুলো স্পষ্ট হলে PostgreSQL বনাম CockroachDB-এর ট্রেডঅফ বুঝতে সহজ হবে।
যদি আপনি একটি একক প্রাইমারি রাইট অঞ্চল রাখতে পারেন এবং রিজিয়ন আউটেজে স্বল্প ফেইলওভার প্রক্রিয়া মেনে চলতে রাজি থাকেন, তবে PostgreSQL সাধারণত ভালো ডিফল্ট। অপারেশন সহজ, হায়ার করা সহজ এবং প্রাইমারির কাছে লেখা হলে লেখা ল্যাটেন্সি সাধারণত তাড়াতাড়ি। অপর অঞ্চলে দ্রুত রিড চাইলে সেখানে read replica যোগ করুন, যদি আপনি কিছু রেপ্লিকেশন ল্যাগ গ্রহণ করতে পারেন।
CockroachDB তখন বেশি মানায় যখন আপনাকে চাই যে কোনো রিজিয়ন ডাউন থাকলেও সিস্টেম সঠিক থাকে এবং লেখাগুলো গ্রহন করে যাবে—হাতে-কলমে promote-and-switch না করেই। বিনিময়ে থাকে উচ্চতর বেসলাইন লেখা ল্যাটেন্সি এবং বেশি জটিলতা, কারণ ডাটাবেসকে কনসিস্টেন্ট রাখতে রেপ্লিকাগুলোর মধ্যে সমন্বয় করতে হয়। যদি মাল্টি-রিজিয়ন কনসিস্টেন্সি আবশ্যকীয় হয়, তখন এটা ভাল মিল।
সাধারণ প্যাটার্ন হল একক PostgreSQL প্রাইমারি যেখানে পড়া ও লেখা হয়, এবং অন্য অঞ্চলে read replicas থাকে লোকাল রিড পারফরম্যান্সের জন্য। রিড-অনলি বা “স্বল্প মাত্রার পুরোনো হলে ঠিক আছে” স্ক্রিনগুলোকে রেপ্লিকায় পাঠান, আর যেগুলো কনসিস্টেন্সি-ক্রিটিক্যাল (বিলিং, পারমিশন) সেগুলো প্রাইমারিতে পাঠান। এতে পুরো ডিস্ট্রিবিউটেড-রাইট জটিলতা এড়ানো যায়।
রেপ্লিকা ল্যাগ কিছু সময়ের জন্য ব্যবহারকারীকে পুরোনো ডেটা দেখাতে পারে, যা যদি পরের ধাপটি সর্বশেষ লেখার উপস্থিতি ধরে নেয় তবে ওয়ার্কফ্লো ভাঙ্গতে পারে। ঝুঁকি কমাতে, ক্রিটিক্যাল রিডগুলো প্রাইমারিতে রাখুন, নন-ক্রিটিক্যাল স্ক্রিনে ছোট বিলম্ব সহনের UX ডিজাইন করুন, এবং যেখানে প্রয়োজন রিট্রাই বা রিফ্রেশ প্রম্পট যোগ করুন। মূলটি হল আগে থেকেই সিদ্ধান্ত নেওয়া কোন ফিচারগুলো “eventually consistent” হতে পারে।
মাল্টি-রিজিয়ন লেখাগুলো সাধারণত ধীর মনে হয় কারণ ডাটাবেসকে অন্যান্য রেপ্লিকাগুলোর সাথে লিখা কনফার্ম করতে হয়। আপনি যতদূর রেপ্লিকা ছড়িয়ে দেবেন, সমন্বয়ের জন্যround-trip সময়ই তত বাড়বে এবং সেটা p95 ল্যাটেন্সিতে স্পষ্ট হবে। যদি আপনার অ্যাপ লেখাভিত্তিক হয় বা শেয়ার করা রোতে একাধিক ধাপের ট্রাঞ্জ্যাকশন থাকে, অতিরিক্ত রাউন্ড-ট্রিপ ব্যবহারকারীদের কাছে খুবই অনুভূত হতে পারে।
আপনার শীর্ষ ইউজার অ্যাকশনের p95 ল্যাটেন্সিতে ফোকাস করুন, শুধু গড় বা সিন্থেটিক বেঞ্চমার্ক নয়। আপনার ব্যবহারকারীরা যেখানে আছেন সেই রিজিয়নগুলো থেকে বাস্তব পড়া ও লেখার টাইমিং মাপুন এবং কয়েকটি ক্রিটিক্যাল ফ্লো (সাইনআপ, চেকআউট, পারমিশন চেঞ্জ) এন্ড-টু-এন্ড টেস্ট করুন। কমপক্ষে একটি ব্যর্থতা মোড সিমুলেট করে রেকর্ড করুন কী ভেঙে। "সাধারণ অবস্থায় কাজ করে" মানেই নয় "আউটেজে কাজ করে"।
PostgreSQL-এ ডেঞ্জার সাধারণত লক সময় ও বড় টেবিলের সময়-নিয়ে যায় এমন বিকল্পগুলোর থেকে আসে। ডিস্ট্রিবিউটেড সিস্টেমেও অনলাইন চেঞ্জ সমর্থিত থাকতে পারে, কিন্তু পরিবর্তনগুলো নোডজুড়ে একরকমভাবে ছড়াতে সময় লাগতে পারে এবং রিজিয়নভিত্তিক হটস্পট বা কোয়েরি প্ল্যান শিফট দেখা দিতে পারে। দুটো ক্ষেত্রেই সবচেয়ে নিরাপদ পদ্ধতি হচ্ছে স্টেজড, অ্যাডিটিভ মাইগ্রেশন যাতে অ্যাপ সাময়িকভাবে সামঞ্জস্যপূর্ণ থাকে।
PostgreSQL-এ একটি পুরো রিজিয়ন আউটেজ সাধারণত একটি পরিকল্পিত ফেইলওভার ট্রিগার করে—রিপ্লিকাকে প্রোমোট করে অ্যাপকে নতুন প্রাইমারিতে সুইচ করা হয়, মাঝে মাঝে সংক্ষিপ্ত লেখার বিরতি দেখা যায়। ডিস্ট্রিবিউটেড সিস্টেমে সবচেয়ে কষ্টদায়ক ঘটনাটি হতে পারে নেটওয়ার্ক স্প্লিট—সিস্টেম কনসিস্টেন্সি রক্ষা করতে কোয়োরাম না পেলে কিছু লেখাকে অস্বীকার করতে পারে। আপনার রুনবুকগুলোকে উভয় ধরনের ঘটনাই কভার করতে হবে।
হ্যাঁ—যদি আপনি এটিকে একটি বিবর্তনধারী পদক্ষেপ হিসেবে বিবেচনা করেন। প্রথমে একক-রিজিয়ন রাইট মডেল নিয়ে শুরু করুন, আপনার স্কিমা পরিষ্কার রাখুন, এবং প্রতিটি ফিচারের জন্য মাল্টি-রিজিয়ন প্রয়োজনীয়তা নির্দিষ্ট রাখুন যাতে ভুলবশত ক্রিটিক্যাল ওয়ার্কফ্লো স্টেইল রিডে নির্ভর না করে। AppMaster দিয়ে কাজ করলে আপনি দ্রুত ডেটা মডেল ও বিজনেস লজিক ইটারেট করে বাস্তব ল্যাটেন্সি ও ব্যর্থতা আচরণ যাচাই করতে পারবেন, এবং প্রয়োজনে পরে জটিল মাল্টি-রিজিয়ন পরিকল্পনায় যেতে পারবেন।


