পাঠ ১০ · ৫১-এর মধ্যে · মডিউল ৩
Home / Courses / System Design / ভার্টিক্যাল বনাম হরাইজন্টাল স্কেলিং

ভার্টিক্যাল বনাম হরাইজন্টাল স্কেলিং

Vertical vs horizontal scaling
৭ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

  • ভার্টিক্যাল ও হরাইজন্টাল স্কেলিং-এর সংজ্ঞা এবং মূল পার্থক্য
  • কেন ভার্টিক্যাল স্কেলিং-এর একটি হার্ড সিলিং আছে, হরাইজন্টালের নেই
  • Single point of failure ধারণা এবং হরাইজন্টাল স্কেলিং কীভাবে এটি এড়ায়
  • বাস্তবে কখন কোনটি বেছে নেওয়া হয়
  • Python দিয়ে দুই মডেলের ক্যাপাসিটি-বৃদ্ধি তুলনা করা একটি টেবিল বানানো

১ · ভার্টিক্যাল স্কেলিং — একই মেশিনকে শক্তিশালী করা

ভার্টিক্যাল স্কেলিংVertical Scaling (Scale Up)একটি একক মেশিনে বেশি CPU, RAM বা দ্রুততর ডিস্ক যোগ করে তার ক্যাপাসিটি বাড়ানো — মেশিনের সংখ্যা বাড়ে না, একটি মেশিনই শক্তিশালী হয়। সবচেয়ে সহজ সমাধান — যখন একটি সার্ভার ধীরগতির হয়ে যায়, তখন সেই একই সার্ভারে আরও শক্তিশালী CPU, বেশি RAM, বা দ্রুততর SSD যোগ করা। এতে কোনো কোড পরিবর্তনের দরকার নেই, ডেটা-ডিস্ট্রিবিউশন নিয়ে ভাবতে হয় না — শুধু একই মেশিন "আপগ্রেড" হয়।

কিন্তু এর দুটি বড় সীমাবদ্ধতা আছে। প্রথমত, একটি হার্ড সিলিং আছে — বাজারে বিদ্যমান সবচেয়ে শক্তিশালী মেশিনও একটি নির্দিষ্ট সীমার বেশি CPU কোর বা RAM দিতে পারে না, এবং সেই সিলিং-এ পৌঁছালে আর কোনো উপায় নেই। দ্বিতীয়ত, এটি একটি single point of failureSingle Point of Failureএকটি সিস্টেমের এমন একটি অংশ, যেটি ব্যর্থ হলে পুরো সিস্টেম বন্ধ হয়ে যায় — কোনো ব্যাকআপ বা বিকল্প না থাকায়। তৈরি করে — সেই একটি মেশিন ক্র্যাশ করলে, পুরো সিস্টেমই বন্ধ হয়ে যায়, কারণ কাজ চালিয়ে নেওয়ার মতো দ্বিতীয় কোনো মেশিন নেই।

২ · হরাইজন্টাল স্কেলিং — আরও মেশিন যোগ করা

হরাইজন্টাল স্কেলিংHorizontal Scaling (Scale Out)একটি মেশিনের ক্ষমতা বাড়ানোর বদলে আরও মেশিন যোগ করে মোট ক্যাপাসিটি বাড়ানো — কাজ একাধিক মেশিনের মধ্যে ভাগ করে দেওয়া হয়। পদ্ধতিতে একটি মেশিনকে শক্তিশালী করার বদলে আরও মেশিন যোগ করা হয়, এবং লোড ব্যালেন্সার (L11-এ বিস্তারিত) দিয়ে ট্র্যাফিক তাদের মধ্যে ভাগ করে দেওয়া হয়। এখানে কোনো বাস্তবিক সিলিং নেই — দরকার হলে ১০টি, ১০০টি, এমনকি ১০,০০০টি মেশিনও যোগ করা যায়। একটি মেশিন ক্র্যাশ করলেও বাকিগুলো কাজ চালিয়ে যেতে পারে — অনেক বেশি ফল্ট-টলারেন্ট।

