19-bo‘lim

Proksi, balanslovchi, CDN va P2P

To'g'ri va teskari proksi, yuk balanslash usullari, CDN nima uchun kechikishni kamaytiradi va P2P ning o'rni.

🕑 8 daqiqa o‘qish 📄 900 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Proksi - oradagi vositachi
  2. Yuk balanslash
  3. CDN - kechikishga qarshi yagona qurol
  4. P2P - serversiz almashinuv
  5. Xulosa

Shu paytgacha ikki tomon bor edi: mijoz va server. Haqiqiy tizimlarda ular orasida yana bir nechta qatlam turadi.

Proksi - oradagi vositachi #

Proksi ikki xil bo'ladi va ular butunlay boshqa vazifani bajaradi:

To'g'ri proksiTeskari proksi
Kim uchun ishlaydiMijoz uchunServer uchun
Kim biladiMijoz sozlaganMijoz bilmaydi
Odatiy vazifasiFiltrlash, kesh, anonimlikTLS, balanslash, himoya
MisolKorxona proksisinginx, Cloudflare

Teskari proksi bugun deyarli har bir saytda bor. Uni yozib ko'ramiz:

Python
import socket
import threading

ORQA_PORT = 9970      # haqiqiy ilova
PROKSI_PORT = 9971    # mijoz shu yerga ulanadi

# --- orqadagi ilova
orqa = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
orqa.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
orqa.bind(("127.0.0.1", ORQA_PORT))
orqa.listen(4)


def ilova():
    u, _ = orqa.accept()
    sorov = u.recv(4096).decode()
    yol = sorov.split(" ")[1]
    tana = f"ilova javobi, yo'l: {yol}".encode()
    u.sendall(b"HTTP/1.1 200 OK\r\nContent-Length: "
              + str(len(tana)).encode() + b"\r\n\r\n" + tana)
    u.close()


# --- proksi
proksi = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
proksi.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
proksi.bind(("127.0.0.1", PROKSI_PORT))
proksi.listen(4)

jurnal = []


def proksi_ishla():
    mijoz_ulanishi, kim = proksi.accept()
    sorov = mijoz_ulanishi.recv(4096)
    jurnal.append(sorov.split(b"\r\n")[0].decode())

    # Orqadagi ilovaga uzatamiz - va o'zimiz haqimizda sarlavha qo'shamiz
    qoshimcha = b"X-Forwarded-For: 127.0.0.1\r\n"
    uzatiladigan = sorov.replace(b"\r\n\r\n", b"\r\n" + qoshimcha + b"\r\n")

    orqaga = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    orqaga.connect(("127.0.0.1", ORQA_PORT))
    orqaga.sendall(uzatiladigan)

    javob = b""
    while True:
        b_ = orqaga.recv(4096)
        if not b_:
            break
        javob += b_
    orqaga.close()

    mijoz_ulanishi.sendall(javob)
    mijoz_ulanishi.close()


t1 = threading.Thread(target=ilova, daemon=True)
t2 = threading.Thread(target=proksi_ishla, daemon=True)
t1.start()
t2.start()

# --- mijoz PROKSIga ulanadi, ilovani umuman bilmaydi
m = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
m.settimeout(5)
m.connect(("127.0.0.1", PROKSI_PORT))
m.sendall(b"GET /darslik HTTP/1.1\r\nHost: sayt.uz\r\n\r\n")

javob = b""
while True:
    b_ = m.recv(4096)
    if not b_:
        break
    javob += b_
m.close()

t1.join()
t2.join()
orqa.close()
proksi.close()

sarlavhalar, tana = javob.decode().split("\r\n\r\n", 1)
print("mijoz ulangan port:", PROKSI_PORT)
print("javob birinchi qatori:", sarlavhalar.split("\r\n")[0])
print("javob tanasi:", tana)
print()
print("proksi jurnali:", jurnal)
print("mijoz orqadagi port", ORQA_PORT, "ni bilmaydi ham")
Natija
mijoz ulangan port: 9971
javob birinchi qatori: HTTP/1.1 200 OK
javob tanasi: ilova javobi, yo'l: /darslik

proksi jurnali: ['GET /darslik HTTP/1.1']
mijoz orqadagi port 9970 ni bilmaydi ham

Ellik qatorlik kod - va bu aslida nginx qiladigan ishning mag'zi. Qolgani sozlanish, tezlik va xatolarni ishlash.

X-Forwarded-For ga ehtiyot bo'lib ishoning

Proksi orqada turgan ilovaga mijozning haqiqiy manzilini X-Forwarded-For sarlavhasida yetkazadi - chunki ilova uchun ulanish proksidan kelayotgandek ko'rinadi.

