Presentation is loading. Please wait.

Presentation is loading. Please wait.

Primirea si procesarea cererilor

Similar presentations


Presentation on theme: "Primirea si procesarea cererilor"— Presentation transcript:

1 Primirea si procesarea cererilor
Mugurel Ionuț Andreica 2012

2 Etapele generale ale procesarii unei cereri

3 Primirea cererilor (1/3)
Server-ul (o instanta a serviciului) creeaza un socket initial S In cazul utilizarii unor protocoale orientate pe conexiune (TCP, SCTP, etc.), server-ul accepta conexiuni pe socket-ul S ; dupa stabilirea conexiunii se creeaza un socket asociat conexiunii, pe care se vor accepta cereri In cazul utilizarii protocolului UDP (sau a altor protocoale neorientate pe conexiune), server-ul accepta cereri direct pe socket-ul initial S Alternativ, server-ul poate crea mai multi socketi initiali pe care sa accepte conexiuni / cereri

4 Primirea cererilor (2/3)
Server-ul asteapta cereri pe o multime MS de socketi Varianta 1 (un thread per socket): Avem cate un thread separat pentru fiecare socket din MS Thread-ul respectiv citeste cererea de pe socket, o proceseaza si trimite raspunsul inapoi (pe acelasi socket); eventual, daca se trimit mai multe cereri pe acelasi socket, citeste cererile de pe socket si le proceseaza in continuare Thread-ul care face accept creeaza cate un thread nou pentru fiecare conexiune acceptata Varianta 2 (un singur thread per total): Exista un singur thread care citeste de pe socket-ii din MS (folosind un Selector) Cand citeste o cerere completa, o proceseaza imediat si apoi trimite inapoi raspunsul la client

5 Primirea cererilor (3/3)
Varianta 3 (un thread pentru citire si un pool de thread-uri pentru procesare): Exista un singur thread care citeste de pe socket-ii din MS (folosind un Selector) Cand citeste o cerere completa, o trimite unui pool de thread-uri dedicate procesarii de cereri Un thread din pool proceseaza cererea si trimite raspunsul la client Varianta 4 (un pool de thread-uri pentru citire si un pool de thread-uri pentru procesare) Exista un pool de thread-uri care citesc de pe socket-ii din MS (folosind Selector-i) Fiecare socket din MS este asignat unui thread din pool-ul pentru citire Fiecare thread din pool-ul de citire se comporta ca thread-ul unic de citire din varianta 3 Varianta 5 (un thread per socket pentru citire + un thread per cerere pentru procesare) Varianta 6 (un pool de thread-uri pentru citire + un thread per cerere pentru procesare)

6 Procesarea efectiva a cererilor (1/2)
Thread-ul care proceseaza o cerere efectueaza actiunile specifice necesare, in functie de parametrii din cadrul cererii Procesarea unei cereri poate conduce la modificarea starii interne a serviciului Aceasta stare interna este stocata in date partajate de toate thread-urile server-ului Modificarea starii interne poate implica comunicatia (imediata sau ulterioara) cu alte server-e (instante ale serviciului) Rezultatul procesarii (daca exista) este trimis inapoi clientului (daca se doreste acest lucru)

7 Procesarea efectiva a cererilor (2/2)
Procesarea efectiva a unei cereri poate fi un proces complex In cel mai simplu caz, thread-ul care o proceseaza nu are nevoie de alte functionalitati si date pe care nu le detine (el avand acces atat la functiile necesare procesarii, cat si la datele necesare) In cazul general, procesarea unei cereri poate determina aparitia unor sub-cereri, care sunt trimise altor pool-uri de thread-uri (sau altor servicii), iar rezultatul final se obtine prin combinarea rezultatelor sub-cererilor De asemenea, thread-ul poate avea nevoie sa apeleze alte servicii pentru a putea finaliza procesarea cererii

8 Elemente comune si diferite ale serviciilor
Orice serviciu trebuie sa primeasca cumva cererile din retea, astfel ca o componenta de primire a cererilor este necesara in implementarea oricarui serviciu Componenta trebuie sa identifice o cerere “completa” In cazul TCP: o cerere poate fi primita dupa mai multe read-uri de pe socket => trebuie stabilit un protocol care marcheaza inceputul/sfarsitul unei cereri In cazul UDP/SCTP: o cerere poate fi complet inclusa intr-un singur mesaj (si atunci e primita in totalitate in urma unui singur read) sau poate fi impartita (explicit) pe mai multe mesaje (caz in care componenta de receptie trebuie sa buffer-eze mesajele pana cand formeaza o cerere completa) Complexitatea unui serviciu consta in modul in care proceseaza o cerere (care depinde de functionalitatea specifica oferita de serviciu)