কিন্তু এর মূল্য আছে — একাধিক মেশিনের মধ্যে ট্র্যাফিক ভাগ করতে লোড ব্যালেন্সিং লাগে, ডেটা যদি একাধিক মেশিনে ছড়িয়ে থাকে তাহলে কোন ডেটা কোথায় আছে তা ঠিক করতে ডেটা-ডিস্ট্রিবিউশন কৌশল (L13, L17-এ বিস্তারিত) লাগে, এবং সার্ভারগুলো স্টেটলেস (L12) হওয়া দরকার যাতে যেকোনো রিকোয়েস্ট যেকোনো মেশিন হ্যান্ডল করতে পারে।

ভার্টিক্যাল (Scale Up)
সহজ, দ্রুত সেটআপ। কিন্তু হার্ড সিলিং ও single point of failure।
হরাইজন্টাল (Scale Out)
কোনো বাস্তব সিলিং নেই, ফল্ট-টলারেন্ট। কিন্তু ব্যালেন্সিং ও ডিস্ট্রিবিউশন জটিলতা।
বাস্তবে কখন কোনটি

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

ভার্টিক্যাল — একটি মেশিন, ক্রমে শক্তিশালী ছোট মাঝারি সবচেয়ে বড় সিলিং! আর সম্ভব না হরাইজন্টাল — আরও মেশিন যোগ হতেই থাকে M1 M2 M3 M4 M5 ... যত দরকার তত মেশিন
ভার্টিক্যাল স্কেলিং একটি মেশিনকে শক্তিশালী করে সিলিং-এ থেমে যায়; হরাইজন্টাল স্কেলিং মেশিন যোগ করে চলতেই থাকে।

৩ · কোড দিয়ে দেখা — ক্যাপাসিটি বৃদ্ধির তুলনা

নিচের সিমুলেশনে ভার্টিক্যাল স্কেলিং প্রতিটি "ধাপ"-এ মেশিন আপগ্রেড করে, কিন্তু সবচেয়ে বড় মেশিনের ক্যাপাসিটি (১০,০০০ QPS) ছাড়িয়ে যেতে পারে না। হরাইজন্টাল স্কেলিং প্রতিটি ধাপে একটি নতুন ২,০০০-QPS-ক্যাপাসিটির মেশিন যোগ করে — কোনো সিলিং ছাড়াই।

Python
vertical_ceiling = 10_000  # সবচেয়ে বড় একক মেশিনের ম্যাক্সিমাম QPS সিলিং

def vertical_capacity(step):
    # ধাপে ধাপে বড় মেশিনে আপগ্রেড করা হচ্ছে, কিন্তু সিলিং-এর বেশি যেতে পারে না
    upgrade_path = [2_000, 4_000, 6_000, 8_000, 10_000]
    if step < len(upgrade_path):
        return upgrade_path[step]
    return vertical_ceiling  # সিলিং-এ আটকে গেছে

def horizontal_capacity(num_servers, per_server_capacity=2_000):
    # প্রতিটি নতুন মেশিন সমান ক্যাপাসিটি যোগ করে, কোনো সিলিং নেই
    return num_servers * per_server_capacity

print(f"{'ধাপ':<6}{'ভার্টিক্যাল (QPS)':<22}{'হরাইজন্টাল (QPS)':<20}")
print("-" * 48)
for step in range(7):
    v = vertical_capacity(step)
    h = horizontal_capacity(step + 1)
    print(f"{step + 1:<6}{v:<22,}{h:<20,}")

print("\nলক্ষ্য করুন — ভার্টিক্যাল ৫ম ধাপ থেকেই ১০,০০০-এ থমকে আছে,")
print("কিন্তু হরাইজন্টাল প্রতি ধাপে বাড়তেই থাকে, ৭ম ধাপে ভার্টিক্যালকে ছাড়িয়ে গেছে।")

    
টেবিলে দেখুন — ধাপ ৫-এ পৌঁছে ভার্টিক্যাল স্কেলিং ১০,০০০ QPS-এ থেমে যায় এবং ধাপ ৬, ৭-এও সেখানেই আটকে থাকে (কারণ আর বড় মেশিন নেই), অথচ হরাইজন্টাল স্কেলিং একই ধাপগুলোতে ১২,০০০ ও ১৪,০০০ QPS-এ পৌঁছে ভার্টিক্যালকে ছাড়িয়ে যায়। এই "প্লাটো বনাম অবিরাম বৃদ্ধি" প্যাটার্নটাই দুই কৌশলের মধ্যে মৌলিক পার্থক্য।
মূল কথা · Key takeaway

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

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

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

