Limitarea vitezei de procesare a cererilor în nginx

  • 11.07.17 07:57 •
  • olemskoi •
  • # 329876
  • Habrahabr •
  • Traducere •
  • 11 •
  • 4500

- la fel ca Forbes, doar mai bine.

Limitarea vitezei de procesare a cererilor în nginx

Imaginea lui Wonderlane

NGINX este grozav! Iată doar documentația sa privind limitarea vitezei de procesare a solicitărilor mi se părea, cum aș spune, oarecum limitată. Prin urmare, am decis să scriu acest ghid privind limitarea vitezei de procesare a cererilor (rate-liming) și a modelarea traficului (modelarea traficului) în cadrul NGINX.








  • descrie liniile directoare ale NGINX,
  • pentru a înțelege cu acceptarea / respingerea logicii NGINX,
  • să vizualizeze procesarea erorilor de trafic pe diferite setări.

În plus, am creat un depozit GitHub și o imagine Docker. cu care puteți experimenta și reproduce testele din acest articol. Este întotdeauna mai ușor de învățat în practică.

Regulile NGINX pentru limitarea vitezei cererilor de procesare

În acest articol vom vorbi despre ngx_http_limit_req_module. în care sunt implementate directivele limit_req_zone. limit_req. limita_req_status și limita_req_level. Acestea vă permit să controlați valoarea codului de stare HTTP pentru solicitările respinse, precum și înregistrarea acestor erori.

Cel mai adesea acestea sunt confuze tocmai în logica respingerii interogării.

Mai întâi trebuie să înțelegeți directiva limit_req. care necesită parametrul zonei. De asemenea, are parametri opționali pentru spargere și nodelay.

Următoarele concepte sunt folosite aici:

spargere este un parametru opțional. Odată instalat, acesta determină numărul de solicitări care pot fi procesate în exces față de limita de viteză de bază stabilită. Este important să înțelegem că explozia este valoarea absolută a numărului de cereri, nu a vitezei.


  • nodelay este, de asemenea, un parametru opțional care este folosit împreună cu spargerea. Mai jos vom înțelege de ce este nevoie.

  • Cum decide NGINX să accepte sau să respingă cererea?

    La setarea zonei, este setată viteza. De exemplu, la 300r / m vor fi acceptate 300 de cereri pe minut, iar la 5r / s - 5 cereri pe secundă.


    • limit_req_zone $ request_uri zona = zona1: rata de 10m = 300r / m;
    • limit_req_zone $ request_uri zona = zona2: rata de 10m = 5 / s;

    Este important să înțelegeți că aceste două zone au aceleași limite. Folosind parametrul rate, NGINX calculează frecvența și, în consecință, intervalul după care puteți accepta o nouă solicitare. În acest caz, NGINX va folosi un algoritm numit găleată neetanșă.

    Pentru NGNX 300r / m și 5r / s sunt aceleași: va trece peste o cerere la fiecare 0,2 s. În acest caz, NGINX va stabili un steag la fiecare 0,2 secunde pentru a permite primirea cererii. Când apare o cerere pentru această zonă, NGINX elimină drapelul și procesează solicitarea. Dacă vine următoarea solicitare și cronometrul care contorizează timpul dintre pachete nu a funcționat încă, cererea va fi respinsă cu un cod de stare de 503. Dacă timpul a expirat și pavilionul este deja setat la valoarea permisă, nu se va efectua nicio acțiune.

    Trebuie să limitați viteza procesării cererilor și modelarea traficului?

    Să vorbim despre parametrul de spargere. Imaginați-vă că steagul despre care am vorbit mai sus poate avea valori mai mari decât unul. În acest caz, acesta va reflecta numărul maxim de solicitări pe care NGINX ar trebui să le rateze într-o singură explozie.

    Acum nu este o "găleată de găleată", o "găleată de token". Parametrul ratei specifică intervalul de timp dintre solicitări, dar nu avem de-a face cu un jeton de tip true / false, dar cu un contor de la 0 la 1 + izbucni. Contorul este incrementat de fiecare dată când trece intervalul de timp calculat (începe ceasul), atingând valoarea maximă în b + 1. Permiteți-mi să vă reamintesc din nou: explozia este numărul de cereri, nu viteza de transmitere a acestora.

    Atunci când apare o nouă solicitare, NGINX verifică disponibilitatea jetonului (numărător> 0). Dacă tokenul nu este disponibil, cererea este respinsă. În caz contrar, cererea este acceptată și procesată, iar tokenul este considerat a fi consumat (contorul este redus cu unul).

    Dacă există jetoane neexpuse, NGINX va accepta cererea. Dar când o va procesa?

    Am stabilit o limită de 5 r / s, cu ca NGINX să accepte cereri în exces față de normă dacă există jetoane de spargere disponibile, dar amânarea procesării lor astfel încât să susțină viteza setată. Adică, aceste cereri de spargere vor fi procesate cu o anumită întârziere sau vor fi completate cu expirare.

    Cu alte cuvinte, NGINX nu va depăși limita stabilită pentru zonă, dar va plasa cereri suplimentare în coadă și le va procesa cu o anumită întârziere.

    Iată un exemplu simplu: să spunem că avem o limită de 1 r / s și o explozie de 3. Ce se întâmplă dacă NGINX primește 5 cereri simultan?


    • Primul va fi acceptat și procesat.
    • Deoarece nu mai mult de 1 + 3 este permisă, o cerere va fi respinsă imediat cu un cod de stare de 503.
    • Cele trei rămase vor fi procesate unul câte unul, dar nu instantaneu. NGINX le va sări cu o viteză de 1 r / s. rămânând în limita stabilită și, de asemenea, cu condiția să nu vină noi cereri, care să utilizeze și cota. Când coada este goală, contorul va începe să crească din nou (coșul de jetoane începe să se umple).







    Dacă serverul NGINX este folosit ca server proxy, serviciile aflate în spatele acestuia vor primi cereri cu o viteză de 1r / s și nu vor ști nimic despre supratensiunile de trafic netezite de serverul proxy.

    Așadar, am stabilit configurarea traficului, aplicând întârzieri pentru a gestiona exploziile de interogări și pentru a alinia fluxul de date.

    nodelay spune NGINX că trebuie să accepte pachetele în fereastra definită de valoarea de spargere. și să le proceseze imediat (ca și cererile normale).

    Ca urmare, explozii de trafic vor ajunge în continuare la serviciile aflate în spatele NGINX, dar aceste explozii vor fi limitate de valoarea de spargere.

    Vizualizarea limitelor de viteză pentru procesarea cererilor

    Deoarece cred că această practică ajută foarte mult la memorarea a ceva, am făcut o mică imagine Docker cu NGINX la bord. Există resurse configurate pentru care sunt implementate diferite opțiuni de limitare a vitezei de procesare a cererilor: cu o constrângere de bază, cu o limită de viteză folosind explozie. precum și cu spargere și nodelay. Să vedem cum funcționează.

    Aici folosim o configurație destul de simplă a NGINX (este, de asemenea, în imaginea Docker, o legătură care poate fi găsită la sfârșitul articolului):

    Configurați testul NGINX cu diverse opțiuni pentru limitarea vitezei cererilor de procesare

    În toate testele, folosind această configurație, trimitem simultan 10 solicitări concurentă.

    Să aflăm ce:


    • câte solicitări vor fi respinse din cauza limitelor de viteză?
    • Care este viteza de procesare a cererilor primite?

    Facem 10 solicitări concurentă la resursă cu limitarea vitezei de procesare a cererilor

    10 solicitări simultane către o resursă cu o limită de viteză pentru procesarea cererilor

    În configurația noastră sunt permise 30 de solicitări pe minut. Dar în acest caz, 9 din 10 vor fi respinse. Dacă citiți cu atenție secțiunile anterioare, acest comportament NGINX nu vă va surprinde: 30r / m înseamnă că va exista o singură cerere în 2 secunde. În exemplul nostru, 10 cereri ajung simultan, una este omisă, iar celelalte nouă sunt respinse, deoarece NGINX este vizibilă înainte ca ceasul să permită următoarea solicitare.

    Voi supraviețui unor mici explozii de cereri către clienți / puncte finale

    Bine! Apoi adăugăm spargerea argumentului = 5. care va permite NGINX să ignore explozii mici de solicitări la acest punct final al zonei cu restricția vitezei de procesare a cererilor:

    10 cereri simultane la resursa cu spargerea argumentului = 5

    Ce sa întâmplat aici? Așa cum v-ați putea aștepta, cu argumentul exploziei, au fost primite 5 solicitări suplimentare și am îmbunătățit raportul dintre cererile primite până la numărul lor total de la 1/10 la 6/10 (restul au fost respinse). Este ușor de văzut modul în care NGINX actualizează cererile de jetoane și procesele primite - viteza de ieșire este limitată la 30r / m. care este egal cu o cerere la fiecare 2 secunde.

    Răspunsul la prima cerere este returnat în 0,2 secunde. Timerul este declanșat după 2 secunde, una dintre solicitările în așteptare este procesată și clientul primește un răspuns. Timpul total petrecut pe drumul înainte și înapoi a fost de 2,02 secunde. După încă 2 secunde, temporizatorul declanșează din nou, oferind posibilitatea de a procesa o altă solicitare, care este returnată cu un timp total de deplasare de 4,02 secunde. Și așa mai departe ...

    Astfel, argumentul de spargere permite transformarea sistemului de limitare a vitezei de procesare a cererilor NGINX de la un filtru de prag simplu la un formator de trafic.

    Serverul meu va rezista încărcăturii suplimentare, dar aș dori să folosesc limita de viteză a procesării cererilor pentru a preveni supraîncărcarea acestuia

    În acest caz, argumentul nodelay poate fi util. Să trimitem aceleași 10 interogări la punctul final cu setarea de spargere = 5 nodelay:

    10 cereri simultane la resursa cu spargerea argumentului = 5 nodelay

    Așa cum era de așteptat cu explozie = 5. vom avea același raport de 200 și 503 de coduri de stare. Dar viteza de ieșire nu se limitează acum la o solicitare la fiecare 2 secunde. În timp ce sunt disponibile jetoanele de declanșare, cererile primite vor fi acceptate și procesate imediat. Viteza timerului este încă importantă în ceea ce privește completarea numărului de jetoane, dar întârzierea nu se aplică cererilor primite.

    Să însumăm rezultatele

    Să încercăm să vizualizăm modul în care NGINX acceptă cererile primite și le procesează pe baza parametrilor ratei. spargere și nodelay.

    Pentru a nu complica, vom afișa numărul de cereri de intrare (care sunt apoi respinse sau primite și procesate) pe scala de timp definită în setările zonei, împărțită la valori egale ale declanșatorului cronometrului segmentului. Valoarea absolută a intervalului de timp nu este semnificativă. Numărul de solicitări pe care NGINX le poate procesa la fiecare pas este important.

    Iată traficul pe care îl vom rula prin setări diferite pentru limita de viteză pentru procesarea cererilor:


    Limitarea vitezei de procesare a cererilor în nginx

    Cererile de intrare și limitele de viteză de procesare a interogărilor stabilite pentru zonă


    Limitarea vitezei de procesare a cererilor în nginx

    Cereri primite și respinse (setarea de spargere nu este specificată)

    Fără izbucniri (adică atunci când spargerea este 0), NGINX îndeplinește funcția de limitator de viteză. Solicitările sunt procesate imediat sau respinse imediat.

    Dacă vrem să permitem explozii mici de trafic, de exemplu, pentru a încărca capacități în limita stabilită, atunci puteți adăuga argumentul de spargere. ceea ce implică o întârziere în procesarea cererilor primite în cadrul jetoanelor de explozie disponibile:


    Limitarea vitezei de procesare a cererilor în nginx

    Solicitări acceptate, întârziate și respinse (utilizând explozie)

    Vedem că numărul total de solicitări respinse a scăzut. Doar acele cereri de mare viteză au fost respinse, care au venit într-un moment în care nu existau jetoane de explozie. Cu astfel de setări, NGINX efectuează modelarea pe scară largă a traficului.

    În cele din urmă, Nginx pot fi folosite, ceea ce va duce în final la rata de ieșire mai puțin stabilă pentru gestionarea traficului prin limitarea dimensiunii cerere de spargere (spargere), dar va fi parțial cu izbucniri de cereri ajung stivuitoare lor (în amonte sau locale), dar va îmbunătăți latență de rețea ( dacă sunteți, desigur, aveți posibilitatea să se ocupe de aceste interogare suplimentare):


    Limitarea vitezei de procesare a cererilor în nginx

    Solicitări acceptate, procesate și respinse (exploziile sunt utilizate cu nodelay)

    Jucați cu cereri de limită de viteză

    Acum, pentru a consolida mai bine înțelegerea conceptelor de mai sus, puteți să studiați codul, să copiați repozitoriul și să experimentați imaginea pregătită de Docker:

    Nu văd de ce, pentru scurtcircuit, în traducerea termenului limită, nu renunțați la ultimele două cuvinte. Cred că toată lumea înțelege ce "limită de viteză" în contextul nginx este întrebarea. Nu ar trebui să existe altă interpretare și o posibilă ambiguitate.

    Pentru mine viteza este limit_rate (a apărut în nginx înainte). În original, se pare că este scris și stricat ... înlocuirea conceptelor)) ce limitezi în continuare, conform articolului dvs., nu este de înțeles. Mai mult, scrieți despre modelarea traficului, dar despre el nu există nimic)))







    Articole similare

    Trimiteți-le prietenilor: