6 মিনিট

বিতরণকৃত সিস্টেম ধারণা: Kleppmann-এর আইডিয়া SaaS স্কেলিং-এর জন্য

প্রোটোটাইপকে নির্ভরযোগ্য SaaS-এ রূপান্তরের সময় দলগুলো যে বাস্তবপক সিদ্ধান্তগুলো করে: ডেটা ফ্লো, কনসিস্টেন্সি, এবং লোড কন্ট্রোল সহজ ভাষায় ব্যাখ্যা।

বিতরণকৃত সিস্টেম ধারণা: Kleppmann-এর আইডিয়া SaaS স্কেলিং-এর জন্য

প্রোটোটাইপ থেকে SaaS: বিভ্রান্তি কোথায় শুরু হয়

একটি প্রোটোটাইপ আইডিয়া প্রমাণ করে। একটি SaaS-কে বাস্তব ব্যবহারের সঙ্গে বাঁচতে হয়: пик ট্র্যাফিক, এলোমেলো ডেটা, রিট্রাই, এবং এমন গ্রাহক যারা প্রতিটি হিঁচকির কথা নজরে রাখে। তখনই জিনিসগুলো বিভ্রান্তিকর হয়, কারণ প্রশ্ন থাকে “এটা কি কাজ করে?” থেকে বদলে যায় “এটা কি চালু থেকে কাজ করে?”

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

অধিকাংশ জটিলতা চারটি জায়গায় দেখা যায়: ডেটা (একই ফ্যাক্ট একাধিক স্থানে থাকে ও ড্রিফট করে), ল্যাটেন্সি (50 ms কল কখনো 5 সেকেন্ড নেয়), ব্যর্থতা (টাইমআউট, পার্শিয়াল আপডেট, রিট্রাই), এবং টিম (ভিন্ন মানুষ ভিন্ন সার্ভিস আলাদা সময়সূচিতে ডিপ্লয় করে)।

একটি সোজা মানসিক মডেল সাহায্য করে: কম্পোনেন্ট, মেসেজ, এবং স্টেট।

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

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

ধারণাকে লিখিত সিদ্ধান্তে রূপদান করুন

সিস্টেমগুলো কঠিন হয় কারণ সেগুলো বাড়ে ঠিক তখনই যখন কি সঠিক থাকতে হবে, কি দ্রুত হওয়া দরকার, এবং কোনো ব্যর্থতার সময় কি হওয়া উচিত সে সম্পর্কে সম্মতি থাকে না।

প্রথমে আপনি যে সীমা ব্যবহারকারীদের কাছে প্রতিশ্রুতি দিচ্ছেন তা আঁকুন। সেই সীমানার ভেতরে এমন অ্যাকশনগুলো নাম দিন যেগুলো প্রতিবার সঠিক থাকা বাধ্যতামূলক (টাকা লেনদেন, অ্যাক্সেস কন্ট্রোল, অ্যাকাউন্ট মালিকানা)। এরপর সেই এলাকাগুলো নাম করুন যেখানে “eventually correct” ঠিক আছে (অ্যানালিটিক্স কাউন্ট, সার্চ ইনডেক্স, রিকমেন্ডেশন)। এই এক ভাগফোড়া অস্পষ্ট তত্ত্বকে অগ্রাধিকার হিসেবে পরিণত করে।

এরপর আপনার source of truth লিখে রাখুন। এটি সেই জায়গা যেখানে ফ্যাক্ট একবার, টেকসইভাবে স্পষ্ট নিয়মসহ রেকর্ড হয়। বাকী সবকিছু গতি বা সুবিধার জন্য ডেরাইভড ডেটা। যদি একটি ডেরাইভড ভিউ ক্ষতিগ্রস্ত হয়, আপনাকে সেটি source of truth থেকে পুনর্নির্মাণ করতে সক্ষম হওয়া উচিত।

যখন টিম আটকে যায়, সাধারণত এই প্রশ্নগুলো গুরুত্বপূর্ণ বিষয়গুলো উত্থাপন করে:

  • কোন ডেটা কখনই হারাতে পারবেন না, এমনকি যদি সেটা ধীর করে দেয়?

  • কোন ডেটা অন্য ডেটা থেকে পুনরায় তৈরি করা যাবে, এমনকি যদি সেটিতে কয়েক ঘন্টা লাগতে পারে?

  • ব্যবহারকারীর দৃষ্টিকোণ থেকে কি স্টেল হতে পারে, এবং কতক্ষণ?

  • কোন ব্যর্থতা আপনার জন্য খারাপ: ডুপ্লিকেট, ইভেন্ট মিসিং, না কি ডিলে?