9 Socketi UDP – 1 thread per socket + 1 thread per cerere (1/2)
Serviciul poate deschide mai multi socketi UDP pe care sa accepte cereri ; exista un thread separat pentru fiecare astfel de socket care citeste mesajele UDP de pe socket O cerere = 1 mesaj UDP (in acest caz, fiecare mesaj e procesat independent) Mai multe mesaje UDP (in acest caz, este nevoie de un mecanism care sa marcheze inceputul/sfarsitul cererii) La fiecare cerere primita se creeaza un thread nou, responsabil cu tratarea cererii respective La finalizarea procesarii cererii, thread-ul isi incheie executia Se poate impune o limita maxima pt numarul de thread-uri active simultan Daca soseste o cerere si limita maxima este atinsa, atunci: Cererea poate fi respinsa sau Cererea poate fi pusa intr-o coada de asteptare, de unde va fi luata mai tarziu de un thread special, care va instantia un thread nou care sa proceseze cererea Coada poate avea si ea o limita maxima (daca se atinge si limita maxima a cozii, atunci thread-ul care a citit cererea se blocheaza in asteptarea eliberarii de spatiu in coada sau cererea este respinsa)

10 Socketi UDP – 1 thread per socket + 1 thread per cerere (2/2)

11 Socketi UDP – 1 thread per socket + pool de thread-uri pentru cereri (1/2)
similar cu cazul precedent, dar: Cand se primeste o cerere completa, aceasta este data pool-ului de thread-uri, care: O va pune intr-o coada comuna de unde toate thread-urile worker iau cereri sau va selecta un thread din pool si va pune cererea in coada proprie a thread-ului respectiv, care va procesa cererea la finalul procesarii, thread-ul worker va astepta sa primeasca o cerere noua pentru a o procesa Numarul de thread-uri din thread pool poate fi static sau dinamic Daca capacitatea maxima a cozilor a fost atinsa: Se blocheaza in asteptarea eliberarii spatiului in cozi Cererea este respinsa

12 Socketi UDP – 1 thread per socket + pool de thread-uri pentru cereri (2/2)

13 Socketi UDP – pool de thread-uri de citire + 1 thread per cerere (1/2)
Serviciul creeaza unul sau mai multi socketi UDP pe care accepta cereri Se creeaza un pool de thread-uri de citire, care sunt responsabile de citirea mesajelor de pe unul sau mai multi socketi UDP Se foloseste mecanismul de Selector (similar cu functia select() in C) Dupa citirea unei cereri complete de pe unul din socket-ii pentru care e responsabil, thread-ul de citire va crea un thread nou care va procesa cererea

14 Socketi UDP – pool de thread-uri de citire + 1 thread per cerere (2/2)

15 Socketi UDP – pool de thread-uri de citire + pool de thread-uri pentru cereri (1/2)
Thread-urile de citire: la fel ca in cazul anterior Cand se primeste o cerere completa, aceasta este data pool-ului de thread-uri de procesare (care se comporta ca in slide-urile anterioare)

16 Socketi UDP – pool de thread-uri de citire + pool de thread-uri pentru cereri (2/2)

17 Socketi TCP Serviciul deschide unul sau mai multi socketi TCP pe care accepta conexiuni Clientii se conecteaza intai la serviciu, deschizand astfel propriul socket TCP client-serviciu TCP nu pastreaza limitele mesajelor (ofera doar abstractia de flux de bytes) => sunt necesare marcaje pentru inceputul/sfarsitul cererii Serviciul trebuie sa stocheze intr-un buffer asociat fiecarui socket datele primite pe socket in urma unui read, pana cand acestea formeaza o cerere completa 2 modele posibile: O cerere per conexiune TCP (se deschide conexiunea, se trimite cererea completa, eventual se asteapta raspunsul, se inchide conexiunea) Mai multe cereri pe aceeasi conexiune TCP (o cerere A poate fi trimisa dupa o alta cerere B chiar daca raspunsul pentru B nu a fost primit inca de client, daca cele 2 cereri sunt logic independente) Atentie! Este posibil ca in urma aceluiasi read pe socket, sa soseasca sfarsitul unei cereri, urmat de una sau mai multe cereri complete, urmat de inceputul unei alte cereri. Aceste cazuri trebuie tratate corespunzator imediat dupa citirea datelor de pe socket => se formeaza toate cererile complete si se pastreaza in buffer-ul asociat socket-ului doar inceputul cererii incomplete

