Acceleratoare Web Folosind Memorii Volatile Si Replicate
PROGRAMUL DE STUDII INFORMATICĂ IFR
LUCRARE DE LICENȚĂ
Coordonator științific:
Lect. univ. dr. Popa V Dan
Absolvent: Mantale Alin Andrei
2016
PROGRAMUL DE STUDII INFORMATICĂ IFR
ACCELERATOARE WEB FOLOSIND MEMORII VOLATILE ȘI REPLICATE
Coordonator științific:
Lect. univ. dr. Popa V Dan
Absolvent: Mantale Alin Andrei
2016
Introducere
În această lucrare de licență, voi prezenta ce sunt acceleratoarele web, cum funcționează acceleratoarele web folosind memoria RAM, cum poate fi datele lor replicate folosind programe și metode specifice. Am să explic tot ce este de știut legat de memorii volatile, acceleratoare web și metode de replicare a memoriei programului “memcached” în detaliu. Pe parcursul lucrării voi pune accent pe terminologie, logica aplicației și a metodelor, voi defini caracteristicile importante la nivel tehnic, clasificate după scop.
Am ales această temă deoarece reprezintă o mare parte din tehnologiile moderne care folosesc un accelerator care lucrează cu memoria ram pentru a îmbunătăți viteza aplicațiilor și timpul lor de răspuns. În era modernă, aplicațiile și site-urile trebuie sa țină pasul cu tehnologiile noi, de exemplu dacă în anul 2000 telefoanele aveau un procesor de 200 MHz și foloseau GSM pentru date mobile, un site simplu static dura 2-3 minute pentru a se încărca, iar conținutul său avea în jur de 1-2 megabiți și nu era nevoie de metode sau programare de accelerare a paginii. Cu trecerea timpului conținutul și complexitatea paginilor web a crescut semnificativ, odată cu asta și timpul de încărcare a paginilor. De aici a fost nevoie de o metoda sau un program adițional de tip “accelerator”, pentru a micșora timpul de încărcare.
În anul 2003 compania Danga Interactive Inc. a inventat un program numit “memcached”, pentru a îmbunătăți viteza site-ului “LiveJournal.com”, acest site avea la momentul respectiv aprox. 20 milioane de vizualizări dinamice pe zi, provenind dintr-un grup gigant de servere web și baze de date. Problema era că majoritatea programelor web (apache, nginx, lighthttpd) la un număr mare de cereri pentru pagini dinamice, consumau foarte multe resurse pentru a service aceași pagină/variabilă. De aici pot apărea multe probleme la fișiere și memorie, fiecare cerere dinamică poate bloca o resursa respectivă sau acel bloc de memorie pană acel proces al serverul web eliberează resursa. S-a văzut clar nevoia de o soluție rapidă care să numai fie blocantă sau să consume resurse inutil.
Sursa: “https://en.wikipedia.org/wiki/Memcached#History” [1]
Acest program conceput de Danga Interactive Inc. a ajutat infrastructura prin a adaugă toate obiectele refolosite în memcached, pentru a fi accesat rapid data viitoare și de nu a mai face aceiași operație în baza de date sau citire pe hard-disk. Acest lucru a scăzut încărcarea bazelor de date drastic, mărind performanța site-ului și timpul de acces.
Studiind principiile memoriei ram și programul open-source “Memcached”, am făcut o corelație cum pot îmbunătăți multe aplicații, cu un sistem de stocare de tip cheie valoare modern. Am folosit o metodă de replicare a cheilor folosind un patch numit “repcached”, care îmi permite să adaug conceptul de replicare “master-master” sau “master-slave” unidirecțional. De aici am folosit titlul“acceleratoare web folosind memorii volatile și replicate” (a nu se confunda cu termenul “volatile” din C++/C/C# care este o constantă a unei variabile). Memorii volatile se referă la date care pot fi scrise și suprascrise sau manipulate în orice fel, și care își pierd valoarea când alimentarea este oprită, termenul “replicate” se refera la metodă de duplicare a unor date în altă instanță sau altă locație.
De aici am creat o aplicație de tip “wrapper”, denumită “PyRepPool” însemnând “Python Replicated Pool”, folosind cunoștințe din diferite ramuri tehnologice (Debian GNU Linux, Memcached și libmemcached) și din limbaje de programare (Python, PHP). Acestă aplicație de tip “wrapper” lucrează cu “memcached” pentru a porni și administra o simplă instanță sau cu opțiunea de a avea mai multe instanțe de memcached replicate în timp real, în alte zone sau locații. Denumirea de “wrapper” se referă la o metodă de programare care funcționează cu alte programe din sub rutina lui, el nu poate lucra singur fără programul “memcached”.
Nevoia de sisteme de cache se datorează limitării hardware de a adăuga memorie adițională și desigur prețul ei. Din punct de vedere logic, ar fi mai simplu să implementăm un sistem care stochează datele folosite des în memorie pentru a fi servite mai ușor data viitoare, decât să achiziționăm memorie adițională. Limitarea hardware este adeseori problematică, deoarece pentru a adăuga memorie trebuie schimbate toate modulele de memorie sau placa de bază, care ajung să fie foarte costisitoare.
Suportul hardware al acceleratoarelor web: Memoria RAM
De la începutul erei tehnologice în domeniul informației și comunicației, multe tehnologii și aspecte au luat formă, cum ar fi primul calculator personal, primul hard disk cu capacitatea de stocare mai mare de 1 GB, prima placă video creată special pentru jocuri, grafică, editare video etc. Toate aceste tehnologii au în comun un lucru, toate folosesc memorie ram (“Random Access Memory”), fiecare dintre ele au rol diferit dar asemănător, folosind memoria ram pentru a stoca diverse informații, pentru a fi accesate mai rapid. Termenul de memorie în domeniul IT se referă la întipărirea și recunoașterea unor date, produse de diverse programe sau utilizatori, însemnând că orice acțiune care o avem sau o facem produce un rezultat. De cele mai multe ori acel rezultat dorim să îl avem afișat pe ecran sau să îl stocăm undeva, preferabil pe hard disk. Înainte de a avea acest rezultat toate datele procesate au trecut prin memorie, acolo au fost citite, scrise și procesate. Din natura domeniul IT sau cum a fost creat sistemul de operare, orice program deschis sau folosit de utilizator este încărcat în memorie pentru a fi accesat mai rapid și pentru a elibera componenta hard disk de operațiunile I/O.
Încă de la apariția ei (componenta RAM) aprox. 1947 și apoi utilizată începând din anul 1970, memoria este o componentă care nu lipsește din orice tehnologie hardware. De la ceasul electronic al mașinii de spălat până la smartwatch-ul din era modernă, toate folosesc memorie RAM sau ROM, depinde de caz, dar principiul este același, amândouă provin din memorie. Termenul RAM (“Randoom Access Memory”) este o memorie volatilă, care poate fi citită, scrisă și rescrisă ori de câte ori avem nevoie. Ea are un concept simplu și unicat, anume date scrise și accesate rapid, iar pe partea opusă termenul ROM (“Read Only Memory”) care poate fi doar citită, ea fiind folosită pentru a încărca date predefinite, din acest scop nu poate fi considerată volatilă.
Sursă: “https://en.wikipedia.org/wiki/Random-access_memory#History” [2]
Memoria RAM este folosită în aproape orice operațiune sau interacțiune care o avem noi cu calculatorul, putem spune atunci când un utilizator își accesează adresa de email, contul de Facebook, privește un videoclip online sau vizualizează o poză, folosește memoria pentru a îndeplini cele 3 scopuri (a ușura hard disk-ul de operațiuni input/output, stochează datele pentru a fi refolosite și accesate mai rapid la următoarea operațiune asemănătoare). În contextul programării și a limbajelor de programare memoria este o componentă obligatorie și de care nu ne lipsim, toate compilările, accesările și procesările de date, variabile sau text sunt încărcate și procesate în memorie.
I.II Funcția memoriei RAM
Memoria RAM este o formă de stocare a datelor volatilă, unde locația datelor se află în memorie. Un dispozitiv de stocare a datelor în memorie aleatoriu (provenit din “Random Access Memory”) permite citirea, scrierea și rescrierea datelor în memorie, indiferent de timp și locația lor fizică pe componenta RAM, orice dată poate fi scrisă, actualizată sau ștearsă în același timp. În contrast cu definiția de mai sus, oricare alt dispozitiv cu acces direct (exemplu, CD, DVD, HDD) au timpul de acces foarte variat, datorită limitării mecanice (viteza discului sau a dvd-ului, tipul portului folosit USB 2.0 sau USB 3.0) pe care o dețin.
În era modernă memoria RAM ia forma unui circuit integrat, orice modul de memorie se află pe o componentă ram, a se observa în figura 1. Pe un dispozitiv de memorie ram găsim de obicei între 8-12 module de memorie în funcție de mărimea memoriei, iar aceste module pot fi singulare (un singur set de module de memorie pe o parte a plăcii) sau multi-liniare (cu 1 set de module pe fiecare parte, față și spate). Aceste tipuri de memorii sunt volatile, odată ce alimentarea de curent a fost oprită, datele sunt pierdute. În colțul opus avem date de stocare non-volatile precum ar fi:
ROM (“Read Only Memory”)
Figura. 1 Memorie DDR SDRAM 4. Sursa: pcgarage.ro [3]
I.III.1 Tipuri de memorii volatile
Memoriile volatile au evoluat destul de mult cu timpul, au devenit mai mici ca dimensiune, performanțe mai mari, costuri mai mici. Tipurile de memorii volatile pot fi clasificate în două categorii mari, anume DRAM și SRAM:
I.III.2 Memorii DRAM
DRAM (“Dynamic random-access memory”) este o formă de memorie ram volatilă care stochează fiecare bit de informație într-un capacitor electronic separat înăuntrul unui circuit integrat. Capacitorii pot fi încărcați sau descărcați electronic, aceste două stări reprezintă valorile unui bit, convențional numit 1 și 0. Deoarece capacitorii au mereu scurgeri electronice mici, capacitorii se vor descărca ușor cu ușor, eventual informația va dispărea dacă nu reîmprospătăm capacitorul periodic. Deoarece reîmprospătarea capacitorului este o cerință obligatorie, este considerată memorie dinamică, opus memoriei ram statice și a altor tipuri de memorii statice. Memoria DRAM volatilă își pierde datele în dată ce circuitul de memorie numai este alimentat.
Memoria DRAM este formată din o matrice de rânduri și coloane care conțin celule de memorie, teoretic aici sunt ținute toate datele noastre cum putem observa în figura 2. Fiecare rând conține o celulă electronică în care sunt stocate datele. Dat fiind natura precum funcționează capacitoarele aceste date trebuiesc mereu reîmprospătate.
Figura 2. Reprezentarea grafică a coloanelor și rândurilor de celule a unui bloc de memorie RAM.
I.III.2.1 Funcția memorii DRAM
La introducerea datelor în memoria DRAM, o încărcare electronică este aplicată asupra capacitorilor care au o valoare 1 sau sunt inițiați, și nu celor care au o valoare de 0. Apoi data este trimisă la o celulă (a se vedea în figura 3) unde un tranzistor preia data și o stochează.
Figura. 3 Un tranzistor de date înăuntrul unei celule de date.
La citirea datelor din DRAM, încărcarea capacitorilor este măsurată folosind un circuit amplificator de sens, care detectează încărcările capacitorilor și returnează valoarea lor, 0 sau 1. Pentru a putea citi starea dintr-un capacitor acesta trebuie întâi preîncărcat folosind metoda “precharging”, din acest motiv la citirea unei valori dintr-o celulă un rând întreg este scris într-un buffer, iar apoi de acolo căutăm valoarea cerută. După ce acest proces este terminat, tot rândul este rescris, motivul fiind procesul de citire din DRAM care este distructiv. Totodată doar un singur rând poate fi citit odată, pentru a citi alt rând trebuie întâi preîncărcat apoi reluat același proces de citire.
– SDRAM provenit din (“Synchronous dynamic random-access memory”) însemnând “Memorie sincronă dinamică cu acces aleatoriu”. Se numără printre primele modele de memorie DRAM(“Dynamic random-access memory”), fiind folosită prima dată în anii 1970, de compania Intel, apoi în anul 1993 a început să fie inclusă și în industria electrica. Memoria SDRAM este un sub modul al memorie DRAM, diferența este ca frecvența memoriei este sincronizată cu cea a magistralei centrale, de aici denumirea de “Synchronus”. Frecvențele la care memoria SDRAM operează sunt:
– 66, 100, 133 MHz
– DDR SDRAM provenit din (“Double data rate synchronous dynamic random-access memory”) însemnând “Memorie sincronă dinamică cu acces aleatoriu și rată de date dublată” este o clasă de circuite cu memorie integrată folosită în calculatoare, servere sau alte echipamente de rețea. DDR SDRAM reprezintă seria de plăcuțe sau dispozitive RAM folosite începând din anul 2000. Memoriile DDR folosesc ambele fronturi ale semnale de ceas “clock signal”, crescător și cel descrescător, datorită acestui fapt viteza pe care memoria DDR o are este dublată, a se vedea în figura 4.
Figura 4. Reprezentarea semnalului de acces din memoria SDRAM versus memoria DDR RAM, Sursă: Karbosguide.com [4]
I.III.2.2 Tipuri memorii DRAM
Memoriile DRAM se împart în următoarele categorii:
SDRAM:
Frecvența memoriei variază de la 200 MHz la 333 MHz
Mărimea variază de la 64 MB la 512 MB per modul
Prima generație
Voltaj: 3.3V
DDR SDRAM (DDR 1)
Frecvența memoriei variază de la 266 MHz la 400 MHz
Mărimea variază de la 128 MB la 1024 MB per modul
Prima generație DDR
Voltaj: 2.5 / 2.6 V
Dimensiunea memoriei tampon pre accesată: >= 2 cuvinte per acces
DDR SDRAM 2
Frecvența memoriei variază de la 533 MHz la 800 MHz
Mărimea variază de la 256 MB la 4 GB per modul
Voltaj: 1.8 V
Dimensiunea memoriei tampon pre accesată: >= 4 cuvinte per acces
DDR SDRAM 3
Frecvența memoriei variază de la 1066 MHz la 1600 MHz
Mărimea variază de la 512 MB la 16 GB per modul
Dimensiunea memoriei tampon pre accesată: >= 8 cuvinte per acces
Voltaj scăzut 1.35/1.5 V per modul
DDR SDRAM 4
Frecvența memoriei variază de la 2133 MHz la 3200 MHz
Mărimea variază de la 1GB la 32 GB per modul
Voltaj scăzut 1.2 V per modul
Figura 5. Tipurile de memorii DRAM.
Sursă http://www.transcend-info.com/Support/FAQ-296 [5]
I.III.3 Memorii SRAM
SRAM (“Static random access memory”) însemnând memorie statică cu acces aleatoriu, este un tip memorie RAM care folosește un semiconductor de memorie integrat (a se vedea figura 6). Acest tip de semiconductor folosește circuite logice combinaționale pentru a stoca fiecare bit, din această pricină reîmprospătarea datelor din memorie numai este necesară. Acest tip de memorie este considerat volatil, deoarece datele pot fi scrise și rescrise, iar ele sunt pierdute când alimentarea este întreruptă. Termenul “static” diferențiază memoria SRAM de DRAM, eliminând nevoie de a avea un ciclu de reîmprospătare a datelor. Memoria SRAM este mult mai rapidă și scumpă decât memoria DRAM, ea fiind folosită ca memoria principală și nivele de cache ale unui procesor modern. Din pricina prețului memoria SRAM este folosită pentru aplicații “low-cost” și nu este implementată la nivel înalt sau pentru aplicații cu operațiuni masive. Memoria SRAM este de tip “dual ported RAM” însemnând ce poate face operațiuni scriere și citire în același timp.
Figura 6. Memorie ram integrată de tip static (Capsulă CY62256NLL-70PXC SRAM )
(Sursă: http://uk.rs-online.com/web/p/sram-memory-chips/6427372/ [6])
Puterea consumată de o memorie variază față de memoria DRAM care de multe ori este fixă, variațiile depind de frecvența memoriei SRAM și cât de des este accesată, poate fi totuși la fel de consumatoare ca memoria DRAM când este folosită la nivelul ei maxim. În aplicațiile moderne memoria SRAM este folosită la un pas mai mic, microprocesoarele cu frevență mică sau moderată consumă putină putere când este în stare de “idle”.
Folosințele memorie statice:
În aplicații incorporate (ex. raspberry, arduino, placi micro sau nano, dispozitive industriale etc). Mărimea memoriei statice în aceste componente variază de la câțiva kilobiți la câțiva megabiți.
În calculatoare (ex. routere, switch-uri, hard disk-uri, procesor, imprimante, monitoare LCD).
Pasionați sau entuziasmați de tehnologii și circuite integrate, majoritatea componentelor și tutorialelor se găsesc în magazine online.
Tipuri de memorii statice:
Memorii statice non-volatile, sau “nvSRAM”, dețin aceiași funcționalitate ca memoriile statice dar salvează datele când alimentarea este oprită. Folosite foarte des în dispozitive de rețelistică, aeronautice, medicale, plus multe alte domenii.
În funcție de tipul tranzistorului:
Tranzistor cu conjuncție bipolară, foarte rapid dar consumator de putere.
“MOSFET” folosit de circuite “CMOS”, foarte comun și folosește putină putere.
Asincronă sau sincronă.
“Zero bus turnaround”, memoria statică de tip ZBT modifică numărul ciclurilor de ceas care are nevoie sa producă operațiunile de scriere/citire și vice-versa. Latența dintre ciclurile de scriere și citire este zero.
“syncBurst”, acces sincron cu viteza mare pentru a îmbunătăți operațiunile de scriere.
DDR SRAM, memorie sincronă cu porturi citire/scriere separate, rată de transfer I/O dublă.
QDR SRAM (“Quad data rate SRAM”), memorie sincronă cu porturi citire/scriere separate, rată de transfer I/O de patru ori mai mare.
Memorie SRAM binară sau Ternarry după modelul (“trinary computer”).
I.III.3.1 Funcția memoriei SRAM
Memoria SRAM funcționează diferit de memoria DRAM, o celulă de memorie este compusă din trei pană la șase tranzistori de tip mosfet(“metal–oxide–semiconductor field-effect transistor”) a se vedea în figura 6, fiecare bit de informație este stocat în patru tranzistoare (M1, M2, M3, M4) care formează două legături încrucișate și inversate. Această celulă de memorie are două stări stabile, 0 sau 1, iar cei doi tranzistori adiționali acționează ca un controlor pentru operațiuni de citire și scriere.
Figura 7. Circuitul unei memorii statice ram.
(Sursă: https://en.wikipedia.org/wiki/Static_random-access_memory [7])
Accesul la celulă se face prin linia WL (“Word Line”) a se vedea în figura 7, care controlează tranzistorii de acces M5 și M6, care la rândul lor controlează celula pentru a fi conectată la liniile cu informațiile din biți. În timpul accesărilor de citire, liniile de biți sunt comutate în sus sau jos de invertoarele din celula SRAM, această metodă îmbunătățește viteza lungimii de bandă comparativ cu memoria DRAM unde liniile de biți sunt conectate prin capacitori de stocare.
Stările memorie SRAM sunt următoarele:
Inactivă, dacă liniile WL nu sunt accesate, tranzistorii de acces sunt deconectați iar celulă intră într-un de ciclu de așteptare.
Mod de citire, în acest mod este necesar sa accesăm liniile WL cu o singură stare și un singur tranzistor de acces. La citiri intense sau pentru îmbunătăți procesul de citire, ciclul de citire este preîncălzit de ambele linii de citire, la aceste tipuri de citiri tensiunea variază în funcție de stările căutate.
Mod de scriere, în acest mod el va scrie valorile date la liniile WL, dacă dorim sa scriem 0, el va scrie 0 la liniile de biți, iar dacă vrem sa scriem 1 el va inversa valorile liniilor de biți.
II. Acceleratoare de date
Termenul de accelerator se referă la un program sau o metodă, prin care îmbunătățim viteza aplicației. Această metodă poate include modificare sau adăugări de funcționalități noi precum ar fi stocarea datelor volatile sau non-volatile în altă locație sau zonă specifică, memorie, mediu de stocare diferit, pentru a îmbunătăți viteza și timpul de acces.
Majoritatea acceleratoarelor functioneză ca proxy sau reverse-proxy, acestă metodă oferta posibilitatea de a adăuga mai multe servicii direct, fără a afecta aplicația originală.
Acceleratoarele pot fi de mai multe categorii, și anume:
Acceleratoare web, ele pot fi folosite ca servere de cache, proxy sau reverse proxy, sau chiar amplasate înaintea serverelor web (modelul varnish sau squid) pentru a reda datele din cache înainte de a face o cerere la serverele web.
Acceleratoare de baze de date, folosite ca sisteme de caching pentru rezultate din baza de date, ele sunt amplasate înaintea bazei de date, pentru a verifica dacă exista rezultatul înainte de a face un query la baza de date.
Acceleratoare de date, ele pot fi folosite ca sistem de caching pentru fișiere statice (exemplul CDN), sau ca accelerator pentru servere FTP(S)/SFTP.
Accelerator TCP, folosit ca un reverse-proxy pentru conexiuni persistente, poate menține conexiuni deschise cu alte servicii pentru a fi utilizate mai rapid.
Servere de compresii, acceleratoarele pot fi folosite pentru a compresa obiectele și cererile venit din spatele unui serviciu. Metoda de compresie folosește multă putere al procesorului, folosind acest serviciu putem ușura alte servicii.
III. Principii de design
În general pentru a crea o aplicație de tip “wrapper” cu care vom crea și administra o aplicație de “memory caching” avem nevoie de următoarele componente:
Memcached
Python 2.7 folosind librăriile:
os, sys, socket
pylibmc
configparser
argparse
getpass
PHP 5.5+ folosind librăriile:
php5-memcached
Debian GNU Linux:
libmemcached
memcached
repcached
Aplicația va comunica cu programul memcached și cu metodele proprii interne, pentru a realiza operațiuni de adăugare instanțe noi de memcached, de a crea un grup de instanțe și replicate, de a copia datele dintr-o instanță în alta fără o conexiune între ele, de a verifica statusul unei instanțe și de a verifica instanța dacă ascultă pe un port anume.
III.1 Rolul aplicațiilor și funcțiile lor
III.1.1 Ce este Memcached
Memcached este un sistem de stocare în memoria RAM de tip cheie valoare. Programul este gratuit cu sursele deschise “open-source”, oricine poate clona codul sau contribui la el . Este de tip distribuit, poate lucra în conjuncție cu alte instanțe de memcached, sau poate fi setat în modul “master-master” sau “master-slave”.
Memcached a fost creat de firma Danga Interactive INC, în anul 2003 pentru a ușura încărcarea site-ului LiveJournal.com. Inițial el a fost gândit doar pentru o singură folosință, după ce a fost publicat numele și codul sursă pe internet, proiectul a luat amploare, multe companii și utilizatori au început sa folosească programul pentru a-și îmbunătăți aplicația. Programul este scris în limbajul de programare C, folosind multe tehnologii moderne, gen pthreads, ultima versiune curentă este 1.4.25, iar cea din teste este 1.4.13.
Sursa: “Linux: aptitude info”
Memcached functionează după modelul server-client, unde clientul poate fi un driver de conectare, o bibliotecă al unui limbaj de programare sau o conexiune directă la portul implicit 11211. Datele din program sunt ținute în memorie folosind un algoritm intern de alocare a blocurilor de memorie și respectiv a datelor în funcție de mărimea lor. El poate stoca toate tipurile de variabile (int, double, long, string, hash), implicit valoarea maximă admisă este de 1 megabit care poate fi mărită la 128 megabiți.
Deoarece memcached folosește memorie ram ca mediu de stocare, el este foarte rapid la ambele operațiuni de scriere sau de citire. Principala lui funcție este de a stoca date care sunt folosite foarte des pentru a fi refolosite și accesa-te foarte rapid la următoarea cerere. În cele mai multe cazuri el este folosit ca accelerator pentru web, baze de date, a stoca fișiere statice și imagini.
III.1.2 Memcached ca accelerator universal
Putem folosi aplicația memcached ca un accelerator web, prin mai multe metode, cea mai utilizată și frecventă, el fiind propus în fata unei baze de date, stocând rezultatele pentru a fi servite rapid la următoare cerere, a se vedea figura 8.
.
Figura 8. Memcached folosit ca accelerator pentru baze de date.
Alt moduri în care putem folosi memcached:
Pentru a stoca sesiunile și datele sensibile alte utilizatorilor.
Accelerator web, prin adăugând memcached între aplicație și utilizator, a se vedea figura 9.
CDN -”Content Delivery Network,” Folosit ca server de stocare pentru fișiere statice pentru pagini web (js, css, jpg, png), a se vedea figura 10.
Figura 9. Memcached folosit ca accelerator web.
Figura 10. Memcached folosit ca serviciu de stocare a fișierelor statice.
III.1.3 Funcția memcached și metode de stocare
Memcached este un program de tip “key store”, care stochează datele în formă “cheie:valoare”, aceste date sunt stocate în “slabs”, denumirea din memcached pentru un bloc intern de memorie. Acestea sunt blocuri de memorie interne cu dimensiuni variabile de la 8 biți pana la 128 MB, iar înăuntrul fiecărui “slab” sunt alocate sectoare mai mici de date numite “chunk”. În fiecare “chunk” de 2kb putem introduce o cheie de dimensiune aproximativă de 2kb sau mai multe chei cu dimensiunea totală de 2 kb.
Funcția programului memcached este destul de simplă și direct la obiect, poate stoca, citi, incrementa, decrementa, verifica, șterge sau înlocui o valoare. Pentru fiecare valoare introdusă el verifică dimensiunea valorii și lista lui de blocuri “slabs” care se apropie de dimensiunea lui, apoi verifică valoarea cerută în blocul respectiv.
Memcached își alocă blocurile “slabs” dinamic în funcție de cerință si spațiul disponibil, aceste blocuri pot varia de la dimensiuni mici 8 biți pană la 128 MB). Aceste blocuri sunt generate îndată ce vina prima cerere de stocare cu dimensiunea valorii, de exemplu dacă vrem sa stocăm o valoare de 16 biți si nu avem bloc pentru ea, memcached automat alocă un bloc nou de memorie in funcție de mărimea valorii introduse și parametrul “ -I page size”, care ne permite sa modificăm limita de dimensiunea a unei valori stocate.
Alocare blocurilor “slabs” se fac incepând de la cea mai mică valoare pană la cea mai mare disponibilă, urmând exemplul n^2 unde n este dimensiunea variabile noastre si 2 este factorul de creștere a blocurilor. Ex. dacă alocăm 128 MB de ram aplicației memcached, ea va crea (dinamic) blocuri incepând cu cea mai mică valoare posibilă 8 biți pana la 1024MB, folosind următorul algoritm:
#!/usr/bin/env python
val = 0
arr = []
number = 0
while (val <= 10240000000):
suma=8192**2
val += suma
arr.append(val)
print "Created slab: #%s" % number + " with", val," bytes"
number += 1
if sum(arr) >= 10240000000:
break
Acest algoritm algoritm va crea o listă de valori, care vor fi asignate blocurilor de memorie.
Acestă alocare a blocurilor de memorie se aseamănă cu problema matematică “Pătratul perfect” de Martin Gardner, unde avem un bloc de valoare x iar y la puterea a doua este pătratul lui x. Aceeași asemănare o avem și la alocare blocurilor din memcached, în figura 9 putem observa problema pătratului perfect, unde valoarea totală reprezintă memoria alocată aplicației noastre, și fiecare pătrat reprezintă fiecare bloc de memorie începând de la cel mai mic pană la cel mai mare, în funcție de memorie disponibilă, a se vedea figura 11.
Sursă: https://ro.wikipedia.org/wiki/Pătrat_perfect [8]
Figura 11. Metoda de alocare a memoriei în memcached folosind metoda pătratul perfect, Sursă: [9] https://upload.wikimedia.org/wikipedia/commons/thumb/6/64/Squaring_the_square.svg/220px-Squaring_the_square.svg.png
Toate obiectele din memcached sunt alocate unui bloc de memorie sau “slab”, dacă un bloc este umplut cu date, va crea încă unul cu aceiași mărime dacă avem suficientă memorie disponibilă. Orice obiect are un termen de expirare exprimat în secunde, implicit 900 secunde sau 15 minute. Odată ce obiectele expiră ele sunt șterse din bloc, de un proces intern al lui memcached implicit. Când numai avem memorie liberă, memcached aplică algoritmul “LRU – Least Recently Used” însemnând obiectul utilizat cel mai puțin recent, prin care începe un ciclu de citire a blocurile, a datalor și timpul de expirare a acestora, primul bloc care îl citește va fi cel în care a fost prima cerere de stocare ex(blocurile de 2kb) , de acolo va șterge obiectul cel mai puțin folosit, pentru a face loc obiectelor noi.
Acestă metodă se numește evacuare sau evacuări “evictions”, în memcached, numărul total al evacuărilor sunt ținute într-o listă, care poate fi accesată din pagina de status al programului.
Sursă: “pagina de ajutor al memcached din GNU Linux”
III.1.4 Python 2.7.x și librăriile dependente
Am folosit Python 2.7.x deoarece el vine preinstalat pe orice distribuție Debian GNU Linux, și nu avem nevoie sa instalăm prea multe dependințe. În aplicația noastră “PYRepPool” care o folosim ca un “wrapper” pentru a controla instanțele de memcached, folosește următoarele librării:
sys (funcțiile de bază ale lui Python: sys.exit(), sys.exc_info())
os (funcțiile de baza ale sistemului de operare: os.system)
subprocess (modul de management al subproceselor, folosit pentru a porni un proces în sistemul din python)
pylibmc (conectorul pentru memcached din python)
argparse (librările pentru parsarea argumentelor din cli, folosit pentru a crea pagina de ajutor)
configparser (folosit pentru a parsa și citi fișierul de configurare)
socket (folosit pentru a verifica porturile aplicațiilor)
getpass (folosit pentru a verifica utilizatorul care rulează aplicația)
III.1.5 PHP 5.5 și librăriile dependente
Am folosit PHP 5.5 pentru a crea un simplu API (“Application programable interface”) numit “api.php” care lucrează cu memcached, folosind modelul server-client, pentru a ușura modul de comunicare, eliminând nevoie de a instala librăriile conectoare și dependintele sale. Aplicația functioneaza folosind metodele http (GET, POST, DELETE):
GET – caută și afișează o variabilă
Cerere
root@ubuntu:~/PYRepPool# curl http://10.0.0.2:8000/get/?val=TEST
Răspuns:
Response: OK
Type: string
Value : '2^n/100 3-1/0'
POST – stochează o variabilă
Cerere:
root@ubuntu:~/PYRepPool# curl –data "var_name=TEST&var_value='2^n/100+3-1/0'" http://10.0.0.2:8000
Răspuns:
Response: OK
Type: string
Value : TEST was set
DELETE – șterge variabila
Cerere:
root@ubuntu:~/PYRepPool# curl -X DELETE http://10.0.0.2:8000/TEST
Răspuns:
TEST was deleted
Pentru a realiza conexiunea și comunica cu programul memcached, a fost nevoie de librăria php5-memcached și libmemcached (bibliotecă de sistem din linux).
III.1.6 PyRepPool
PyRepPool este aplicația concepută de mine, am gândit-o pentru a lucra ca un “wrapper”, o aplicație dependentă de un program (memcached). Cu acestă aplicație putem reduce dimensiunea comenzilor și complexitatea lor din programului memcached, si anume:
crea instanțe simple sau replicate
copia cheile dintr-o instanță și să le încărcam în altă instanță.
verifica integritatea datelor
crea un API HTTP pentru clienții care nu doresc să se conecteze direct la program
crea un grup de instanțe memcached
IV. Funcția aplicației PyRepPool
Aplicatia “PyRepPool” funcționează ca un “wrapper”, o aplicație dependentă de programul memcached, care ajută la simplificarea comenzilor și a uzuabilității. PyRepPool este un program de tip cli (“command line interface”), el funcționează ca un program normal, apelat direct cu parametric (a se vedea exemplul 1.)
-h, –help arată acest mesaj
–add ADD Adaugă o instanță de memcached
–api [API] Pornește un API PHP pe portul 8000 și ip-ul 127.0.0.1
–create CREATE crează o instanță de memcached Master/Slave sau
Master/Master
–check CHECK Verifică statsul unei instanțe memcached
–dump DUMP Descarcă cheile dintr-o instanță memcached, folosește portul implicit 11212
–file [FILE] Numele fișierului unde se salvează sau se importă cheile
–import IMPORT_KEYS Importă cheile descărcate intr-o instanță memcached
–ip [IP] Adresa IP al instanței memcached
–memory [{64,128,256,512,1024}]
Memoria instanței memcached
–port [PORT] Portul demonului, implicit [11211]
–rep-ip [REP_IP] Adresa IP al instanței memcached de replicat
–rep-port [REP_PORT] Portul demonului al instanței memcached de replicat, implicit [11212]
–test_replication TEST_REP Testează replicarea intre 2 instanțe memcached
Exemplul 1. Pagina de ajutor al programului PYRepPool
Cu aceste funcții și parametrii putem administra aplicația memcached, numele funcțiilor și a parametrilor au fost concepute în limba engleză deoarece termenii sunt mai simpli de utilizat și explicat, funcțiile aplicației PyRepPool sunt următoarele:
add (adaugă), aplicația verifică prima dată daca pe portul specificat nu rulează deja o aplicație, dacă da execuția se oprește si ne afișeaza un mesaj de avertizare. Dacă nu, programul va începe sa compună comanda, verifică și validează parametrii, iar în final va excuta comanda. Comanda respectivă arată în felul următor:
./PYRepPool –add yes –memory 64 –port 11311 –rep-port 11511 –ip 127.0.0.1
Parametrul “–add cu valorea yes” este funcția principală, care crează o instantă a programului memcached, folosind parametrii “–memory” care definește memorie pe care instanța, portul de rețea pe care va asculta, acestă valoare este implicit 11311, portul de replicare cu care comunică cu alte instanțe de memcache, și ip pe care va fi accesat, implicit 127.0.0.1. După ce validează toți acesti parametri, el va compune comanda de cli care va arată în forma următoare:
/usr/local/bin/memcached -m 64 -l 127.0.0.1 -p 11311 -d -X 11511
create (creează), deși numele se aseamănă cu adaugă, am ales sa folosesc create deoarece cu aceste parametru creăm 2 aplicații interconectate între ele. Aplicația verifica din nou daca portul nu este folosit, dacă da va afișa un mesaj de avertizare si va opri execuția. Dacă nu, ea va verifica și valida parametrii, iar în final va executa comanda. Comanda respectivă arată în felul următor:
./PYRepPool –create yes –memory 64 –port 11411 –rep-port 11511 –ip 127.0.0.1 –rep-ip 127.0.0.1
Parametrul “–create cu valoare yes” este funcția principală, parametrii au același rol cu excepția parametrului “–rep-ip”, el se referă la ip instanței cu care vrem sa facem conexiune replicată, si parametrul “–rep-port” se referă la portul de replicare instanței principale sau cea numită master. Dupa ce programul validează parametrii comanda de cli care va fi executată va arată în felul următor:
/usr/local/bin/memcached -m 64 -l 127.0.0.1 -p 11411 -d -X 11511 -x 127.0.0.1
check (verifică), aplicația verifică portul și ip-ul dacă sunt disponibile, ea crează un “socket”, de acolo se conecteză la parametrii dați de noi, returneză eroare dacă ip-ul si portul sunt folosite, daca nu returnează sucess, comanda cli este listată mai jos.
./PYRepPool –check yes –ip 127.0.0.1 –port 11211
dump (descarcă), această funcție ne permite să descărcăm toate cheile instanței noastre de memcached, o modalitate unicată pe piața, putem face salvări la diferite intervaluri pentru a asigura o copie de rezervă a datelor, integritate sau pentru a fi incărcate în alte instanțe. Aplicația se conectează la portul de replicare a programului memcached (doar dacă nu este folosit în mod master-master sau master-slave, atunci portul nu va fi liber), si de acolo primește o lista de chei care va fi salvată intr-un fisier binar, comanda cli este listată mai jos.
./PYRepPool –dump yes –ip 127.0.0.1 –port 11212 –file keys.bin
import_keys (incarcă chei), este funcția opusă a “dump”, cu ea putem incărca cheile intro instanță memcached. Aplicația crează o conexiune la portul de replicare (ex. 11212) asteaptă mesajul “marugoto_end” care semnifică, instanța este pregatită pentru a accepta date, apoi trimite datele din fișierul nostru și returnează succes sau eșuat după caz, comanda cli este listată mai jos.
./PYRepPool –import yes –ip 127.0.0.1 –port 11212 –file keys.bin
test_rep (testează replicarea), această funție ne permite să testem dacă funcționează replicarea între 2 instanțe memcached conectate între ele indiferent de mod (MM sau MS). Acestă funcție se conectează la prima instanța denumită master și seteaza o cheie de test cu valore mică, daca fost cu succes, se conectează apoi pe a doua instanță denumite slave,si cauta cheia de teste acolo, dacă a fost cu succes va afisa un mesj de informare, dacă nu va returna un mesaj de eroare. Conexiunea se face cu conectorul pylibmc, iar comanda de cli arată în felul următor.
./PYRepPool –test_replication yes –ip 127.0.0.1 –port 11411 –rep-ip 127.0.0.1 –rep-port 11511
api, (interfață de aplicație programabilă), este un program separat de PYRepPool, conceput de mine și scris în PHP 5.5, acest fișier (api.php), poate fi rulat ca un demon de sine stătător sau poate fi rulat prin Apache2, Nginx, Lighthttp sau orice alt program care poate interpreta limbajul PHP. Scopul lui este de a ușura accesabilitatea la programul memcached sau pentru a fi folosit la operțiuni web. Este simplu de rulat și utlizat, doar trebuie configurat cu parametrii necesari (ip-ul și portul instanței de memcached). Apoi putem face cereri http (GET, POST, DELETE) pentru a înlocui operațiunea de conectare cu driverul memcached. Funcționalitatea lui este destul de simplă, se conectează la instanța de memcached, de acolo interpretează comenzi http în comenzi simple, urmând exemplul următor.
curl "http://127.0.0.1:8000/get/?val=asd", de aici aplicația api interpretează și rulează comanda următoare, GET asd in memcached. Comanda cli arată astfel:
./PYRepPool –api yes –port 8000 –ip 127.0.0.1
V. Teste comparative și de performanță
Am făcut câteva teste de perfomanță pentru a arâta performanțele aplicației memcached sub diferite medii și componente. Testele au fost rulate atât în medii dedicate cât și cloud.
V.1. Platformă de testare: Local VM
HW: Masină virtuală cu 2 procesoare i5-4210U CPU @ 1.70GHz (1GB memorie RAM DDR3)
Testul 1. Inserare de 1000 de valori, fiecare valoare 32 KB
root@ubuntu:~/PYRepPool# time php ins.php
ok
real 0m40.015s
user 0m0.662s
sys 0m0.722s
De aici rezultă 0.04 secunde pentru a stoca o cheie de 32 kb, la un calculator cu 2 procesoare.
Testul 2. Inserare de 1000 de valori, fiecare valoare 256 KB
./PYRepPool/Tools# time php mem_ins.php
ok
real 0m55.775s
user 0m13.468s
sys 0m1.059s
Putem observa la valori mai mari și multe, durează puțin mai mult, detrimentul aici fiind limitare hardware a hdd-ului.
Testul 3. Inserare de 100 de valori, fiecare valoare 1 MB
root@ubuntu:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m9.951s
user 0m5.750s
sys 0m0.270s
La valori mari durează mult mai puțin, din nou detrimentul fiind limitarea hardware.
Testul 4. Inserare de o singură valoare cu mărimi diferite, 1, 5, 10, 50, 100 MB
1MB
root@ubuntu:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.049s
user 0m0.010s
sys 0m0.005s
5MB
root@ubuntu:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.068s
user 0m0.019s
sys 0m0.005s
10MB
root@ubuntu:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.077s
user 0m0.023s
sys 0m0.011s
50MB
root@ubuntu:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.192s
user 0m0.055s
sys 0m0.093s
100MB
root@ubuntu:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.949s
user 0m0.042s
sys 0m0.556s
Timpuri bune de stocare, respectând standardul “Google” de încărcare și scriere sub o secundă.
V.2 .Platformă de testare: AWS EC2
Hardware: t2.micro 1CPU, 1GB RAM
Pentru teste mai modern și precise, am folosit platforma “Platform as a service” Amazon Web Services.
Testul 1. Inserare de 1000 de valori, fiecare valoare 32 KB
root@ip-172-31-39-40:~/PYRepPool/Tools# time php mem_ins.php
real 0m1.177s
user 0m1.016s
sys 0m0.068s
Testul 2. Inserare de 1000 de valori, fiecare valoare 256 KB
root@ip-172-31-39-40:~/PYRepPool/Tools# time php mem_ins.php
real 0m48.919s
user 0m11.648s
sys 0m0.288s
Testul 3. Inserare de 100 de valori, fiecare valoare 1 MB
root@ip-172-31-39-40:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m16.603s
user 0m8.604s
sys 0m0.256s
Testul 4. Inserare de o singură valoare cu mărimi diferite, 1, 5, 10, 50, 100 MB
1MB
root@ip-172-31-39-40:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.248s
user 0m0.232s
sys 0m0.012s
5MB
root@ip-172-31-39-40:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.310s
user 0m0.236s
sys 0m0.020s
10MB
root@ip-172-31-39-40:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.529s
user 0m0.460s
sys 0m0.016s
50MB
root@ip-172-31-39-40:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m2.381s
user 0m2.240s
sys 0m0.080s
100MB
root@ip-172-31-39-40:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m4.640s
user 0m4.420s
sys 0m0.168s
Din teste viteza serviciilor AWS sunt mai slabe decăt cele din masina virtuală locală, dar din pricina prețului masinile sunt limitate la operațiuni I/O.
V.3 .Platformă de testare: Dell Poweredge 1950
Hardware: 2 x Intel Xeon E5420 @ 2.50GHz, 16GB RAM
Testul 1. Inserare de 1000 de valori, fiecare valoare 32 KB
root@gits:~/PYRepPool/Tools# time php mem_ins.php
real 0m16.071s
user 0m14.568s
sys 0m1.112s
Testul 2. Inserare de 1000 de valori, fiecare valoare 256 KB
root@gits:~/PYRepPool/Tools# time php mem_ins.php
real 0m16.454s
user 0m15.572s
sys 0m0.488s
Testul 3. Inserare de 100 de valori, fiecare valoare 1 MB
root@gits:~/PYRepPool/Tools# time php mem_ins.php
real 0m7.335s
user 0m6.372s
sys 0m0.260s
Testul 4. Inserare de o singură valoare cu mărimi diferite, 1, 5, 10, 50, 100 MB
100MB
root@gits:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.126s
user 0m0.008s
sys 0m0.004s
50MB
root@gits:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.125s
user 0m0.004s
sys 0m0.008s
10MB
root@gits:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.016s
user 0m0.004s
sys 0m0.008s
5MB
root@gits:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.016s
user 0m0.012s
sys 0m0.000s
1MB
root@gits:~/PYRepPool/Tools# time php mem_ins.php
ok
real 0m0.016s
user 0m0.004s
sys 0m0.008s
Tabel comparativ test nr.1,2,3
Tabel comparativ test nr.4
V.4. Teste comparative: Squid3 vs Varnish vs memcached
Testul 1. Redare pagină web cu 2 imagini de 5 megabiți fiecare (unitatea de măsură: ms, mai mic este mai bine)
Fară accelerator: 1940 ms
squid3: 738 ms
memcached: 337 ms
varnish: 266 ms
Testul 2. Redare pagină web cu 2 imagini de 10 megabiți fiecare (unitatea de măsură: ms, mai mic este mai bine)
Fară accelerator: 815 ms
squid3: 772 ms
varnish: 621 ms
memcached: 542 ms
Testul 3. Redare pagină web cu 2 imagini de 50 megabiți fiecare (unitatea de măsură: ms, mai mic este mai bine)
varnish: 4271 ms
Fară accelerator: 3890 ms
squid3: 3690 ms
memcached: 3329 ms
Testul 4. Redare pagină web text de dimensiune mare (unitatea de măsură: ms, mai mic este mai bine)
Fară accelerator: 27 ms
squid3: 10 ms
varnish: 6 ms
memcached: 6 ms
Figura 12. Tabel comparativ valori măsurate.
VI. Concluzii
Din testele concepute, aplicația memcached este intradevăr rapidă și la stocare și la citire, depinde foarte mult de componentele hardware al echipamentului pe care folosim aplicația. Aplicația memcached se apropie cu performanța programului varnish, din teste putem observa că nu putem folosi memcached în toate ipostazele.
Aplicația memcached folosește threads pentru a-și impărți funcțiile interne, acestă metoda este distribuită în nucleele procesoarelor (dacă numărul de nuclee este mai mare decăt 1). Acestă metodă plus anumite operațiuni sunt consumatoare de procesor și de memorie. Din experiența mea profesională pot spune ca, aplicația memcached este mai rapidă daca folosim tipuri de memorii DDR mai noi, începănd de la DDR2 pînă la ultima generație DDR4. Desigur și tipul și modelul de procesor contează foarte mult, un procesor cu frecvența mai mare și mai multe nuclee are rol important în performanța aplicației.
Din teste cu medii de testare putem observa, aplicația memcached funcționează cel mai bine pe medii dedicate cu resurse directe. Din experiența mea, de multe ori am instalat memcached pe un mediu dedicat cu resurse propii, aceste 2 cerințe au îmbunătățit performanțele aplicației cu minim 50%. Limitele aplicației nu am reușit să le ating, am folosit memcached pe un mediu cu 25 servere dedicate (Dell PowerEdge R730 cu procesoare de 72 nuclee și 512GB de ram) care făceau aproximativ 40.000 de conexiuni și aprox 56.000 operațiuni pe secunda. Totul pe o singură instanța cu 16GB de ram și un procesor cu 4 nuclee.
Folosind aplicația “PyRepPool” putem ușura munca noastră, crea mai multe instanțe de memcached, mai rapid, și le putem administra fară cunoștiințe generale de memcached. Am încredere precum aplicația mea, va ajuta programatorii, inginerii noi sau senior de sistem sau alți curioși de programul memcached, să iși configureze instanțele.
VII. Bibliografie
“How SDRAM memory works“ https://embeddedmicro.com/tutorials/mojo/sdram accesat 05.05.2016 11:20
“DDR SDRAM” https://en.wikipedia.org/wiki/DDR_SDRAM accesat 05.06.2016 16:35
“Memorii statice” https://en.wikipedia.org/wiki/Static_random-access_memory accesat 02.05.2016 09:40
“memcached” https://en.wikipedia.org/wiki/Memcached accesat 04.05.2016 13:33
“LRU Algorithm” https://www.adayinthelifeof.nl/2011/02/06/memcache-internals/ accesat 07.05.2016 11:40
“Web accelerators” https://en.wikipedia.org/wiki/Web_accelerator accesat 02.05.2016 09:40
Sursa [1] “https://en.wikipedia.org/wiki/Random-access_memory#History” accesat 02.05.2016 19:56
Sursa [2] “https://en.wikipedia.org/wiki/Memcached#History” accesat 02.05.2016 22:12
Sursa [3] “http://www.pcgarage.ro/memorii-server/crucial/ecc-rdimm-ddr4-8gb-2133mhz-cl15-single-rank-x4/” accesat 07.06.2016 11:20
Sursa [4] Karbosguide.com accesat 03.06.2016 23:45
Sursa [5] http://www.transcend-info.com/Support/FAQ-296 accesat 08.06.2016 10:06
Sursa [6] http://uk.rs-online.com/web/p/sram-memory-chips/6427372/%20 accesat 05.06.2016 14:20
Sursa [7] https://en.wikipedia.org/wiki/Static_random-access_memory accesat 05.06.2016 15:30
Sursa [8] https://ro.wikipedia.org/wiki/Pătrat_perfect accesat 05.06.2016 15:30
Sursa [9] https://upload.wikimedia.org/wikipedia/commons/thumb/6/64/Squaring_the_square.svg/220px-Squaring_the_square.svg.png
Figura 1, Sursa [3] accesat 07.06.2016 11:25
Figura 4, Sursa [4] accesat 03.06.2016 23:45
Figura 5, Sursa[5] accesat 08.06.2016 10:06
Figura 6, Sursa [6] accesat 05.06.2016 14:20
Figura 7, sursa [7] accesat 05.06.2016 15:30
Figura 11, Sursa [9] accesat 05.06.2016 19:30
Figura 2,3,8,9,10,12 design propriu.
DECLARAȚIE DE AUTENTICITATE
privind elaborarea lucrării de licență
Subsemnatul/subsemnata Mantale Alin Andrei declar pe propria răspundere că:
lucrarea a fost elaborată personal și îmi aparține în întregime;
nu au fost folosite alte surse decât cele menționate în bibliografie;
nu au fost preluate texte, date sau elemente de grafică din alte lucrări sau din alte surse fără a fi citate și fără a fi precizată sursa preluării, inclusiv în cazul în care sursa o reprezintă alte lucrări ale mele;
lucrarea nu a mai fost folosită în alte contexte de examen sau de concurs.
Data, Semnătura,
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Acceleratoare Web Folosind Memorii Volatile Si Replicate (ID: 108621)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