যদি একজন ব্যবহারকারী তাদের বিলিং প্ল্যান আপডেট করে, একটি ড্যাশবোর্ড দেরি দেখাতে পারে। কিন্তু পেমেন্ট স্ট্যাটাস এবং বাস্তব অ্যাক্সেসের মধ্যে মিলবৈপরীত্য সহ্য করা যায় না।

স্ট্রিম, কিউ, এবং লগ: কাজের সঠিক আকার বেছে নেওয়া

যদি ব্যবহারকারী একটি বাটন ক্লিক করে এবং অবিলম্বে ফলাফল দেখতে হবে (প্রোফাইল সেভ, ড্যাশবোর্ড লোড, পারমিশন চেক), সাধারণ request-response API সাধারনতেই যথেষ্ট। সরাসরি রাখুন।

যেই মুহূর্তে কাজ পরে করা যায়, সেটিকে async-এ পাঠান। ইমেইল পাঠানো, কার্ড চার্জ করা, রিপোর্ট জেনারেট করা, আপলোড রিসাইজ করা, বা সার্চ-এ ডেটা সিঙ্ক করা—এসব কাজ ব্যবহারকারীকে অপেক্ষা করাতে হবে না এবং আপনার API চলতে থাকা অবস্থায় ব্লক থাকা উচিত নয়।

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

প্র্যাকটিক্যালভাবে বেছে নেওয়ার উপায়:

  • ব্যবহার করুন request-response যখন ব্যবহারকারী অবিলম্বে উত্তর চান এবং কাজটা ছোট।
  • ব্যাকগ্রাউন্ড ওয়ার্কের জন্য কিউ ব্যবহার করুন যেখানে রিট্রাই আছে এবং প্রতিটি জব একবার একজন ওয়ার্কার-কে করা উচিত।
  • রিপ্লে, অডিট ট্রেইল, বা একাধিক কনজিউমার দরকার হলে স্ট্রিম/লগ ব্যবহার করুন যাতে প্রডিউসারের সাথে কাপল না হয়।

উদাহরণ: আপনার SaaS-এ একটি “Create invoice” বোতাম আছে। API ইনপুট ভ্যালিডেট করে এবং ইনভয়েস Postgres-এ স্টোর করে। তারপর একটি কিউ “send invoice email” এবং “charge card” হ্যান্ডেল করে। পরে যদি আপনি অ্যানালিটিক্স, নোটিফিকেশন, এবং ফ্রড চেক যোগ করেন, একটি InvoiceCreated ইভেন্ট স্ট্রিম প্রত্যেক ফিচারকে সাবস্ক্রাইব করতে দেয় কোনো মূল সার্ভিসকে জটিল করার দরকার ছাড়া।

ইভেন্ট ডিজাইন: আপনি কী প্রকাশ করবেন এবং কী রাখবেন

পণ্যে বৃদ্ধির সাথে ইভেন্টগুলো “ভালো থাকার মতো” হওয়া বন্ধ করে এবং একটি সেফটি নেটে পরিণত হয়। ভাল ইভেন্ট ডিজাইন আসলে দুই প্রশ্নে স্বংক্ষেপিত: আপনি কী ফ্যাক্ট রেকর্ড করবেন, এবং অন্য অংশগুলো কিভাবে অনুমানের দরকার ছাড়াই প্রতিক্রিয়া জানাতে পারবে?

বিজনেস ইভেন্টের একটি ছোট সেট থেকে শুরু করুন। ব্যবহারকারী ও অর্থের পক্ষে গুরুত্বপূর্ণ মুহূর্তগুলো বেছে নিন: UserSignedUp, EmailVerified, SubscriptionStarted, PaymentSucceeded, PasswordResetRequested.

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

ইভেন্টগুলোকে কনট্রাক্ট হিসেবে বিবেচনা করুন। একটি “UserUpdated” ধরার-অল এড়িয়ে চলুন যেখানে প্রতিটি স্প্রিন্টে বিভিন্ন ফিল্ড যোগ-বিয়োগ হয়। যতটা সম্ভব ছোট ফ্যাক্ট রাখুন যা আপনি বছরের পর বছর ধরে সমর্থন করতে পারবেন।

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

আপনি কী সংরক্ষণ করবেন? যদি আপনি কেবল ডাটাবেসে সর্বশেষ সারি রাখেন, আপনি সেখানে পৌঁছানোর গল্প হারান।