18 Socketi TCP – 1 thread per accept socket + 1 thread per socket pentru citire + procesare (1/2)
Clientul se conecteaza la serviciu Clientul trimite o cerere pe socket, si, eventual, asteapta raspunsul Fiecare socket pe care se accepta conexiuni are cate un thread separat, care accepta conexiuni, iar, la acceptarea unei conexiuni, creeaza un thread nou care va citi date de pe socket-ul corespunzator conexiunii In modelul de 1 cerere per conexiune, acelasi thread poate si procesa cererea imediat dupa citirea ei, iar apoi trimite raspunsul pe socket Daca pot sosi mai multe cereri per socket, atunci thread-ul respectiv poate procesa toate cererile de pe socket, secvential (citeste o cerere, o proceseaza, citeste cererea urmatoare, o proceseaza, etc.) Daca sunt deja prea multi socket-i (adica prea multe thread-uri), atunci avem aceleasi optiuni prezentate anterior pentru cazul atingerii limitei maxime a numarului de thread-uri de procesare cereri (sau a capacitatii maxime a cozii/cozilor)

19 Socketi TCP – 1 thread per accept socket + 1 thread per socket pentru citire + procesare (2/2)

20 Socketi TCP – pool de thread-uri pentru accept + 1 thread per socket pentru citire + procesare (1/2)
Se creeaza un pool de thread-uri pentru acceptarea de conexiuni Fiecare socket TCP pe care se accepta conexiuni este asignat unui thread din pool Fiecare thread din pool foloseste mecanismul de Selector pentru acceptarea conexiunilor de pe socket-ii asignati lui La acceptarea unui conexiuni noi, thread-ul care a acceptat conexiunea se comporta la fel ca in cazul precedent

21 Socketi TCP – pool de thread-uri pentru accept + 1 thread per socket pentru citire + procesare (2/2)

22 Socketi TCP – 1 thread per socket pentru citire + pool de thread-uri pentru procesare (1/3)
Putem avea un thread per socket de accept sau un pool de thread-uri pentru acceptarea de conexiuni La acceptarea unei noi conexiuni se creeaza un thread nou care va citi cereri de pe conexiunea respectiva La citirea fiecarei cereri complete, aceasta este data mai departe unui pool de thread-uri pentru a fi procesata Util doar daca se pot primi mai multe cereri pe acelasi socket sau daca procesarea poate fi cumva paralelizata (nu e complet secventiala)

23 Socketi TCP – 1 thread per socket pentru citire + pool de thread-uri pentru procesare (2/3)

24 Socketi TCP – 1 thread per socket pentru citire + pool de thread-uri pentru procesare (3/3)

25 Socketi TCP – 1 thread pentru accept si citire cereri (1/3)
Se foloseste un singur thread pentru acceptarea de conexiuni si citirea cererilor de pe toti socket-ii (care se bazeaza pe mecanismul de Selector) La primirea unei cereri complete: Se poate crea un thread nou care sa o proceseze si care sa isi incheie executia dupa aceea Se poate da cererea unui pool de thread-uri Actiunile intreprinse daca se atinge limita maxima (pentru numarul de thread-uri active sau pentru numarul de cereri in coada/cozi) sunt aceleasi care au fost discutate anterior

26 Socketi TCP – 1 thread pentru accept si citire cereri (2/3)

27 Socketi TCP – 1 thread pentru accept si citire cereri (3/3)

28 Socketi TCP – pool de thread-uri pentru accept si citire cereri (1/3)
Se foloseste un pool de thread-uri pentru acceptarea de conexiuni si citirea cererilor de pe toti socket-ii Fiecare thread din pool are asignat zero, unul sau mai multi socket-i de pe care poate accepta conexiuni sau citi date Fiecare socket este asignat unui singur thread din pool Fiecare thread din pool foloseste mecanismul de Selector La primirea unei cereri complete: Se poate crea un thread nou care sa o proceseze si care sa isi incheie executia dupa aceea Se poate da cererea unui pool de thread-uri Actiunile intreprinse daca se atinge limita maxima (pentru numarul de thread-uri active sau pentru numarul de cereri in coada/cozi) sunt aceleasi care au fost discutate anterior

29 Socketi TCP – pool de thread-uri pentru accept si citire cereri (2/3)

30 Socketi TCP – pool de thread-uri pentru accept si citire cereri (3/3)

