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.
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.
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.
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 = 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.
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.
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 qaraydi | IP va port (TCP/UDP) | HTTP — URL, header, cookie |
| Tezlik | Juda tez (ichini ko‘rmaydi) | Sekinroq (paketni o‘qiydi) |
| Imkoniyat | Oddiy taqsimlash | Yo‘l bo‘yicha marshrut, SSL termination, header asosida |
| Misol | AWS NLB, HAProxy (TCP) | Nginx, AWS ALB, Envoy, Traefik |
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.
Algoritmlar va health check
Balanser so‘rovni qaysi serverga yuborishini algoritm bilan hal qiladi. Eng muhimlari:
| Algoritm | Qanday ishlaydi | Qachon |
|---|---|---|
| Round Robin | Navbatma-navbat: 1→2→3→1… | Serverlar bir xil quvvatda, so‘rovlar bir xil og‘irlikda |
| Weighted RR | Kuchli serverga ko‘proq (weight) | Serverlar har xil quvvatda |
| Least Connections | Eng kam band (ochiq ulanishi kam) serverga | So‘rovlar turli muddatli (ba’zisi uzoq) |
| IP Hash | Mijoz IP’si bo‘yicha doim bir serverga | Session affinity (sticky) kerak bo‘lganda |
| Least Response Time | Eng tez javob beradigan serverga | Server yuki noaniq, kechikishni minimallashtirish |
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.
Implementatsiya (Nginx + NestJS)
nginx · terminus · gracefulLoad 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.
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.
Stateless bo‘lish va session
sticky · redis · JWT · WS adapterEng 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.
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.
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
LB turlari va balanser SPOF
cloud LB · floating IP"Load balancer" — bitta narsa emas; bir necha turi va joyi bor:
| Tur | Qayerda | Xususiyat |
|---|---|---|
| DNS-based | DNS 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 LB | Boshqariladigan xizmat (AWS ALB/NLB) | HA o‘zida, autoscaling bilan integratsiya |
| Client-side | Mijoz serverlar ro‘yxatidan o‘zi tanlaydi | Mikroservis/gRPC + service discovery bilan |
| Global (GeoDNS/Anycast) | Mintaqalar bo‘ylab | Foydalanuvchini eng yaqin DC’ga yo‘naltiradi |
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.
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.
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
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.
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 proxyhaqiqiy 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.