র’অ ক events অডিট, রিপ্লে, ও ডিবাগিংয়ের জন্য দারুণ। স্ন্যাপশট দ্রুত রিড এবং দ্রুত রিকভারের জন্য সুবিধাজনক। অনেক SaaS উভয়ই ব্যবহার করে: কেমান কিওয়ার্কফ্লো (বিলিং, পারমিশন) জন্য র’অ ইভেন্ট সংরক্ষণ করুন এবং ইউজার-ফেসিং স্ক্রিনের জন্য স্ন্যাপশট বজায় রাখুন।

ব্যবহারকারীরা বাস্তবে অনুভব করা কনসিস্টেন্সি ট্রেডঅফ

SaaS বানান, স্লাইড নয়
আপনার স্কেলিং সিদ্ধান্তগুলোকে এক জায়গায় React + Go + Postgres অ্যাপে রূপ দিন।

কনসিস্টেন্সি এমন মুহূর্তগুলোতে দেখা যায়: “আমি আমার প্ল্যান বদলেছি, কেন এখনও Free দেখাচ্ছে?” বা “আমি একটা ইনভাইট পাঠিয়েছি, কেন আমার টিমমেট এখনও লগইন করতে পারছে না?”

স্ট্রং কনসিস্টেন্সি মানে আপনি সফল মেসেজ পেলেই প্রতিটি স্ক্রিন তৎক্ষণাত নতুন স্টেট প্রতিফলিত করবে। ইভেন্টুয়াল কনসিস্টেন্সি মানে পরিবর্তন সময়ের সঙ্গে ছড়িয়ে পড়ে, এবং একটি সংক্ষিপ্ত উইন্ডোতে অ্যাপের বিভিন্ন অংশ আলাদা ধারণা রাখতে পারে। কোনটিই “ভাল” নয়—আপনি সিদ্ধান্ত নেন কোন মিলবৈপরীত্য কতটা ক্ষতি করতে পারে।

স্ট্রং কনসিস্টেন্সি সাধারণত টাকা, অ্যাক্সেস, এবং নিরাপত্তার জন্য উপযুক্ত: কার্ড চার্জ, পাসওয়ার্ড পরিবর্তন, API কী প্রত্যাহার, সিট লিমিট-এর প্রয়োগ। ইভেন্টুয়াল কনসিস্টেন্সি সাধারণত কার্যকলাপ ফিড, সার্চ, অ্যানালিটিক্স ড্যাশবোর্ড, “last seen,” এবং নোটিফিকেশনের জন্য যুক্তিযুক্ত।

যদি আপনি স্টেলনেস গ্রহণ করেন, তাতে লুকোন না, বরং তার জন্য ডিজাইন করুন। UI-কে সৎ রাখুন: একটি_WRITE হওয়ার পর Until কনফার্মেশন না আসা পর্যন্ত “Updating…” দেখান, তালিকার জন্য ম্যানুয়াল রিফ্রেশ অফার করুন, এবং অপ্টিমিস্টিক UI কেবল তখন ব্যবহার করুন যখন আপনি সহজে রোলব্যাক করতে পারেন।

রিট্রাই-এ কনসিস্টেন্সি চতুর হয়ে যায়। নেটওয়ার্ক ড্রপ করে, ক্লায়েন্ট ডাবল-ক্লিক করে, ওয়ার্কার রিস্টার্ট করে। গুরুত্বপূর্ণ অপারেশনের জন্য রিকোয়েস্টগুলো idempotent করুন যাতে একই অ্যাকশন পুনরায় করতে গেলে দুইটি ইনভয়েস, দুইটি ইনভাইট, বা দুইটি রিফান্ড না ঘটে। একটি সাধারণ পদ্ধতি হল প্রতি অ্যাকশনের জন্য একটি idempotency key এবং সার্ভার-সাইড নিয়ম যাতে পুনরাবৃত্তির ক্ষেত্রে মূল ফলাফল ফেরত দেয়া হয়।

ব্যাকপ্রেশার: সিস্টেমকে পুড়ে যেতে না দেওয়ার উপায়

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

সরল ভাষায়: আপনার প্রডিউসার কথা বলা চালিয়ে যায় আর আপনার কনজিউমার ডুবছে। আপনি যদি আরো কাজ গ্রহণ করতে থাকেন, আপনি কেবল ধীর হচ্ছেন না; আপনি টাইমআউট ও রিট্রাইয়ের একটি চেইন রূপে লোডকে গুণ করছেন।

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

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

প্রথমে ডাটাবেসকে রক্ষা করুন। কানেকশন পুল ছোট ও পূর্বানুমেয় রাখুন, কুয়েরি টাইমআউট সেট করুন, এবং ad-hoc রিপোর্টের মতো ব্যয়বহুল এন্ডপয়েন্টগুলোর উপর কঠোর সীমা রাখুন।