প্র ০১ একটি ডেটাবেস প্রায়ই ভার্টিক্যালি স্কেল করা তুলনামূলক সহজ, কিন্তু হরাইজন্টালি স্কেল করা (শার্ডিং) কঠিন কেন?

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

প্র ০২ "যত বড় মেশিন তত ভালো" — ভার্টিক্যাল স্কেলিং-এ কেন এই যুক্তি সবসময় ঠিক নয়?

দুটি কারণ। প্রথমত, খরচ রৈখিক (linear) ভাবে বাড়ে না — একটি মেশিনের ক্ষমতা দ্বিগুণ করতে প্রায়ই দামের চেয়ে বেশি বাড়তি খরচ লাগে (diminishing returns), যেখানে ৫টি ছোট মেশিন কেনা প্রায়ই সমান ক্যাপাসিটির একটি বিশাল মেশিনের চেয়ে সস্তা হতে পারে। দ্বিতীয়ত, এমনকি সবচেয়ে ব্যয়বহুল মেশিনও একটি single point of failure — সেটি ডাউন হলে পুরো সিস্টেম বন্ধ, যা শুধু বড় মেশিন কিনে সমাধান করা যায় না; সমাধানের জন্য একাধিক (হরাইজন্টাল) মেশিন লাগবেই।

প্র ০৩ একটি সিস্টেম স্টেটলেস (L12) না হলে হরাইজন্টাল স্কেলিং কেন কার্যত অসম্ভব হয়ে যায়?

হরাইজন্টাল স্কেলিং-এর পুরো ধারণাটাই এই অনুমানের উপর দাঁড়িয়ে যে, যেকোনো রিকোয়েস্ট যেকোনো মেশিন হ্যান্ডল করতে পারবে, যাতে লোড ব্যালেন্সার (L11) স্বাধীনভাবে ট্র্যাফিক ভাগ করতে পারে। যদি একটি নির্দিষ্ট ইউজারের ডেটা (যেমন তার সেশন) শুধু একটি নির্দিষ্ট সার্ভারের মেমরিতেই থাকে (স্টেটফুল), তাহলে সেই ইউজারের প্রতিটি রিকোয়েস্ট বাধ্যতামূলকভাবে সেই একই সার্ভারে পাঠাতে হবে — যা লোড ব্যালেন্সিং-এর নমনীয়তা নষ্ট করে এবং সেই সার্ভার ডাউন হলে ডেটা হারানোর ঝুঁকি তৈরি করে। L12-এ আমরা দেখব কীভাবে শেয়ার্ড স্টোরে স্টেট সরিয়ে নিয়ে এই সমস্যা সমাধান করা হয়।

অনুশীলন

  1. চিন্তা করুন: একটি ছোট স্টার্টআপ (মাসে ১,০০০ ইউজার) এবং একটি বড় সোশ্যাল মিডিয়া প্ল্যাটফর্ম (দৈনিক ১ কোটি ইউজার) — কোনটি ভার্টিক্যাল স্কেলিং দিয়ে শুরু করা উচিত এবং কেন?

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

  2. কোড এক্সটেন্ড করুন: উপরের কোড সেলে per_server_capacity-কে ৩,০০০ করুন এবং upgrade_path-এর শেষ মান ১২,০০০ করুন। কত নম্বর ধাপে হরাইজন্টাল ভার্টিক্যালকে ছাড়িয়ে যায়, হাতে হিসাব করে টেবিলের সাথে মিলিয়ে দেখুন।

    নতুন vertical_ceiling হবে ১২,০০০। হরাইজন্টাল ক্যাপাসিটি = ধাপ × ৩,০০০। ধাপ ৪ = ১২,০০০ (সমান), ধাপ ৫ = ১৫,০০০ (ছাড়িয়ে গেছে)। তাই ধাপ ৫ থেকেই হরাইজন্টাল ভার্টিক্যালের সিলিং ছাড়িয়ে যাবে — কোড চালিয়ে টেবিলে এটি নিশ্চিত করা যায়।

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

পূর্ববর্তী পাঠ
TCP বনাম UDP ও নেটওয়ার্ক লেয়ার বেসিকস