Muammo shundaki, bu shunchaki sarlavha - uni har kim yozib yuborishi mumkin.

HolatIshonish mumkinmi
Ilova faqat proksi orqali ochiqHa - proksi qo'ygan qiymatga
Ilova to'g'ridan-to'g'ri ham ochiqYo'q
Bir necha proksi zanjiriFaqat oxirgisiga

Shuning uchun ilova X-Forwarded-For ni faqat ishonchli proksidan kelgan bo'lsa qabul qilishi kerak. Aks holda kimdir o'zini boshqa manzildan kelayotgandek ko'rsatib, IP bo'yicha cheklovlarni chetlab o'tadi.

Bu "Kiberxavfsizlik asoslari" darsligining 5-bo'limidagi kirish nazorati mavzusiga bevosita bog'liq.

Yuk balanslash #

Bitta server yetmay qolganda, bir nechtasi qo'yiladi. Savol - so'rovni qaysi biriga berish kerak?

Python
class Balanslovchi:
    def __init__(self, serverlar):
        self.serverlar = serverlar
        self.joriy = 0
        self.ulanishlar = {s: 0 for s in serverlar}

    def navbat_bilan(self):
        s = self.serverlar[self.joriy % len(self.serverlar)]
        self.joriy += 1
        return s

    def eng_bosh(self):
        return min(self.serverlar, key=lambda s: self.ulanishlar[s])


SERVERLAR = ["server-1", "server-2", "server-3"]

b = Balanslovchi(SERVERLAR)
print("navbat bilan (round-robin):")
for i in range(1, 7):
    print(f"  {i}-so'rov -> {b.navbat_bilan()}")

print()
print("eng bo'sh serverga (least connections):")
b2 = Balanslovchi(SERVERLAR)
# server-1 ga uchta uzoq ulanish osilib qolgan
b2.ulanishlar["server-1"] = 3
b2.ulanishlar["server-2"] = 1
b2.ulanishlar["server-3"] = 0

for i in range(1, 7):
    s = b2.eng_bosh()
    b2.ulanishlar[s] += 1
    holat = " ".join(f"{k.split('-')[1]}:{v}"
                     for k, v in b2.ulanishlar.items())
    print(f"  {i}-so'rov -> {s}   yuk: {holat}")

print()
print("navbat bilan usuli yukni HISOBGA OLMAYDI")
print("eng bo'sh usuli esa band serverni chetlab o'tadi")
Natija
navbat bilan (round-robin):
  1-so'rov -> server-1
  2-so'rov -> server-2
  3-so'rov -> server-3
  4-so'rov -> server-1
  5-so'rov -> server-2
  6-so'rov -> server-3

eng bo'sh serverga (least connections):
  1-so'rov -> server-3   yuk: 1:3 2:1 3:1
  2-so'rov -> server-2   yuk: 1:3 2:2 3:1
  3-so'rov -> server-3   yuk: 1:3 2:2 3:2
  4-so'rov -> server-2   yuk: 1:3 2:3 3:2
  5-so'rov -> server-3   yuk: 1:3 2:3 3:3
  6-so'rov -> server-1   yuk: 1:4 2:3 3:3

navbat bilan usuli yukni HISOBGA OLMAYDI
eng bo'sh usuli esa band serverni chetlab o'tadi

Asosiy usullar:

UsulQachon yaxshi
Navbat bilanSo'rovlar bir xil og'irlikda
Eng bo'shSo'rovlar turli davomiylikda
Xesh bo'yichaMijoz doim bir serverga tushishi kerak
Tasodifiy (ikkitadan)Katta miqyosda, hisob yuritmasdan

Oxirgisi qiziq: ikkita serverni tasodifan tanlab, ulardan bo'shrog'ini olish - deyarli "eng bo'sh" darajasida yaxshi natija beradi, lekin butun ro'yxatni tekshirish kerak emas.

Sog'liqni tekshirish bo'lmasa, balanslovchi zarar keltiradi

Serverlardan biri ishdan chiqsa, balanslovchi buni bilmasa, u so'rovlarni o'sha yerga yuborishda davom etadi.

Natijada har uchinchi foydalanuvchi xato oladi.

Shuning uchun har balanslovchida sog'liq tekshiruvi bo'ladi:

SozlamaMa'nosi
Yo'l/health kabi yengil manzil
DavriylikHar 2-5 soniyada
Nosoz deb hisoblashKetma-ket 2-3 xatodan keyin
QaytarishKetma-ket 2-3 muvaffaqiyatdan keyin

Tekshiruv manzili yengil bo'lishi kerak: agar u bazaga so'rov yuborsa, tekshiruvning o'zi yuk yaratadi.