বড়ো করে না লিখে রিলায়বিলিটি অর্জনের ধাপগুলো

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

বিশ্বাস অর্জন বা হারানোর ফ্লোগুলো থেকে শুরু করুন, তারপর ফিচার যোগ করার আগে সেফটি রেল যোগ করুন:

  1. ক্রিটিক্যাল পাথ ম্যাপ করুন। সাইনআপ, লগইন, পাসওয়ার্ড রিসেট, এবং কোনো পেমেন্ট ফ্লো-এর সঠিক ধাপগুলো লিখে রাখুন। প্রতিটি ধাপের জন্য তার ডিপেনডেন্সি (ডাটাবেস, ইমেইল প্রোভাইডার, ব্যাকগ্রাউন্ড ওয়ার্কার) তালিকাভুক্ত করুন। এটি কি অবিলম্বে হতে হবে বনাম কি “eventually” ঠিক করা যাবে তা স্পষ্ট করে।

  2. অবজারভেবিলিটি বেসিক যোগ করুন। প্রতিটি রিকোয়েস্টকে একটি ID দিন যা লগে দেখা যায়। এমন একটি ছোট সেট মেট্রিক্স ট্র্যাক করুন যা ব্যবহারকারীর কষ্টের সাথে মিলে: এরর রেট, ল্যাটেন্সি, কিউ ডেপথ, এবং ধীর কুয়েরি। যে জায়গায় রিকোয়েস্ট সার্ভিস পেরোয় সেখানে ট্রেস যোগ করুন।

  3. ধীর বা ফ্লেকি কাজ আলাদা করুন। বাইরে কোনো সার্ভিসকে কল করা বা নিয়মিত 1 সেকেন্ডের বেশি সময় নেওয়া যেকোনো কাজ জব ও ওয়ার্কার-এ স্থানান্তর করুন।

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

  5. রিকভারি অনুশীলন করুন। ব্যাকআপগুলো কেবল তখনই মূল্যবান যদি আপনি সেগুলো রিস্টোর করতে পারেন। ছোট রিলিজ ব্যবহার করুন এবং দ্রুত রোলব্যাক পথ রাখুন।

যদি আপনার টুলিং স্ন্যাপশট ও রোলব্যাক সমর্থন করে (Koder.ai করে), সেগুলোকে অভ্যাসে ঢুকান, জরুরি ট্রিক হিসেবে নয়।

উদাহরণ: একটি ছোট SaaS-কে নির্ভরযোগ্য করে তোলা

বাস্তব শর্তে পরীক্ষানিরীক্ষা করুন
শুরুতেই আপনার অ্যাপ ডিপ্লয় ও হোস্ট করুন যাতে ল্যাটেন্সি, রিট্রাই, ও কিউ ল্যাগ দেখা যায়।

একটি ছোট SaaS ধরুন যা টিমগুলোকে নতুন ক্লায়েন্ট অনবোর্ড করতে সাহায্য করে। ফ্লো সহজ: একজন ব্যবহারকারী সাইন আপ করে, প্ল্যান পছন্দ করে, পেমেন্ট করে, এবং একটি স্বাগত ইমেইল ও কিছু “শুরু করার ধাপ” পায়।

প্রোটোটাইপে সবকিছু এক রিকোয়েস্টে হয়: অ্যাকাউন্ট তৈরি, কার্ড চার্জ, ব্যবহারকারীর “paid” ফ্ল্যাগ অন, ইমেইল পাঠানো। এটি চলবে যতক্ষণ না ট্রাফিক বাড়ে, রিট্রাই ঘটে, এবং বাইরের সার্ভিস ধীর হয়ে যায়।

নির্ভরযোগ্য করতে টিমটা মূল অ্যাকশনগুলোকে ইভেন্টে পরিণত করে এবং একটি অ্যাপেন্ড-অনলি ইতিহাস রাখে। তারা কয়েকটি ইভেন্ট পরিচয় করায়: UserSignedUp, PaymentSucceeded, EntitlementGranted, WelcomeEmailRequested। এতে অডিট ট্রেইল মিলে, অ্যানালিটিক্স সহজ হয়, এবং ধীর কাজ ব্যাকগ্রাউন্ডে হতে পারে সাইনআপ ব্লক না করে।

