Tizim dizayni kursi · 5-mavzu
TuzdiDinMuhammad

Load Balancing — masshtab va ishonchlilik

Bir nechta bir xil server oldiga yuk taqsimlovchi qo‘yib, gorizontal masshtab va yuqori ishonchlilikka erishamiz. Noldan boshlab algoritmlar, health check, Nginx+NestJS implementatsiyasi, eng muhim ilova qoidasi — stateless bo‘lish va balanserning o‘zini SPOF qilmaslikni o‘rganamiz.

Stack: Nginx · NestJS · RedisMavzular: L4/L7 · health check · stateless · stickyBog‘liq: 4-mavzu (Caching/Redis)

Bu darsda nima bor

1–4-qismlar load balancing’ni noldan quradi: nega kerak, L4/L7, algoritmlar va Nginx+NestJS implementatsiya (health check, graceful shutdown). 5–6-qismlar — eng muhim amaliy masalalar: serverni stateless qilish, session/WebSocket, LB turlari va balanserni SPOF qilmaslik. 7-qism qachon kerakligi va amaliy qoidalar.

01
Load Balancing · qism 1

Nega kerak — sig‘im va SPOF

🚦

Oddiy o‘xshatish: do‘konda bitta kassa o‘rniga bir nechta kassa va navbatni taqsimlovchi xodim. U har mijozni eng bo‘sh kassaga yo‘naltiradi — navbat tez ketadi, bitta kassir kasal bo‘lsa, qolganlari ishlayveradi.

Bitta NestJS serverni tasavvur qil: u sekundiga ma’lum miqdordagi so‘rovni ko‘taradi. Trafik o‘sgan sayin og‘riq boshlanadi.

Muammo (ikki tomonlama)

1. Sig‘im chegarasi: bitta server cheksiz so‘rovni ko‘tara olmaydi — CPU, RAM va ulanishlar tugaydi, javoblar sekinlashadi, server cho‘kadi. Uni kuchaytirish (vertikal) ma’lum chegaragacha ishlaydi va qimmat.
2. Yagona zaiflik nuqtasi (SPOF): bitta server — bitta nuqta. U o‘chsa (yoki deploy paytida qayta ishga tushsa) — butun sayt o‘chadi.

Yechim — yukni taqsimlash

Ilovaning bir nechta bir xil nusxasini (instance) ishga tushirib, ularning oldiga yuk taqsimlovchi (load balancer) qo‘yamiz. Balanser kelayotgan so‘rovlarni serverlar o‘rtasida teng taqsimlaydi. Bu — gorizontal masshtablash (server qo‘shib o‘sish) va yuqori ishonchlilikning asosi.

Vertikal vs Gorizontal

Vertikal = bitta serverni kuchaytirish (ko‘proq CPU/RAM) — oson, lekin chegarasi bor va SPOF qoladi. Gorizontal = ko‘proq server qo‘shish — deyarli cheksiz va SPOF’ni yo‘qotadi. Load balancer aynan gorizontalni mumkin qiladi.

02
Load Balancing · qism 2

Asosiy g‘oya va L4/L7

Load balancer mijozlar bilan serverlar o‘rtasida turadi: barcha so‘rov unga keladi, u esa ularni sog‘lom serverlarga uzatadi.

Mijozlar Load Balancer+ health check Server 1 ✓ Server 2 ✓ Server 3 ✕ (o‘lik)
Bitta kirish nuqtasi → sog‘lom serverlarga taqsimlaydi, o‘likni chetlab o‘tadi

Bu bir vaqtning o‘zida ikki muammoni hal qiladi: masshtab (server qo‘shib o‘sasan) va ishonchlilik (biri o‘lsa, balanser uni navbatdan chiqaradi, qolganlari ishlaydi).

L4 va L7 — balanser qaysi darajada ishlaydi

L4 (transport)L7 (ilova / HTTP)
Nimaga qaraydiIP va port (TCP/UDP)HTTP — URL, header, cookie
TezlikJuda tez (ichini ko‘rmaydi)Sekinroq (paketni o‘qiydi)
ImkoniyatOddiy taqsimlashYo‘l bo‘yicha marshrut, SSL termination, header asosida
MisolAWS NLB, HAProxy (TCP)Nginx, AWS ALB, Envoy, Traefik
Qaysi biri?

