পাঠ ৪৫ · ৫৭-এর মধ্যে · মডিউল ১১
Home / Courses / Cloud Computing & DevOps / সার্ভারলেস আর্কিটেকচার গভীরভাবে

সার্ভারলেস আর্কিটেকচার গভীরভাবে

Serverless architecture deep dive
৮ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • একটি সার্ভারলেস আর্কিটেকচার কীভাবে অনেক ছোট, ইভেন্ট-ট্রিগার্ড ফাংশন দিয়ে গঠিত হয়
  • API গেটওয়ে → ফাংশন → ম্যানেজড স্টোর — সাধারণ সার্ভারলেস আর্কিটেকচার প্যাটার্ন এবং BaaS ধারণা
  • কেন স্টেটলেসনেস একটি সার্ভারলেস ফাংশনের জন্য একটি হার্ড রিকোয়ারমেন্ট, ঐচ্ছিক নয়
  • Python দিয়ে একটি ইভেন্ট-ডিসপ্যাচ সিমুলেশন — বিভিন্ন ইভেন্ট টাইপ বিভিন্ন ফাংশনকে স্বাধীনভাবে ট্রিগার করা

১ · L07-এর উপর ভিত্তি করে — একটি সম্পূর্ণ আর্কিটেকচার হিসেবে সার্ভারলেস

L07-এ আমরা FaaS (Function as a Service)-কে একটি একক কম্পিউট অপশন হিসেবে পরিচয় করিয়েছিলাম — একটি ফাংশন লিখুন, প্রোভাইডার সব ইনফ্রাস্ট্রাকচার সামলায়। এই পাঠে আমরা দেখব কীভাবে একটি সম্পূর্ণ অ্যাপ্লিকেশন এই একক ফাংশনগুলোর সমন্বয়ে একটি পূর্ণাঙ্গ আর্কিটেকচার হিসেবে গঠিত হতে পারে — একটি একক মনোলিথ সার্ভারের বদলে, অনেকগুলো ছোট, স্বাধীন, একক-উদ্দেশ্যমূলক ফাংশন, প্রতিটি একটি নির্দিষ্ট ইভেন্ট (একটি HTTP রিকোয়েস্ট, স্টোরেজে একটি ফাইল আপলোড, একটি কিউতে একটি মেসেজ আসা, একটি নির্ধারিত টাইমার) দ্বারা ট্রিগার হয়ে চলে, তারপর সম্পূর্ণ হয়ে বন্ধ হয়ে যায়।

২ · সাধারণ আর্কিটেকচার প্যাটার্ন — API গেটওয়ে → ফাংশন → ম্যানেজড স্টোর

একটি সাধারণ সার্ভারলেস ওয়েব ব্যাকএন্ড এইভাবে গঠিত হয় — একটি API গেটওয়ে ইনকামিং HTTP রিকোয়েস্টগুলো সঠিক ফাংশনে রুট করে (system-design কোর্সের API গেটওয়ে ধারণার সরাসরি প্রয়োগ) → সেই ফাংশন প্রয়োজনীয় লজিক এক্সিকিউট করে → এবং যেকোনো স্থায়ী ডেটা একটি ম্যানেজড ডেটাবেস/স্টোরেজ সার্ভিসে (L10) পড়ে/লেখে। পুরো "ব্যাকএন্ড" — গেটওয়ে, ফাংশন, ডেটাবেস, প্রায়ই ম্যানেজড অথেন্টিকেশনও — সম্পূর্ণভাবে ম্যানেজড সার্ভিস দিয়ে গঠিত, একসাথে গ্লু করা ফাংশন দিয়ে সংযুক্ত — এই কম্বিনেশনকে কখনো কখনো BaaSBackend as a Serviceম্যানেজড অথ, ডেটাবেস ও স্টোরেজ সার্ভিসের সমন্বয়ে গঠিত একটি ব্যাকএন্ড, যেখানে ডেভেলপার শুধু ফাংশন/গ্লু-লজিক লেখেন — অন্তর্নিহিত ইনফ্রাস্ট্রাকচারের কিছুই ম্যানেজ করেন না। (Backend as a Service) বলা হয়।

ক্লায়েন্ট API গেটওয়ে রুটিং ফাংশন স্টেটলেস DB
ক্লায়েন্ট → API গেটওয়ে → স্টেটলেস ফাংশন → ম্যানেজড ডেটাবেস — কোনো ধাপেই আপনাকে সার্ভার প্রভিশন করতে হয় না।

৩ · স্টেটলেসনেস — একটি হার্ড রিকোয়ারমেন্ট

একটি সাধারণ, সবসময়-চালু সার্ভারে একটি প্রোগ্রাম মেমরিতে স্টেট রাখতে পারে (যেমন একটি ইন-মেমরি ক্যাশ বা কাউন্টার) যা কল থেকে কলে টিকে থাকে। কিন্তু একটি সার্ভারলেস ফাংশনের ক্ষেত্রে এটি নির্ভরযোগ্য নয় — যেহেতু যেকোনো ইনভোকেশন সম্পূর্ণ নতুন, তাজা এক্সিকিউশন এনভায়রনমেন্টে চলতে পারে (বিশেষ করে L46-এ দেখব কোল্ড স্টার্টের ক্ষেত্রে), ফাংশন অবশ্যই ইন-মেমরি স্টেটের উপর নির্ভর না করে চলতে হবে — প্রয়োজনীয় যেকোনো স্টেট একটি বাইরের স্টোরে (ডেটাবেস, ক্যাশ সার্ভিস) রাখতে হবে। এটি system-design কোর্সের স্টেটলেস-সার্ভিস-ডিজাইন নীতিরই একটি কঠোর প্রয়োগ — সার্ভারলেসে এটি ঐচ্ছিক নয়, বাধ্যতামূলক।

Python
# ইভেন্ট-ট্রিগার্ড সার্ভারলেস ফাংশন চেইন — প্রতিটি ফাংশন স্টেটলেস, শুধু ইনপুট payload থেকে কাজ করে
def resize_image(payload):
    return f"ছবি রিসাইজ করা হলো: {payload['file_name']} → thumbnail তৈরি হলো"

def cleanup_temp_files(payload):
    return f"cleanup ফাংশন চললো: {payload['deleted_count']}টি অস্থায়ী ফাইল মোছা হলো"

def send_welcome_email(payload):
    return f"স্বাগতম ইমেইল পাঠানো হলো: {payload['email']}"

# event_type -> handler ফাংশন ম্যাপিং, একটি ইভেন্ট বাসের সরলীকৃত রূপ
event_router = {
    "file_uploaded": resize_image,
    "schedule_tick": cleanup_temp_files,
    "user_signed_up": send_welcome_email,
}

def emit_event(event_type, payload):
    """একটি ইভেন্ট বাস — event_type অনুযায়ী সঠিক সার্ভারলেস ফাংশনে dispatch করে, একে অপরের থেকে স্বাধীনভাবে।"""
    handler = event_router.get(event_type)
    if handler is None:
        return f"কোনো হ্যান্ডলার নিবন্ধিত নেই: {event_type}"
    return handler(payload)

events = [
    ("file_uploaded", {"file_name": "vacation.jpg"}),
    ("schedule_tick", {"deleted_count": 14}),
    ("user_signed_up", {"email": "user@example.com"}),
]

for event_type, payload in events:
    result = emit_event(event_type, payload)
    print(f"[{event_type}] {result}")

    
লক্ষ্য করুন প্রতিটি ফাংশন সম্পূর্ণ স্বাধীন — resize_image শুধু file_name জানে, send_welcome_email শুধু email জানে। কোনো ফাংশনই অন্য কোনো ফাংশনের মেমরি অবস্থা বা আগের কোনো কলের উপর নির্ভর করে না — প্রতিটি কল একটি সম্পূর্ণ স্বয়ংসম্পূর্ণ ইউনিট, যা ঠিক স্টেটলেস সার্ভারলেস ডিজাইনের প্রতিফলন।
মূল কথা · Key takeaway

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

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

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ একজন ডেভেলপার যদি একটি সার্ভারলেস ফাংশনে একটি গ্লোবাল ভ্যারিয়েবল ব্যবহার করে একটি কাউন্টার বাড়ানোর চেষ্টা করেন (মনে করে এটি সবসময়-চালু সার্ভারের মতো আচরণ করবে), তাহলে কী ভুল হতে পারে?

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

প্র ০২ BaaS-এর সাথে PaaS (L01-এ শেখা)-এর পার্থক্য কী — উভয়ই কি "কম ম্যানেজমেন্ট" প্রস্তাব করে না?

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

প্র ০৩ একটি অ্যাপ্লিকেশনকে অনেক ছোট, একক-উদ্দেশ্যমূলক ফাংশনে ভাঙার একটি সম্ভাব্য অসুবিধা কী হতে পারে?

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

অনুশীলন

  1. চিন্তা করুন: উপরের কোডে emit_event("payment_failed", {...}) কল করলে কী ফলাফল আসবে, এবং কেন এই বিহেভিয়ার একটি বাস্তব সিস্টেমের জন্য নিরাপদ ডিজাইন?

    এটি "কোনো হ্যান্ডলার নিবন্ধিত নেই: payment_failed" বার্তা ফেরত দেবে, কারণ event_router-এ এই key নেই এবং .get() None ফেরত দেয়। এটি নিরাপদ ডিজাইন কারণ একটি অনিবন্ধিত ইভেন্ট টাইপ সাইলেন্টলি উপেক্ষা করা বা ক্র্যাশ করার বদলে স্পষ্টভাবে জানানো হচ্ছে — একটি বাস্তব সিস্টেমে এটি লগ/অ্যালার্ট (M10) হিসেবে পাঠানো যেত, যাতে অনুপস্থিত হ্যান্ডলার দ্রুত ধরা পড়ে।

  2. পরীক্ষা করুন: event_router-এ একটি নতুন এন্ট্রি যোগ করুন — "order_placed": lambda payload: f"অর্ডার প্রসেসিং শুরু: {payload['order_id']}" — এবং events তালিকায় একটি সংশ্লিষ্ট ইভেন্ট যোগ করে চালান।

    নতুন ইভেন্ট টাইপ স্বয়ংক্রিয়ভাবে সঠিক হ্যান্ডলারে dispatch হবে, ঠিক বিদ্যমান তিনটির মতোই — কারণ emit_event-এর কোনো লজিক কোনো নির্দিষ্ট ইভেন্ট টাইপ হার্ডকোড করা নেই, এটি সবসময় event_router dict থেকে লুকআপ করে। এটি দেখায় নতুন ইভেন্ট-ট্রিগার্ড ফাংশন যোগ করা কতটা সহজ, ঠিক যেমন বাস্তব সার্ভারলেস প্ল্যাটফর্মে নতুন একটি ফাংশন+ট্রিগার যোগ করা হয়।

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

আগের পাঠ
L44 · অ্যালার্টিং ও অন-কল/SRE প্র্যাকটিস