Monolith vs Microservices
Modular monolith কেন প্রায়ই সবচেয়ে ভালো শুরু
Netflix, Uber, Amazon এর গল্প শুনে মনে হয় microservice ই আধুনিক উপায়, আর monolith মানে পুরনো। বাস্তবতা উল্টো: বেশিরভাগ সফল product শুরু হয়েছে monolith দিয়ে, আর অনেক team অকালে microservice এ গিয়ে বছর নষ্ট করেছে। এই অধ্যায়ে দেখবো দুটোর আসল trade-off, আর মাঝের পথ modular monolith, যেটা প্রায়ই সবচেয়ে বুদ্ধিমান শুরু।
#তিন রকম গঠন
#Monolith
একটা codebase, একটা deploy, একটা process (যত copy ই চালাও)। Function call দিয়ে অংশগুলো কথা বলে।
সুবিধা: সহজ develop, test, deploy, debug। একটা database transaction এ অনেক কাজ। কম চলমান অংশ, কম খরচ। অসুবিধা (বড় হলে): সব কিছু সব কিছুকে ছোঁয় ("big ball of mud"), একটা ছোট বদলেও পুরোটা deploy, অনেক team একই code এ একে অপরের পায়ে পা দেয়, একটা অংশের scale এর জন্য পুরোটা scale।
#Microservices
প্রতিটা ব্যবসার অংশ (order, payment, user) আলাদা service: আলাদা codebase, আলাদা deploy, নিজস্ব database, network দিয়ে কথা (HTTP/gRPC/queue)।
সুবিধা:
- স্বাধীন team: payment team নিজের মতো deploy করে, অন্যদের অপেক্ষা ছাড়া
- স্বাধীন scale: search এ চাপ বেশি হলে শুধু search বাড়াও
- ব্যর্থতা আলাদা: recommendation service নষ্ট হলেও order চলে (ঠিকভাবে design করলে)
- প্রযুক্তি বাছাইয়ের স্বাধীনতা: একটা service Go তে, একটা Python এ
অসুবিধা (এগুলো ভারী):
- Network সব কিছুতে: function call ছিল ১ microsecond, এখন network call কয়েক millisecond, আর সেটা ব্যর্থ হতে পারে, ধীর হতে পারে (Resilience লাগবে)
- Distributed transaction: order আর payment দুই database এ; একসাথে commit আর হয় না (Saga)
- Data join কঠিন: "এই মাসের সেরা customer দের order" এখন তিনটা service থেকে মেলাতে হয়
- Operations এর বোঝা: ২০টা service মানে ২০টা deploy pipeline, monitoring, log, version
- Debug কঠিন: একটা request ৭টা service ঘুরে আসে; কোথায় ধীর? (Tracing লাগবে)
- শুরুতে ভুল সীমানা: service এর সীমা ভুল টানলে প্রতিটা feature এ ৩টা service একসাথে বদলাতে হয় ("distributed monolith"), দুই জগতের খারাপটা
#Modular monolith: বুদ্ধিমান শুরু
একটা deploy, কিন্তু ভেতরে কঠোরভাবে আলাদা module, প্রতিটার পরিষ্কার সীমানা:
src/app/
├── orders/
│ ├── api.py ← বাইরের জন্য public interface (শুধু এটাই অন্যরা ডাকতে পারে)
│ ├── service.py
│ ├── models.py ← orders schema/table, অন্য module সরাসরি ছোঁবে না
│ └── events.py
├── payments/
│ ├── api.py
│ └── ...
├── menu/
└── users/নিয়ম:
- এক module আরেক module এর ভেতরের file import করবে না, শুধু তার
api.py - এক module আরেকজনের table এ সরাসরি query করবে না
- পরস্পরের মধ্যে কথা function call (public interface) বা ভেতরের event দিয়ে
- এই নিয়ম tool দিয়ে জোর করো (যেমন
import-linter), শুধু ভরসায় না
লাভ: আজ monolith এর সহজতা, আর কাল কোনো একটা module কে আলাদা service এ বের করতে হলে সীমানা আগে থেকেই পরিষ্কার। Shopify এর মতো বিশাল company ও বছরের পর বছর modular monolith এ চলেছে।
#কখন microservice
| লক্ষণ | মানে |
|---|---|
| অনেক team (৩-৪ এর বেশি) একই codebase এ একে অপরকে আটকাচ্ছে | Organization এর সমস্যা, microservice সাহায্য করতে পারে |
| একটা অংশের scale বা প্রযুক্তির চাহিদা একদম আলাদা | যেমন video processing বা ML inference |
| একটা অংশের নিরাপত্তা/নিয়মকানুন আলাদা | যেমন payment (PCI) কে আলাদা রাখা |
| Deploy করতে ভয় লাগে কারণ একটা বদল সব ভাঙতে পারে | আগে test আর modular সীমানা ঠিক করো |
#Service কীভাবে ভাগ করবে
ভাগ করো ব্যবসার ক্ষমতা অনুযায়ী (bounded context), technical স্তর অনুযায়ী না:
- ✓ Order service, Payment service, Catalog service, Delivery service
- ✗ "Database service", "Validation service", "Email-sending utils service"
ভালো সীমানার লক্ষণ: বেশিরভাগ feature এর কাজ একটা service এর ভেতরেই শেষ হয়, আর service গুলো কম কথা বলে।
#Service দের মধ্যে কথা
| ধরন | কখন | ঝুঁকি |
|---|---|---|
| Sync (REST/gRPC) | এখনই উত্তর লাগবে ("এই user এর address কী?") | Chain লম্বা হলে latency যোগ হয়, একটা ধীর হলে সবাই ধীর |
| Async (event/queue) | পরে হলেও চলে ("order হয়েছে, notification পাঠাও") | Eventual consistency, debug কঠিন |
নিয়ম: sync call এর chain ছোট রাখো। A → B → C → D chain এ প্রত্যেকে 99.9% চালু থাকলে মোট availability 99.6%, আর latency সবার যোগফল। যেখানে সম্ভব async event, আর দরকারি data নিজের কাছে copy রাখা (Order service customer এর নাম আর ঠিকানার copy রাখে, প্রতিবার User service কে জিজ্ঞেস না করে)।
#অনুশীলন
#নিজেকে যাচাই করো
Microservice এর তিনটা বড় অসুবিধা বলো।
Network call এর latency আর ব্যর্থতা, distributed transaction (একসাথে commit সম্ভব না), আর operations এর বোঝা (অনেক deploy, monitoring, debug কঠিন)। সাথে service দের মধ্যে data join কঠিন।
Modular monolith কী, আর কেন প্রায়ই ভালো শুরু?
একটা deploy করা app, কিন্তু ভেতরে কঠোর সীমানার module, যারা শুধু public interface দিয়ে কথা বলে আর একে অপরের data সরাসরি ছোঁয় না। Monolith এর সহজতা পাওয়া যায়, আবার পরে দরকার হলে কোনো module কে আলাদা service বানানো সহজ।
"Distributed monolith" কী?
এমন microservice system যেখানে service গুলো এত জড়ানো যে একসাথে বদলাতে আর deploy করতে হয়। Microservice এর জটিলতা আছে কিন্তু স্বাধীনতার লাভ নেই, সাধারণত ভুল সীমানা টানার ফল।
Service ভাগ করার ঠিক ভিত্তি কী?
ব্যবসার ক্ষমতা বা bounded context (order, payment, catalog), technical স্তর না (database service, validation service)।
চিহ্ন দিলে sidebar আর রোডম্যাপে এই অধ্যায়ের station ভরে যাবে।