Veb-ilova uchun deyarli har doim L7 (HTTP bo‘yicha aqlli marshrut, SSL, header). Juda yuqori hajmli, oddiy TCP trafik uchun (yoki o‘zing protokol darajasida boshqarsang) — L4.

03
Load Balancing · qism 3

Algoritmlar va health check

Balanser so‘rovni qaysi serverga yuborishini algoritm bilan hal qiladi. Eng muhimlari:

AlgoritmQanday ishlaydiQachon
Round RobinNavbatma-navbat: 1→2→3→1…Serverlar bir xil quvvatda, so‘rovlar bir xil og‘irlikda
Weighted RRKuchli serverga ko‘proq (weight)Serverlar har xil quvvatda
Least ConnectionsEng kam band (ochiq ulanishi kam) servergaSo‘rovlar turli muddatli (ba’zisi uzoq)
IP HashMijoz IP’si bo‘yicha doim bir servergaSession affinity (sticky) kerak bo‘lganda
Least Response TimeEng tez javob beradigan servergaServer yuki noaniq, kechikishni minimallashtirish
Load Balancer 1 2 3 Server 1 Server 2 Server 3 Round Robin: navbatma-navbat teng taqsimlash
Round Robin — eng oddiy va keng tarqalgan boshlang‘ich tanlov

Health check — o‘lik serverni chetlab o‘tish

Balanser doimo serverlarni tekshirib turadi. Javob bermaganini navbatdan chiqaradi, tuzalganda qaytaradi. Ikki xil: aktiv (balanser /healthga so‘rov yuborib turadi) va passiv (oddiy so‘rovlardagi xatolarni kuzatadi). Health check bo‘lmasa — balanser o‘lik serverga ham so‘rov yuborib, foydalanuvchiga xato qaytaradi.

04
Load Balancing · qism 4

Implementatsiya (Nginx + NestJS)

nginx · terminus · graceful

Load balancing ko‘proq infratuzilma ishi, lekin ilova ham unga moslashishi shart. Uch qism: balanser konfiguratsiyasi (Nginx), ilovaning health endpointi va graceful shutdown.

1 · Nginx — upstream va proxy