কয়েকটি সিদ্ধান্তই বড়ো কাজ করে:

  • অ্যাক্সেসের সোর্স অফ ট্রুথ হিসেবে পেমেন্টকে বিবেচনা করুন, কেবল একটি “paid” ফ্ল্যাগ নয়।
  • PaymentSucceeded থেকে entitlement প্রদান করুন একটি স্পষ্ট idempotency key দিয়ে যাতে রিট্রাই ডাবল-গ্রান্ট না করে।
  • চেকআউট রিকোয়েস্ট থেকে ইমেইল পাঠাবেন না; ইমেইল পাঠান কিউ/ওয়ার্কার থেকে।
  • ইভেন্ট রেকর্ড করুন এমনকি যদি হ্যান্ডলার ব্যর্থ হয়, যাতে আপনি রিপ্লে ও রিকভার করতে পারেন।
  • বাইরের প্রোভাইডারের চারপাশে টাইমআউট ও সার্কিট ব্রেকার যোগ করুন।

যদি পেমেন্ট সফল হয় কিন্তু অ্যাক্সেস এখনও না দেওয়া হয়, ব্যবহারকারীরা প্রতারণার বোধ করবে। ঠিক করা যাবে না “সবার জায়গায় নিখুঁত কনসিস্টেন্সি” দিয়ে। বরং কি অবিলম্বে কনসিস্টেন্ট থাকতে হবে তা সিদ্ধান্ত নিন, এবং UI-তে সেই সিদ্ধান্ত প্রতিফলিত করুন, যেমন EntitlementGranted না আসা পর্যন্ত “Activating your plan” অবস্থা দেখানো।

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

স্কেল হলে ঘটা সাধারণ ফাঁদগুলো

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

একটি সাধারণ ফাঁদ হল খুব দ্রুত মাইক্রোসার্ভিস-এ বিভক্ত হওয়া। আপনি এমন সার্ভিস পাবেন যা মূলত একে অপরকে কল করে, স্পষ্ট মালিকানা নেই, এবং পরিবর্তনের জন্য পাঁচটি ডিপ্লয় দরকার হয় একটির বদলে।

আরেকটি ফাঁদ হল “eventual consistency” কে বিনা খরচে ছাড় দেওয়া। ব্যবহারকারীরা টার্ম নিয়ে যত্ন করে না; তারা যত্ন করে যে তারা Save ক্লিক করেছে এবং পরে পেজ পুরনো ডেটা দেখায়, বা একটি ইনভয়েস স্ট্যাটাস বারবার পিছিয়ে আসে। যদি আপনি দেরি মেনে নেন, তাহলে তাতে ইউজার ফিডব্যাক, টাইমআউট, এবং প্রতিটি স্ক্রিনে “ভালো পর্যায়” কী সে সংজ্ঞা থাকা দরকার।

অন্যান্য বারবার ঘটে এমন অপরাধীগণ: ইভেন্ট প্রকাশ করা কিন্তু রিপ্রসেসিং প্ল্যান না থাকা, অনিয়ন্ত্রিত রিট্রাই যা ঘটনার সময় লোড বাড়ায়, এবং প্রতিটি সার্ভিসকে একই ডাটাবেস স্কিমায় সরাসরি কথা বলতে দেওয়া যাতে একটি পরিবর্তন অনেক টিমকে ভেঙে দেয়।

“প্রোডাকশনে প্রস্তুত” বলার আগে দ্রুত চেক

সবার এক পাতায় আনা
একই কর্মস্থলে ক্রিটিক্যাল ফ্লোগুলো একসাথে বানিয়ে প্রোডাক্ট ও ইঞ্জিনিয়ারিংকে সঙ্গ মেলান।

“প্রোডাকশন রেডি” হলো এমন কয়েকটি সিদ্ধান্ত যেগুলো রাতের মধ্যেও আপনি সহজে তুলে ধরতে পারেন। স্পষ্টতা মানে চৌকসতার চেয়ে ভাল।

প্রথমে আপনার সোর্স অফ ট্রুথের নাম বলুন। প্রতিটি প্রধান ডেটা টাইপ (গ্রাহক, সাবস্ক্রিপশন, ইনভয়েস, পারমিশন) জন্য সিদ্ধান্ত নিন চূড়ান্ত রেকর্ড কোথায় থাকে। যদি আপনার অ্যাপ “ট্রুথ” দুই জায়গা থেকে পড়ে, আপনি একদিন বিভিন্ন ব্যবহারকারীদের ভিন্ন উত্তর দেখাবেন।

তারপর রিট্রাই দেখুন। ধরে নিন প্রতিটি গুরুত্বপূর্ণ অ্যাকশন শেষ পর্যন্ত দুইবার চলবে। একই রিকোয়েস্ট যদি দুইবার এসে লাগে, আপনি কি ডাবল চার্জ, ডাবল সেন্ড, বা ডাবল ক্রিয়েশন এড়াতে পারবেন?