31 Observatii referitoare la mecanismul de Selector (1/2)
Pentru a folosi mecanismul Selector pe un socket, acesta trebuie trecut in starea neblocanta => apelurile de read/write nu se blocheaza Un apel de read intoarce imediat bytes-ii primiti (si numarul lor, care poate fi 0) care nu au fost inca accesati de aplicatie Un apel de write trimite imediat doar atatia bytes cati poate (si intoarce cati bytes a trimis efectiv din datele date ca parametru; acest numar poate fi 0) In exemplele prezentate pana acum ne-am concentrat pe partea de citire (unde am considerat toate aspectele relevante), dar am omis partea de scriere

32 Observatii referitoare la mecanismul de Selector (2/2)
In principiu, scrierea raspunsului unei cereri pe un socket se face de catre thread-ul care a procesat cererea Cazul 1: cerere per mesaj (socketi UDP) sau o cerere per socket (socketi TCP): Daca socket-ul e blocant, se poate apela write imediat pe socket Daca socket-ul e non-blocant, trebuie sa cerem thread-ului care il gestioneaza sa ne notifice cand se pot scrie date pe socket (pentru a nu apela write intr-una pana cand se trimit toti bytes-ii, ceea ce ar constitui busy waiting) => s-ar putea sa trebuiasca sa apelam, oricum, de mai multe ori write, pana cand se scrie tot raspunsul pe socket Cazul 2: mai multe cereri per socket (socketi TCP): Aceleasi considerente ca mai sus In plus, daca cererile nu sunt procesate secvential (de acelasi thread), atunci trebuie sa avem grija ca la scrierea raspunsurilor pe socket sa nu se intercaleze date din raspunsurile mai multor cereri (de ex., se scrie o parte din raspunsul cererii 1, urmat de o parte din raspunsul cererii 2, etc.) In plus, cererile si raspunsurile trebuie sa aiba identificatori, deoarece raspunsurile nu vor fi scrise neaparat in ordinea in care au venit cererile corespunzatoare

33 Planificarea thread-urilor pe core-uri/procesoare
Thread-urile care citesc cereri de pe socket-i si cele care proceseaza efectiv cererile sunt, in general, planificate in timp si per core/procesor de catre sistemul de operare Exista API pentru setarea de afinitati ale thread-urilor pentru anumite core-uri/procesoare Numai in kernel-ul Linux Pentru a accesa din Java functiile C oferite de kernel-ul Linux se foloseste JNI (Java Native Interface)

34 Afinitati de core/procesor (1/2)
Se poate specifica ca un thread sa se execute doar pe un core/procesor dintr-o submultime data In felul acesta, se pot rezerva core-uri/procesoare pentru diverse task-uri (de ex., thread-urile ce citesc de pe / scriu pe socket-i primesc un subset de core-uri, iar cele care realizeaza procesarea efectiva primesc un alt set) Daca se cunoaste exact arhitectura fizica a masinii, thread-uri ce partajeaza date pot fi amplasate pe core-uri “apropiate” (pentru a beneficia de partajarea aceluiasi modul de cache) Mai putin cache-thrashing (in unele situatii)

35 Afinitati de core/procesor (2/2)
Afinitatea de core/procesor se poate modifica dinamic (de ex., thread-urile care efectueaza anumite actiuni pot primi mai multe sau mai putine core-uri, in functie de importanta si/sau necesarul de resurse al actiunilor efectuate) Planificarea in timp este lasata pe seama sistemului de operare Utilizarea afinitatilor de core/procesor are potentialul de a oferi serviciului o performanta mai ridicata, prin utilizarea mai eficienta a core-urilor/procesoarelor disponibile (si a memoriilor cache partajate de acestea)

36 Observatii Pana acum nu am considerat explicit ca cererile primite de serviciu din partea clientilor pot fi corelate Exemple: Un client trimite o cerere de log-are in sistem, urmata de cereri de acces al datelor proprii (serviciu de ) Un client upload-eaza un fisier, iar o cerere ulterioara vrea sa descarce fisierul upload-at anterior Intre cereri pot exista dependente (o cerere ulterioara se bazeaza pe faptul ca o cerere anterioara a fost procesata si a generat un anumit rezultat) Solutia: procesarea cererilor actualizeaza starea interna a serviciului ; cererile ulterioare vor beneficia de efectul cererilor anterioare prin starea interna modificata a serviciului Cum implementam “starea interna a serviciului” ?


Download ppt "Primirea si procesarea cererilor"

Similar presentations


Ads by Google