# nginx.conf — eng keng tarqalgan L7 balanser
upstream app_servers {
    least_conn;                              # eng kam band serverga
    server 10.0.0.1:3000 max_fails=3 fail_timeout=10s;   # passiv health check
    server 10.0.0.2:3000;
    server 10.0.0.3:3000 weight=2;           # kuchliroq server -> 2x yuk
}
server {
    listen 80;
    location / {
        proxy_pass http://app_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # haqiqiy IP
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

2 · NestJS health endpoint

Balanser serverning tirikligini shu yerdan biladi. Muhim: u shunchaki "200 OK" qaytarmasin — haqiqiy bog‘liqliklarni (baza, Redis) tekshirsin:

// NestJS health endpoint — balanser shu yerga so'rov yuboradi (@nestjs/terminus)
@Controller('health')
export class HealthController {
  constructor(
    private health: HealthCheckService,
    private db: PrismaHealthIndicator,
    private prisma: PrismaService,
  ) {}

  @Get()
  @HealthCheck()
  check() {
    // server "sog'lom" deyishi uchun bazaga ham ulana olishi kerak
    return this.health.check([
      () => this.db.pingCheck('database', this.prisma),
    ]);
  }
}

3 · Graceful shutdown — uzilishsiz deploy

Deploy paytida server qayta ishga tushadi. Agar u so‘rovlar o‘rtasida birdan o‘chsa — foydalanuvchilar xato oladi. Graceful shutdown buni hal qiladi:

// main.ts — uzilishsiz deploy uchun graceful shutdown
async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  app.set('trust proxy', 1);     // LB orqasida -> req.ip haqiqiy mijoz IP'si bo'lsin
  app.enableShutdownHooks();     // SIGTERM/SIGINT'ni ushlaydi

  await app.listen(3000);
}

// onModuleDestroy / onApplicationShutdown hook'ida:
//  1) readiness'ni "unhealthy" qil -> LB yangi so'rov yubormaydi (drain)
//  2) ishdagi so'rovlarni tugat
//  3) DB/Redis ulanishlarini toza yop
// Shunda deploy/restart paytida BIRORTA so'rov yo'qolmaydi.
trust proxy nega kerak

LB orqasida har so‘rov balanser IP’sidan kelgandek ko‘rinadi. X-Forwarded-For header’iga ishonish (trust proxy) orqali ilova haqiqiy mijoz IP’sini oladi — rate limiting, logging va xavfsizlik uchun zarur.

05
Chuqurlashtirilgan mavzu

Stateless bo‘lish va session

sticky · redis · JWT · WS adapter
🎭

Eng muhim ilova-tomon qoidasi: balanser so‘rovlarni turli serverlarga yuboradi. Demak bir foydalanuvchining ketma-ket so‘rovlari har xil serverga tushishi mumkin. Server "biror narsani eslab qolsa" — muammo boshlanadi.

Muammo — holatni (state) serverda saqlash

Foydalanuvchi 1-serverga login qildi, session uning xotirasida saqlandi. Keyingi so‘rov 2-serverga tushdi — u session’ni bilmaydi, foydalanuvchi tizimdan chiqib ketgandek bo‘ladi. Yoki server o‘chsa — undagi barcha session yo‘qoladi.

Yechim 1 · Sticky session (session affinity)

Bitta mijozni doim bitta serverga bog‘lash (IP hash yoki cookie orqali). Oddiy, lekin kamchiliklari bor: yuk notekis taqsimlanadi va o‘sha server o‘chsa — session baribir yo‘qoladi.

Yechim 2 · Stateless server (afzal yo‘l)

Eng to‘g‘ri yo‘l — serverlarni holatsiz (stateless) qilish: hech narsani xotirada saqlamasin. Session’ni tashqi umumiy joyga (Redis) chiqarasan yoki stateless JWT ishlatasan. Shunda istalgan server istalgan so‘rovni qabul qila oladi:

// MUAMMO: session serverning XOTIRASIDA saqlansa -> LB boshqa serverga yuborganda
// foydalanuvchi "tizimdan chiqib ketgan"dek bo'ladi (session o'sha serverda qoldi).

// YECHIM 1: session'ni tashqi umumiy joyga (Redis) chiqarish
import RedisStore from 'connect-redis';
app.use(session({
  store: new RedisStore({ client: redis }),   // session Redis'da, hamma server ko'radi
  secret: process.env.SESSION_SECRET,
  resave: false, saveUninitialized: false,
}));

// YECHIM 2 (ko'proq ishlatiladi): stateless JWT — server hech narsa saqlamaydi,
// token o'zida ma'lumotni olib yuradi -> istalgan server tekshira oladi.
Server 1 Server 2 Server 3 Redis (session) Holat umumiy joyda → istalgan server xizmat qiladi
Stateless: session Redis’da → istalgan server istalgan so‘rovni oladi

WebSocket holati — alohida e’tibor

WebSocket ulanishi uzoq yashaydi va bitta serverga bog‘lanadi (sticky kerak). Lekin bir serverdagi emit boshqa serverdagi mijozlarga yetishi uchun umumiy "backplane" — masalan Socket.IO Redis adapteri — zarur:

// WebSocket masshtablash: ulanish bitta serverga "yopishadi". Bir serverdagi
// emit boshqa serverdagi clientlarga yetishi uchun Redis "backplane" kerak.
import { createAdapter } from '@socket.io/redis-adapter';

const pub = createClient({ url: 'redis://localhost:6379' });
const sub = pub.duplicate();
await Promise.all([pub.connect(), sub.connect()]);
io.adapter(createAdapter(pub, sub));   // endi broadcast HAMMA server bo'ylab ishlaydi
06
Chuqurlashtirilgan mavzu

LB turlari va balanser SPOF

cloud LB · floating IP

"Load balancer" — bitta narsa emas; bir necha turi va joyi bor:

TurQayerdaXususiyat
DNS-basedDNS darajasida (bir nomga ko‘p IP)Oddiy, lekin health check zaif, DNS kesh muammosi
Reverse proxy (L7)Serverlar oldida (Nginx/HAProxy/Envoy)Eng keng tarqalgan, aqlli marshrut + SSL
Cloud LBBoshqariladigan xizmat (AWS ALB/NLB)HA o‘zida, autoscaling bilan integratsiya
Client-sideMijoz serverlar ro‘yxatidan o‘zi tanlaydiMikroservis/gRPC + service discovery bilan
Global (GeoDNS/Anycast)Mintaqalar bo‘ylabFoydalanuvchini eng yaqin DC’ga yo‘naltiradi
Balanserning o‘zi SPOF bo‘lmasin

Diqqat: agar butun trafik bitta balanserdan o‘tsa — endi u yagona zaiflik nuqtasi. Bu mantiqsiz: serverlarni zaxiraladik, lekin balanser o‘lsa baribir hammasi to‘xtaydi.

Yechim — balanserni ham zaxiralash

Ikki (yoki ko‘p) balanser + ular orasida floating (virtual) IP: aktiv balanser o‘lsa, IP zaxiradagisiga o‘tadi (keepalived/VRRP). Yoki boshqariladigan cloud LB — HA allaqachon ichida. Shuning uchun productionda ko‘pchilik cloud LB ishlatadi.

Mijoz Floating IPvirtual LB aktiv ✓ LB zaxira Server'lar
Zaxira balanser + floating IP: balanser o‘lsa ham trafik uzilmaydi
07
Qaror

Qachon kerak va amaliy qoidalar

Load balancing — deyarli har bir jiddiy production tizimida bor. Lekin to‘g‘ri ishlashi uchun ilova ham qoidalarga rioya qilishi kerak.

Qachon kerak
  • Trafik bitta server imkonidan oshganda
  • Yuqori ishonchlilik (HA) zarur bo‘lganda
  • Uzilishsiz (zero-downtime) deploy kerak bo‘lganda
  • Ya’ni — deyarli har bir production veb-ilovada
Ilova rioya qilishi shart
  • Stateless bo‘lish — holatni xotirada saqlamaslik
  • Yaxshi health check (haqiqiy bog‘liqlikni tekshir)
  • Deploy’da graceful drain
  • So‘rovlar idempotent — retry xavfsiz bo‘lsin
Amaliy qoidalar

1. Avval stateless qil — bu hamma narsaning asosi. Session → Redis/JWT, fayllar → S3/R2 (lokal diskka emas).

2. Health check’ni o‘ylab yoz: juda yengil bo‘lsa — o‘lik serverga so‘rov ketadi; juda og‘ir/sezgir bo‘lsa — soppa-sog‘ serverni "o‘lik" deb chiqarib, flapping (kirib-chiqib turish) keltiradi.

3. Deploy’da serverni drain qil: avval health’ni "unhealthy" qilib LB’dan chiqar, ishdagilarni tugat, keyin o‘chir.

4. Retry’lar uchun so‘rovlar idempotent bo‘lsin (14-mavzu): balanser/mijoz qayta yuborsa, ikki marta bajarilmasin.

08
Yakuniy

Eslab qolish kerak bo‘lgan 5 jumla

  • Load balancer — bir nechta bir xil server oldida turib, so‘rovlarni teng taqsimlaydi: masshtab + ishonchlilik (SPOF yo‘qoladi).
  • L7 (HTTP, aqlli marshrut) — veb uchun standart; L4 (TCP, tez) — oddiy yuqori hajm uchun. Algoritm: ko‘pincha round robin yoki least connections.
  • Health check o‘lik serverni chetlab o‘tadi; graceful shutdown uzilishsiz deploy beradi; trust proxy haqiqiy IP’ni beradi.
  • Eng muhim ilova qoidasi — stateless bo‘lish. Session → Redis/JWT. WebSocket → sticky + Redis adapter.
  • Balanserning o‘zi SPOF bo‘lmasligi uchun — zaxira LB + floating IP yoki boshqariladigan cloud LB.

Bu mavzuning Deep/Senior qatlami (consistent hashing/ring hash, Envoy va service mesh, connection draining nozikliklari, health check flapping sozlash, autoscaling, global LB/Anycast) kerak bo‘lsa — ayting.

Yoki keyingi mavzu: “6-mavzu: Database Sharding” — ma’lumotlar bazasini masshtablash.