CDN - kechikishga qarshi yagona qurol #

16-bo'limda ko'rgandik: tarqalish kechikishini kamaytirib bo'lmaydi. Uni faqat masofani qisqartirish bilan kamaytirish mumkin.

CDN aynan shuni qiladi: nusxalarni dunyo bo'ylab tarqatadi va foydalanuvchini eng yaqiniga yo'naltiradi.

CDN sizCDN bilan
MasofaToshkent → FrankfurtToshkent → Toshkent
Kechikish~80 ms~5 ms
Asosiy serverdagi yuk100%Faqat kesh yangilanishi
Server ishdan chiqsaSayt yotadiKesh hali xizmat qiladi

CDN odatda statik fayllar uchun ishlatiladi: rasm, CSS, JS, video. Dinamik sahifalarni keshlash ancha nozik ish - foydalanuvchiga boshqa birovning ma'lumotini ko'rsatib qo'yish xavfi bor.

Qanday qilib "eng yaqin" server tanlanadi?

Ikki asosiy usul bor:

UsulQanday ishlaydi
DNS orqaliBir xil nomga turli hududda turli IP qaytariladi
AnycastBir xil IP manzil ko'p joyda e'lon qilinadi

Ikkinchisi qiziqroq: bir necha o'nlab ma'lumot markazi aynan bir xil IP manzilni e'lon qiladi va marshrutlash (5-bo'lim) paketni eng yaqiniga olib boradi.

Ildiz DNS serverlari ham shunday ishlaydi: manzillari 13 ta, lekin jismoniy serverlari yuzlab.

P2P - serversiz almashinuv #

Mijoz-server sxemasining muqobili - qatnashchilar bir-biriga to'g'ridan-to'g'ri ulanadi.

Mijoz-serverP2P
Ma'lumot qayerdaMarkazdaQatnashchilarda
Yuk o'sgandaServer kuchaytiriladiO'zi kuchayadi
BoshqarishOsonQiyin
NAT ortida ishlashiMuammo yo'qAsosiy qiyinchilik

Oxirgi qator 10-bo'lim bilan bog'liq: ikkala tomon ham NAT ortida bo'lsa, ular bir-biriga to'g'ridan-to'g'ri ulana olmaydi.

Yechim - teshik ochish (hole punching): ikkala tomon ham tashqaridagi umumiy serverga (STUN) ulanadi, u ularning tashqi manzil va portlarini bir-biriga aytadi, keyin ular bir vaqtda bir-biriga urinib ko'radi.

Ishlamasa - trafik oraliq server (TURN) orqali o'tadi. Video qo'ng'iroqlarda sifat ba'zan shuning uchun pasayadi.

Amaliy topshiriq
  1. Teskari proksi misolini ishga tushiring.
  2. Proksiga ikkinchi orqa server qo'shing va navbat bilan taqsimlang.
  3. Proksida so'rov yo'liga qarab turli serverga yo'naltiring.
  4. Javobga X-Proxy: bizniki sarlavhasini qo'shing.
  5. Balanslovchi misolini ishga tushiring.
  6. Unga "xesh bo'yicha" usulini qo'shing.
  7. Sog'liq tekshiruvini qo'shing: nosoz serverni ro'yxatdan chiqaring.
  8. curl -I bilan biror sayt CDN ortidami yoki yo'qligini tekshiring.
  9. CDN kechikishni qanday kamaytirishini uch qatorda yozing.
  10. P2P mos keladigan va kelmaydigan bittadan holat yozing.

Xulosa #

  • To'g'ri proksi mijoz uchun, teskari proksi server uchun ishlaydi.
  • Teskari proksi TLS ni uzadi, yukni taqsimlaydi va ilovani yashiradi.
  • Ellik qator kod - nginx qiladigan ishning asosiy mag'zi.
  • X-Forwarded-For ga faqat ishonchli proksidan kelganda ishoning.
  • Balanslash usullari: navbat bilan, eng bo'sh, xesh bo'yicha, ikkitadan tasodifiy.
  • Sog'liq tekshiruvi bo'lmasa, balanslovchi nosoz serverga so'rov yuboraveradi.
  • Tekshiruv manzili yengil bo'lsin - aks holda o'zi yuk yaratadi.
  • CDN kechikishni masofani qisqartirish orqali kamaytiradi - boshqa yo'l yo'q.
  • Eng yaqin nusxa DNS yoki anycast orqali tanlanadi.
  • P2P yuk oshganda o'zi kuchayadi, lekin NAT ortida ishlash asosiy qiyinchilik.

Keyingi, yakuniy bo'limda hamma o'rganganimizni birlashtirib, xom soketlar ustida o'z HTTP serveringizni yozamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.