Scalability: Vertical vs Horizontal

বড় machine নাকি বেশি machine

রোডম্যাপের মাস ৩পড়তে প্রায় ৯ মিনিট

তোমার app চালু হলো, user বাড়ছে। একদিন দুপুরে সব ধীর হয়ে গেল, কিছু request timeout হচ্ছে। Server আর পারছে না। এখন দুইটা পথ: server টাকে বড় করো, নাকি আরও server যোগ করো। এটাই scaling এর মূল প্রশ্ন, আর system design এর প্রায় সব কিছু এখান থেকে শুরু।

#Vertical scaling: বড় machine

২ CPU আর ৪ GB RAM এর server থেকে ১৬ CPU আর ৬৪ GB RAM এর server এ যাওয়া। একে বলে scale up।

সুবিধা:

  • Code এ কিছু বদলাতে হয় না
  • সহজ: একটা machine, একটা জায়গায় সব
  • Database এর জন্য প্রায়ই প্রথম আর সবচেয়ে কার্যকর পদক্ষেপ

অসুবিধা:

  • সীমা আছে। সবচেয়ে বড় machine এর চেয়ে বড় কিছু কেনা যায় না।
  • দাম দ্রুত বাড়ে। দ্বিগুণ শক্তির machine এর দাম প্রায়ই দ্বিগুণের বেশি।
  • একটাই machine মানে একটাই ভাঙার জায়গা (single point of failure)। ওটা বন্ধ হলে সব বন্ধ।
  • বড় করতে প্রায়ই restart লাগে, মানে কিছুক্ষণ বন্ধ।

#Horizontal scaling: বেশি machine

একটা বড় server এর বদলে অনেকগুলো সাধারণ server, সামনে একটা load balancer যে request ভাগ করে দেয়। একে বলে scale out।

Vertical (scale up) ২ CPU ৩২ CPU ১২৮ GB RAM Horizontal (scale out) Load Balancer ২ CPU ২ CPU ২ CPU ২ CPU দরকার হলে আরও যোগ, একটা নষ্ট হলে বাকিরা চালায়
বাম দিকে machine বড় হচ্ছে। ডান দিকে machine এর সংখ্যা বাড়ছে।

সুবিধা:

  • প্রায় সীমাহীন: আরও machine যোগ করতে থাকো
  • একটা নষ্ট হলে বাকিরা চালিয়ে যায় (high availability)
  • চাপ অনুযায়ী বাড়ানো-কমানো যায় (autoscaling): রাতে ২টা, দুপুরে ১০টা
  • Update দেওয়া যায় একটা একটা করে, বন্ধ না করে (rolling deploy)

অসুবিধা:

  • জটিলতা: load balancer লাগে, অনেক machine চালানো আর দেখা লাগে
  • Code কে stateless হতে হবে (নিচে বিস্তারিত)
  • Database এর ক্ষেত্রে অনেক কঠিন, কারণ data ভাগ করতে হয় (Sharding)

#কোনটা কখন

পরিস্থিতি পরামর্শ
শুরুর app, অল্প user একটা মাঝারি server, scaling এর চিন্তা পরে
App server এ চাপ Horizontal। App server সহজেই stateless করা যায়।
Database এ চাপ প্রথমে vertical (বড় machine), তারপর read replica, cache, শেষে sharding
হঠাৎ spike (sale, result প্রকাশ) Horizontal + autoscaling, সাথে cache আর queue

বাস্তবে প্রায় সব বড় system দুটোই মেশায়: app server horizontal, database প্রথমে vertical।

#Stateless: horizontal scaling এর শর্ত

ধরো user Rahim login করলো। তার login এর তথ্য (session) রাখা হলো server ১ এর memory তে। পরের request এ load balancer তাকে পাঠালো server ২ এ। Server ২ জানে না Rahim কে, তাই আবার login চাইলো। 😕

Stateful (সমস্যা) Rahim Server ১ memory: Rahim এর session Server ২ Rahim কে চিনি না! Stateless (সমাধান) Rahim Server ১ Server ২ Redis / DB / JWT
Stateless server নিজের ভেতরে user এর কোনো তথ্য রাখে না। তাই যেকোনো server যেকোনো request সামলাতে পারে।

Stateless মানে server নিজের memory বা disk এ এমন কিছু রাখে না যা পরের request এ লাগবে। সব "state" থাকে বাইরে:

State কোথায় রাখবে
Login session JWT token (client এর কাছে) বা Redis
Upload করা file Object storage (S3 ধরনের), server এর disk এ না
Cart, অস্থায়ী data Redis বা database
Cache Redis (প্রতিটা server এর নিজস্ব memory cache এ না, অন্তত গুরুত্বপূর্ণগুলো)
Background কাজ Queue (Celery + Redis/RabbitMQ)

#Sticky session: শর্টকাট, কিন্তু সমাধান না

Load balancer কে বলা যায় "Rahim কে সবসময় server ১ এ পাঠাও" (sticky session)। এতে stateful code ও চলে। কিন্তু server ১ বন্ধ হলে Rahim এর session হারায়, আর load সমানভাবে ভাগ হয় না। এটা পুরনো system চালানোর জন্য অস্থায়ী উপায়, নতুন design এ stateless ই লক্ষ্য। (WebSocket এর মতো স্থায়ী connection এর ক্ষেত্রে অবশ্য একটা নির্দিষ্ট server এর সাথে লেগে থাকা স্বাভাবিক।)

#Autoscaling

Cloud এ নিয়ম দেওয়া যায়: "CPU গড়ে ৭০% এর বেশি ৫ মিনিট থাকলে আরেকটা server যোগ করো, ৩০% এর নিচে থাকলে একটা কমাও।"

মনে রাখার বিষয়:

  • নতুন server চালু হতে সময় লাগে (কয়েক সেকেন্ড থেকে কয়েক মিনিট)। হঠাৎ ১০ গুণ traffic এলে autoscaling ধরতে পারার আগেই ভেঙে পড়তে পারে। জানা ঘটনার (sale, খেলা) আগে থেকে বাড়িয়ে রাখো।
  • নিচের অংশ ও যেন পারে। App server ২০টা হলো, কিন্তু database একটাই। ২০টা server এর সব connection database কে ডুবিয়ে দিতে পারে। Scale করলে bottleneck শুধু সরে যায়, চলে যায় না।
  • সর্বোচ্চ সীমা দাও। না হলে কোনো bug বা আক্রমণে হাজার server চালু হয়ে বিশাল bill আসতে পারে।

#Bottleneck খোঁজা

Scaling শুরুর আগে জানো আসলে কোথায় আটকাচ্ছে। ভুল জায়গায় টাকা খরচ করা সাধারণ ভুল।

লক্ষণ সম্ভাব্য কারণ প্রথম চেষ্টা
App server এর CPU ১০০% ভারী হিসাব, অদক্ষ code Profile করো, তারপর horizontal scale
App CPU কম, কিন্তু response ধীর Database বা বাইরের API এর অপেক্ষা Query দেখো (EXPLAIN), index, cache
Database CPU বেশি ধীর query, index নেই, একই query বারবার Index, cache, read replica
Memory শেষ হচ্ছে Memory leak, বড় data একসাথে load Pagination, generator, leak খোঁজা
মাঝে মাঝে সব আটকে যায় Connection pool শেষ, lock, ধীর বাইরের API এ timeout নেই Timeout, pool size, circuit breaker

#অনুশীলন

#নিজেকে যাচাই করো

Vertical scaling এর দুইটা বড় সমস্যা কী?

একটা সর্বোচ্চ সীমা আছে (সবচেয়ে বড় machine এর চেয়ে বড় হয় না), আর একটাই machine হওয়ায় সেটা নষ্ট হলে পুরো system বন্ধ (single point of failure)। সাথে দামও দ্রুত বাড়ে।

Stateless server মানে কী, আর horizontal scaling এ কেন জরুরি?

Server নিজের memory বা disk এ পরের request এর জন্য দরকারি কোনো তথ্য রাখে না, সব রাখে বাইরে (Redis, database, token)। এতে load balancer যেকোনো request যেকোনো server এ পাঠাতে পারে, আর একটা server বন্ধ হলে কিছু হারায় না।

উপরের অনুশীলনের `login_attempts` code দুইটা server এ কী সমস্যা করবে?

প্রতিটা server এর আলাদা dict থাকবে। কেউ ৫ বার ভুল করলে হয়তো ৩ বার server ১ এ আর ২ বার server ২ এ গেছে, কোনোটাই ৫ এ পৌঁছায়নি, ফলে limit কাজ করবে না। Redis এর মতো shared store এ গোনা রাখতে হবে।

App server বাড়ালে সবসময় system দ্রুত হয় না কেন?

Bottleneck অন্য কোথাও থাকতে পারে, যেমন database। বেশি app server মানে database এ আরও বেশি চাপ, ফলে অবস্থা আরও খারাপ হতে পারে। আগে মেপে দেখতে হয় কোথায় আটকাচ্ছে।

চিহ্ন দিলে sidebar আর রোডম্যাপে এই অধ্যায়ের station ভরে যাবে।