একটি ছোট চেকলিস্ট যা বেশিরভাগ ব্যথা ধরা পড়ায়:

  • প্রতিটি ডেটা টাইপের জন্য সোর্স অফ ট্রুথ চিহ্নিত করা আছে ও কি কিছু ডেরাইভড

  • প্রতিটি গুরুত্বপূর্ণ রাইট রিট্রাই-সেফ (idempotency key বা ইউনিক কনস্ট্রেইন্ট)

  • আপনার অ্যাসিঙ্ক ওয়ার্ক অনন্তভাবে বাড়তে পারে না (আপনি ল্যাগ, oldest message age ট্র্যাক করেন এবং ব্যবহারকারী লক্ষ্য করার আগে অ্যালার্ট আছে)

  • পরিবর্তনের জন্য পরিকল্পনা আছে (রিভার্সিবল মাইগ্রেশন, ইভেন্ট ভার্সনিং)

  • আপনি ব্যাকআপ থেকে রিস্টোর ও রোলব্যাক অনুশীলন করেছেন

পরবর্তী ধাপ: একবারে একটা সিদ্ধান্ত নিন

সিস্টেম ডিজাইন একটি দীর্ঘ তত্ত্বের তালিকা নয় বরং সংক্ষিপ্ত সিদ্ধান্তের তালিকা হলে স্কেলিং সহজ হয়।

পরবর্তী একটি মাসে আপনি যেসব ৩–৫ টি সিদ্ধান্তের মুখোমুখি হবেন তা সাধারণ ভাষায় লিখে রাখুন: “আমরা কি ইমেইল পাঠানো ব্যাকগ্রাউন্ড জবে নিব?” “আমরা কি সামান্য স্টেল অ্যানালিটিক্স মেনে নেব?” “কোন অ্যাকশনগুলো অবিলম্বে কনসিস্টেন্ট হতে হবে?” সেই তালিকাটি ব্যবহার করে প্রোডাক্ট ও ইঞ্জিনিয়ারিংকে সমন্বয় করুন।

এরপর একটি ওয়ার্কফ্লো বেছে নিন যা বর্তমানে synchronous এবং কেবল সেটাই async-এ রূপান্তর করুন। রসিদ, নোটিফিকেশন, রিপোর্ট, এবং ফাইল প্রসেসিং সাধারণ প্রথম পদক্ষেপ। পরিবর্তনের আগে ও পরে দুই জিনিস মাপুন: ব্যবহারকারীর মুখোমুখি ল্যাটেন্সি (পেজটি কি দ্রুত অনুভূত হয়েছিল?) এবং ব্যর্থতার আচরণ (রিট্রাই কি ডুপ্লিকেট বা বিভ্রান্তি তৈরি করেছিল?)

যদি দ্রুত prototyping চান, Koder.ai (koder.ai) React + Go + PostgreSQL SaaS-এ কাজ করে দ্রুত পুনরাবৃত্তির সময় স্ন্যাপশট ও রোলব্যাক কাছে রেখে। মাপকাঠি সহজ: এক উন্নতি পাঠান, বাস্তব ট্রাফিক থেকে শিখুন, তারপর পরবর্তী সিদ্ধান্ত নিন।

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

একটি প্রোটোটাইপ এবং প্রোডাকশনের SaaS-এর মধ্যে বাস্তব পার্থক্য কী?

একটি প্রোটোটাইপ উত্তর দেয় “আমরা এটা তৈরি করতে পারি কি?” একটি SaaS উত্তর দিতে হবে “এটা ব্যবহারকারী, ডেটা, এবং ব্যর্থতার মধ্যে থাকলেও চলবে কি?”

সবচেয়ে বড় পরিবর্তনগুলো হল এমনভাবে ডিজাইন করা যাতে সেগুলো সামলে নিতে পারে:

  • ধীর ডিপেনডেন্সি (ইমেইল, পেমেন্ট, ফাইল প্রক্রিয়াকরণ)
  • রিট্রাই ও ডুপ্লিকেটস
  • ডেটা যে বাড়ে ও জটিল হয়
  • কি নিশ্চিতভাবে সঠিক থাকা দরকার বনাম কি সামান্য স্টেলে থাকা মানা যাবে তা সম্পর্কে পরিষ্কার নিয়ম
আমি কীভাবে সিদ্ধান্ত নেব কোনগুলো স্ট্রং কনসিস্টেন্ট হওয়া দরকার এবং কোনগুলো ইভেন্টুয়ালি কনসিস্টেন্ট হওয়া যাবে?

একটি সীমানা বেছে নিন যা আপনি ব্যবহারকারীদের প্রতি প্রতিশ্রুতি দিচ্ছেন, তারপর পদক্ষেপগুলোর প্রভাব অনুযায়ী লেবেল দিন।

প্রথমে প্রতিবার সঠিক হতে হবে-এর তালিকা করুন:

  • টাকা নেওয়া/ফেরত দেওয়া
  • অ্যাক্সেস নিয়ন্ত্রণ এবং অ্যানটাইটেলমেন্ট
  • অ্যাকাউন্ট মালিকানা ও সিকিউরিটি অ্যাকশন

তারপর ধীরগতিতে সঠিক হওয়া যায়-এ চিহ্ন দিন:

  • অ্যানালিটিক্স কাউন্টস
  • সার্চ ইনডেক্স
  • নোটিফিকেশন ও অ্যাক্টিভিটি ফিড

এটা লিখে রাখুন যাতে সবাই একই নিয়ম অনুযায়ী তৈরি করে।

SaaS-এ “source of truth” মানে কী, এবং আমি কীভাবে সেটা বেছে নেব?

প্রতিটি “ফ্যাক্ট” কোথায় একবার রেকর্ড হবে এবং ফাইনাল হিসেবে বিবেচিত হবে সেটা বেছে নিন (ছোট SaaS-এ প্রায়ই Postgres)। এটিই আপনার source of truth।

অন্যান্য সবকিছু গতি বা সুবিধার জন্য ডেরাইভড। একটি ভাল পরীক্ষা: ডেরাইভড ডেটা যদি ভুল হয়ে যায়, আপনি কি source of truth থেকে সেটা পুনর্গঠন করতে পারবেন অনুমান বা আন্দাজ না করে?

কখন আমি কাজকে async-এ নিয়ে যাই পরিবর্তে API রিকোয়েস্টে রেখে?

যখন ব্যবহারকারী অবিলম্বে ফলাফল দেখতে চান এবং কাজ ছোট, তখন request-response ব্যবহার করুন।

কাজটিকে async-এ নিয়ে যাবেন যখন সেটা পরে করা যাবে বা ধীর হতে পারে, যেমন:

  • ইমেইল পাঠানো
  • কার্ড চার্জ করা (প্রায়ই ভ্যালিডেশনের পরে)
  • রিপোর্ট জেনারেশন
  • ফাইল প্রসেসিং

Async রাখা আপনার API কে দ্রুত রাখে এবং ক্লায়েন্ট রিট্রাই থেকে টাইমআউট কমায়।

কিউ এবং স্ট্রিমের মধ্যে পার্থক্য কী, এবং আমি কোনটি ব্যবহার করব?

একটি কিউ হলো টু-ডু লিস্ট: প্রতিটি কাজ একবার একটি ওয়ার্কার দ্বারা করা উচিত (রিট্রাই সহ)।

একটি স্ট্রিম/লগ হলো ইভেন্টের ধারাবাহিক রেকর্ড: একাধিক কনজিউমার এটি রিপ্লে করতে পারে বা নতুন ফিচার তৈরির জন্য সাবস্ক্রাইব করতে পারে।

প্র্যাকটিক্যাল ডিফল্ট:

  • ব্যাকগ্রাউন্ড টাস্কের জন্য কিউ ব্যবহার করুন ("welcome email পাঠান")
  • রিপ্লে বা অডিট জন্য বিজনেস ইভেন্ট হলে স্ট্রিম/লগ ব্যবহার করুন (PaymentSucceeded)
রিট্রাই হলে আমি কীভাবে ডুপ্লিকেট চার্জ বা ডুপ্লিকেট ইনভয়েস প্রতিরোধ করব?

গুরুত্বপূর্ণ অপারেশনগুলো idempotent করুন: একই রিকোয়েস্ট বারবার করলে একই আউটকাম ফিরে আসবে, দ্বিতীয় চার্জ বা দ্বিতীয় ইনভয়েস তৈরি হবে না।

কমন প্যাটার্ন:

  • ক্লায়েন্ট প্রতিটি অ্যাকশনের জন্য একটি idempotency key পাঠায়
  • সার্ভার সেই key দিয়ে ফলাফল স্টোর করে
  • পুনরাবৃত্তি হলে মূল ফলাফলটি রিটার্ন করে

এছাড়া যেখানে সম্ভব ইউনিক কনস্ট্রেইন্ট ব্যবহার করুন (যেমন, একটি অর্ডারের জন্য একটাই ইনভয়েস)।

প্রোডাক্ট বাড়ার সাথে সাথে কোন ইভেন্টটা “ভাল ডিজাইনকৃত” বলা যাবে?

একটা ছোট সেট স্থিতিশীল বিজনেস ফ্যাক্টস প্রকাশ করুন, অতীত কাল নাম ব্যবহার করুন—যেমন PaymentSucceeded বা SubscriptionStarted

ইভেন্টগুলো রাখুন:

  • নির্দিষ্ট (“UserUpdated” ধরনের ক্যাচ-অল সেটা নয়)
  • কন্ট্রাক্ট হিসেবে টেকসই
  • সহজে বিবর্তনশীল (নতুন অপশনাল ফিল্ড যোগ করুন; ব্রেকিং হলে নতুন নাম/ভার্সন প্রকাশ করুন)

এটা কনজিউমারদের অনুমান করতে বাধ্য করবে না কি ঘটেছে।

ব্যাকপ্রেশারের দরকার হলে কী সতর্ক সংকেত থাকে, এবং প্রথমে আমি কী বাস্তবায়ন করব?

আপনার সিস্টেমে ব্যাকপ্রেশার দরকার হওয়ার সংকেতগুলো:

  • কিউ ব্যাকলগ কেবল বাড়ছে
  • ট্রাফিক স্পাইকের পরে ল্যাটেন্সি স্কাইরকেট করছে
  • টাইমআউটের কারণে রিট্রাই বেড়ে যাচ্ছে
  • একটি ধীর ডিপেনডেন্সি অনান্য এন্ডপয়েন্টকে ফেল করছে
  • ডাটাবেস সংযোগ সীমায় পৌঁছেছে

শুরুতে যা করা উচিত:

  • ইউজার/এপিআই কী-ভিত্তিক রেট লিমিট
  • বাউন্ডেড কিউ (পরিষ্কার ড্রপ/ডিলে পলিসি সহ)
  • ব্যর্থ ডিপেনডেন্সির জন্য সার্কিট ব্রেকার
  • ইন্টারঅ্যাকটিভ রিকোয়েস্টকে প্রায়োরিটি দিন যাতে ব্যাকগ্রাউন্ড জবগুলো হার মানে
আরো স্কেল করার আগে আমাকে কী অবজারভেবিলিটি দরকার?

শুরুতে এমন বেসিক অবজারভেবিলিটি রাখুন যা ব্যবহারকারী কষ্টের সাথে মেলে:

  • প্রতিটি রিকোয়েস্টের জন্য একটি ID যা লগে দেখা যায় শেষ পর্যন্ত
  • এরর রেট, ল্যাটেন্সি, কিউ ডেপথ, এবং ধীর কুয়েরির মতো মেট্রিক্স
  • কিউগুলোর জন্য “oldest message age” এর অ্যালার্ট (শুধু সাইজ নয়)

ট্রেসিং যোগ করুন শুধুমাত্র যেখানে রিকোয়েস্ট সার্ভিস পার করে; সবকিছু ইনস্ট্রুমেন্ট করার আগে কি খুঁজছেন তা জানুন।

বাস্তব ব্যবহারকারীরা আসার আগে আমার কোন চেকলিস্ট থাকা উচিত?

“প্রোডাকশন রেডি” মানে এমন সিদ্ধান্তের সেট যা আপনি রাত ২টায়ও দেখাতে পারেন। স্পষ্টতা চতুরতার চেয়ে ভাল।

চেকলিস্ট:

  • প্রতিটি ডেটা টাইপের জন্য সোর্স অফ ট্রুথ কোথায় তা বলতে পারেন
  • প্রতিটি গুরুত্বপূর্ণ রাইট রিট্রাই-সেফ কি (idempotency key বা ইউনিক কনস্ট্রেইন্ট)?
  • অ্যাসিঙ্ক কাজ সীমাবদ্ধ ও মনিটর করা আছে (ল্যাগ/oldest message age)
  • রিভার্সিবল মাইগ্রেশন ও ইভেন্ট ভার্সনিংয়ের পরিকল্পনা আছে
  • ব্যাকআপ থেকে রিস্টোর প্র্যাকটিস করেছেন এবং রোলব্যাক দ্রুত করতে পারেন

যদি আপনার প্ল্যাটফর্ম স্ন্যাপশট ও রোলব্যাক সাপোর্ট করে (যেমন Koder.ai), সেগুলোকে সানডে-অ্যাক্সিডেন্ট ট্রিক না করে নর্মাল রিলিজ অভ্যাস করুন।

Related posts