9.7 Mérés és profiling alapok
Áttekintő
Az előző alfejezetekben sokat beszéltünk arról, mit érdemes optimalizálni. De hogyan tudod meg, hogy kell-e egyáltalán optimalizálni valamit, és ha igen, hol kell belenyúlni a kódba?
A válasz: méréssel.
Ez az alfejezet azt mutatja be, hogyan mérj teljesítményt helyesen – ne találgatással, ne érzésre, hanem adatokkal. Megismered a legfontosabb mérési eszközöket és módszereket, és megtanulod, mikor elég egy egyszerű console.time(), és mikor kell komolyabb profilozóeszköz.
Amit tanulsz:
- Mi a különbség a benchmarking és a profiling között
- Hogyan mérj válaszidőt backend oldalon
- Hogyan használd a böngésző DevTools Performance tabját
- Mikor automizálj mérést és mikor elég a manuális megközelítés
- Hogyan értelmezd a mért adatokat és döntsd el, mit optimalizálj
Miért számít ez az állásinterjún?
Ha egy interjún azt kérdezik: „Hogyan közelítenél meg egy lassú oldalt?", és azt mondod: „Mérnék először" – ez azonnal megkülönböztet a többi junior jelentkezőtől, akik rögtön kódot kezdenének módosítani.
Miért számít production-ben?
Vak optimalizálással rengeteg időt lehet elvesztegetni olyan dolgokra, amelyek nem okozzák a tényleges problémát. A mérés megmutatja, hol az igazi szűk keresztmetszet.
Részletes leírás
Mérés előtt: tisztázd, mit mész
Mielőtt elindítod a stoppert, tudnod kell, mit mész. A teljesítménymérés három kérdésre keresi a választ:
- Mennyit? – Mennyi ideig tart egy adott művelet? (Idő)
- Hol? – A kód melyik részén töltődik el a legtöbb idő?
- Miért? – Mi az oka a lassúságnak?
Az első kérdésre benchmarking, a másodikra és harmadikra profiling ad választ.
Benchmarking vs. profiling – mi a különbség?
Ez a két fogalom sokszor összekeveredik, de különböző kérdésekre válaszolnak.
Benchmarking = Mennyi ideig tart?
Megméred, hogy egy adott kódrészlet, endpoint, vagy rendszer milyen gyorsan fut. Eredménye egy szám (pl. „ez az API endpoint átlagosan 240ms alatt válaszol").
Mire jó?
- Összehasonlítás: most gyorsabb, mint korábban?
- Teljesítmény-küszöb betartása: az SLA 500ms-t mond, mi 240ms-en vagyunk – megfelel-e?
- Regresszió-detektálás: egy változtatás után lassabb lett-e valami?
Profiling = Hol töltődik el az idő?
Megmutatja, hogy a futás alatt a kód melyik részén mennyi időt töltött a program. Eredménye egy térkép: „a teljes futásidő 70%-a az adatbázis-lekérésben ment el, 20% a fájlírásban, 10% a logikában".
Mire jó?
- Szűk keresztmetszet azonosítása
- Váratlan teljesítménybeli problémák feltérképezése
- „Hol nyúljak bele?" kérdés megválaszolása
Analógia:
Benchmarking = megméred, hogy 100 métert mennyi idő alatt futottál le.
Profiling = kiderítjük, hogy az idő 60%-ában cipőfűzőt kötöttél.
Backend response time mérése
Az egyszerű megközelítés: manuális időzítés
Ha gyorsan kell egy számot, a legtöbb nyelvben van egyszerű időmérési eszköz.
Python:
import time
start = time.time()
result = do_something_slow()
end = time.time()
print(f"Elapsed: {(end - start) * 1000:.2f}ms")
JavaScript (Node.js):
console.time('my-operation');
const result = doSomethingSlow();
console.timeEnd('my-operation');
// Kimenet: my-operation: 243.521ms
PHP:
$start = microtime(true);
$result = doSomethingSlow();
$end = microtime(true);
echo "Elapsed: " . round(($end - $start) * 1000, 2) . "ms";
Ez hasznos fejlesztés közben, ha gyorsan szeretnéd tudni, hogy egy konkrét kódrészlet mennyit fut.
Logging és monitoring production-ben
Fejlesztői print/console.log időmérés production-ben nem elegendő. Helyette:
- Request logging: minden HTTP kéréshez logold a válaszidőt (ezt sok framework automatikusan megteszi)
- Application Performance Monitoring (APM): eszközök, amelyek automatikusan gyűjtik és vizualizálják a teljesítményadatokat (pl. New Relic, Datadog, Sentry Performance)
- Slow query log: adatbázis szinten logolható, ha egy lekérdezés egy adott idő felett van
Junior fejlesztőként ritkán te állítod be ezeket – de tudnod kell, hogy léteznek, és hogyan olvasd az eredményeket.
Amit nézz: p50, p95, p99
Ha egy endpoint válaszidejét vizsgálod, ne csak az átlagot nézd. Az átlag elfedheti a problémát.
| Mérőszám | Jelentés |
|---|---|
| p50 (medián) | A kérések 50%-a ennyi ms alatt válaszol |
| p95 | A kérések 95%-a ennyi ms alatt válaszol |
| p99 | A kérések 99%-a ennyi ms alatt válaszol |
Ha az átlag 100ms, de a p99 8000ms, az azt jelenti, hogy minden 100. felhasználó 8 másodpercet vár. Ez érzékelhető probléma, az átlag mégis „szépnek" tűnik.
Browser DevTools Performance tab
A Chrome (és más modern böngészők) beépített Performance eszköze az egyik leghasznosabb profiling eszköz frontend fejlesztéshez – és ingyenes.
Hogyan nyisd meg és rögzíts
- F12 (vagy jobb klikk → Inspect)
- Kattints a Performance tabra
- Kattints a piros rögzítés gombra (⏺)
- Végezd el a lassúnak tűnő műveletet
- Kattints a Stop gombra
Mit látsz a felvételen?
Flamegraph (lángtérkép)
A legfontosabb nézet. Mutatja, hogy a böngésző mit csinált és mennyi ideig. Egy széles sáv = sok idő telt el abban a funkcióban. A mélység = egymásból hívott függvények.
Fő kategóriák, amiket nézz:
- Scripting (JS futtatás): sok időt vesz el? Lehet JS-optimalizációra szükség
- Rendering: az oldal újrarajzolása – sok layout-reflow jele lehet
- Painting: pixelek kirajzolása – intenzív animációknál jellemző
Konkrét dolgok, amit keress juniorként:
- Hosszú script blokkok (>50ms) – ezek blokkolhatják a UI-t
- Sok és ismétlődő re-render – felesleges állapotváltozás jele
- Nagy hálózati kérések – Network tab-on látható az ideje és mérete
Tipp: Ne ijedj meg, ha elsőre sok mindent nem értesz. A Performance tab mély eszköz. A legfontosabb, hogy meg tudd nyitni, rögzíts egy felvételt, és azonosítsd, hol töltődik el a legtöbb idő.
Network tab – a gyors győzelem
Ha az oldal lassú, először mindig nézd meg a Network tabot, mielőtt mélyre mész a Performance tabban:
- Mennyi ideig tartanak a kérések?
- Van-e feleslegesen nagy fájl (pl. 5MB-os kép, tömörítetlen JavaScript)?
- Sorban állnak-e egymás után kérések, amelyek párhuzamosan is mehetnének?
- Van-e 404 vagy 500 hiba, ami újra-kéréseket okoz?
Sokszor a leglassabb oldal nem a JavaScript, hanem egy 10MB-os kép vagy egy 2 másodpercig váró API hívás.
Profiling backend kódban
Python: cProfile
import cProfile
cProfile.run('my_slow_function()', sort='cumulative')
Kimenet: táblázat, amelyben látható, hogy melyik függvény hányszor lett meghívva és mennyi ideig futott összesen.
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.243 1.243 my_code.py:10(my_slow_function)
1000 1.230 0.001 1.230 0.001 my_code.py:25(database_query)
Ebből látszik: database_query 1000-szer lett meghívva, és ez viszi el az idő 99%-át. Valószínűleg N+1 query-ről van szó.
Node.js: --prof flag
node --prof my_app.js
# Generál egy isolate-*.log fájlt
node --prof-process isolate-*.log > profile.txt
PHP: Xdebug vagy Blackfire
PHP-ban az Xdebug profiler vagy a Blackfire.io eszköz a legelterjedtebb. Ezeket általában fejlesztői környezetben futtatják, production-ben kerülik, mert lelassítják az alkalmazást.
Általános tanács: profilozz fejlesztési/staging környezetben
A legtöbb profiling eszköz overhead-del jár – maga a mérés lassítja a programot. Éles production-ban ne hagyd bekapcsolva állandóan a profiling eszközt. Futtasd fejlesztésben, staging-en, vagy production-ban rövid időre, ha konkrét problémát kell diagnosztizálni.
Mikor elég a manuális mérés, mikor kell automatizálni?
Manuális mérés elég, ha:
- Egyszeri kérdésre keresel választ: „Ez a függvény lassú-e?"
- Fejlesztés közben gyors visszajelzésre van szükséged
- Nincs production teljesítményproblémád, csak fejlesztői kíváncsiság
Automatizált mérés kell, ha:
- Regressziót akarsz elkerülni (CI pipeline-ban futó performance benchmark)
- Production rendszer folyamatos monitorozásra szorul
- SLA betartását kell bizonyítanod
- Terheléstesztet végzel (pl. k6, JMeter, Locust eszközökkel)
Junior fejlesztőként valószínűleg ritkán állítasz be CI pipeline-os performance tesztet. De ha a csapatodban van ilyen rendszer, tudnod kell olvasni az eredményeket és érteni, mire figyelmeztetheti.
A mérési folyamat junioroknak
Ha egy lassúság-panasz érkezik (felhasználótól, projektmenedzsertől, csapattárstól), ez a javasolt megközelítés:
- Reprodukáld – Te is látod a lassúságot? Milyen feltételek mellett?
- Mérd meg – Pontosan mennyi ideig tart? Minden esetben, vagy csak bizonyos feltételek mellett?
- Lokalizáld – Frontend, backend, adatbázis, hálózat? Melyik rész a lassú?
- Profilozz – Azon a rétegen belül, mi a szűk keresztmetszet?
- Hipotézis és javítás – Mit változtatsz, és miért gondolod, hogy segít?
- Ellenőrizd a javítást – Tényleg gyorsabb lett? Mérj újra!
Ez a folyamat akkor is működik, ha csak console.time()-ot és Network tabot használsz. A lényeg a szisztematikusság, nem az eszköz.
Életszerű példák
Példa 1: „Az oldal lassú" – hol kezdj?
Szituáció: A csapat Slack-jén jön az üzenet: „Az admin felületen a felhasználólista töltése nagyon lassú, 10+ másodperc."
Amit junior tapasztalat nélkül csinálna:
Egyből belemegy a kódba, elkezdi „optimalizálni" a JavaScriptet, esetleg hozzáad cache-t – találomra.
Amit méréssel csinálsz:
- Megnyitod a Network tabot – Látod: egy API hívás (
GET /api/users) 9800ms-t vesz igénybe. A frontend nem a probléma. - Backend logot nézel – Az endpoint log azt mutatja: az adatbázis lekérdezés 9600ms.
- SQL EXPLAIN-t futtatsz – Kiderül: nincs index a
created_atoszlopon, amin szűrnek. Full table scan fut 2 millió soron. - Index hozzáadása – 50ms-re csökken a válaszidő.
- Újramérés – Megerősíted, hogy tényleg megoldódott.
Tanulság: A Network tab 30 másodperce megmutatta, hogy nem a frontend a probléma. Ha vak optimalizálással kezdtük volna, napokat elpazarolhattunk volna.
Példa 2: Benchmark – romló-e a teljesítmény?
Szituáció: Egy refaktorálás előtt és után le akarod ellenőrizni, hogy a változtatás nem rontotta-e a teljesítményt.
import time
import statistics
def benchmark(func, iterations=100):
times = []
for _ in range(iterations):
start = time.perf_counter()
func()
end = time.perf_counter()
times.append((end - start) * 1000) # ms
print(f"Átlag: {statistics.mean(times):.2f}ms")
print(f"Medián: {statistics.median(times):.2f}ms")
print(f"Min: {min(times):.2f}ms, Max: {max(times):.2f}ms")
benchmark(old_implementation)
benchmark(new_implementation)
Ez egy egyszerű, de hasznos megközelítés: 100-szor mérsz, hogy kiátlagold a véletlenszerű ingadozásokat.
Fontos: Egyetlen mérés nem elég. A CPU terheltsége, az operációs rendszer más folyamatai, a cache állapota mind befolyásolják az eredményt. Mindig több iteráció átlagát nézd.
Példa 3: DevTools flamegraph értelmezése
Szituáció: Egy gombkattintás után az oldal 2 másodpercig nem reagál semmire.
Performance tab rögzítés után a flamegraph-on látod:
[click handler - 1980ms]
└─ [processItems - 1950ms]
└─ [filterByDate - 1200ms]
└─ [sortItems - 740ms]
Ebből látszik:
- A
filterByDateveszi el az idő 62%-át - A
sortItemsveszi el a 38%-át - Ha csak a
filterByDate-et javítod, máris felére csökkented a teljes futásidőt
Ezek nélkül az adat nélkül vakon próbálgathattad volna, hogy melyik részben van a probléma.
Példa 4: „Gyorsabb lett" – de tényleg?
Szituáció: Optimalizálás után úgy tűnik, gyorsabb lett az oldal. De biztos vagy benne?
Helytelen megközelítés: „Korábban lassúnak tűnt, most gyorsabbnak tűnik."
Helyes megközelítés:
Előtte: 5 mérés átlaga = 2340ms (p95: 3100ms)
Utána: 5 mérés átlaga = 340ms (p95: 420ms)
Most már bizonyítékod van. És ha jövőre valaki visszakérdez, hogy „mikor lassult be az oldal?", van egy mérési kiindulópontod.
Feladatok és tesztek
Gyakorlati feladat
Teljesítmény-mérési terv
Kapsz egy feladatot: „A terméklista oldal lassú, különösen sok termék esetén."
Állítsd össze a mérési tervet az alábbi szempontok szerint:
- Milyen eszközzel mérnéd először, hogy a frontend vagy a backend a lassú? Miért?
- Ha a backend a lassú, milyen adatot szeretnél látni a logban?
- Hogyan különböztetnéd meg, hogy az adatbázis-lekérdezés vagy a feldolgozási logika a probléma?
- Miután megtaláltad a problémát és javítottad: hogyan ellenőrzöd, hogy a javítás tényleg segített?
- Mit jelent az, hogy „p95 = 800ms"? Ez jó eredmény-e, ha az elvárás az, hogy az oldal 1 másodpercen belül betöltödjön?
(Nem kell kódot írni – szöveges tervként is megadható a válasz.)
Tesztkérdések
1. Mi a különbség a benchmarking és a profiling között?
a) Benchmarking csak frontend-re, profiling csak backend-re vonatkozik
b) Benchmarking azt méri, mennyi ideig tart egy művelet; profiling megmutatja, a kód melyik részén töltődik el az idő
c) Benchmarking automatikus, profiling manuális mérési módszer
d) Profiling az egyetlen pontos mérési módszer, a benchmarking csak becslés
(Helyes: b)
2. Az alábbi Python kódrészlet mit mér?
import time
start = time.time()
result = process_data(large_dataset)
print(f"{(time.time() - start) * 1000:.2f}ms")
a) A process_data függvény memóriafelhasználását
b) A process_data függvény futásidejét milliszekundumban
c) A large_dataset méretét
d) A CPU terhelését a függvény futása alatt
(Helyes: b)
3. Miért nem elegendő az átlag (mean) egyedül egy backend endpoint válaszidejének értékelésekor?
a) Az átlag nem számítható ki pontosan, ha sok mérés van
b) Az átlag elfedheti a kiugró (lassú) eseteket, amelyeket a p95/p99 mutat meg
c) Az átlag csak frontend mérésre alkalmazható
d) Az átlag mindig magasabb értéket ad, mint a valódi teljesítmény
(Helyes: b)
4. A Browser DevTools Performance tab rögzítése után flamegraph-ot látsz. Melyik állítás igaz?
a) Minél mélyebb egy elem a gráfban, annál lassabb
b) A vízszintesen szélesebb sávok több időt jelölnek az adott műveletre
c) A flamegraph csak hálózati kéréseket mutat
d) Flamegraph csak Node.js alkalmazásokban elérhető
(Helyes: b)
5. Egy lassú oldal diagnosztizálásakor mi a helyes első lépés?
a) Optimalizálni a legnagyobb JavaScript fájlt
b) Rögtön SQL indexet adni hozzá
c) A Network tab megnyitásával megvizsgálni, melyik kérés lassú
d) A teljes kódbázist újraírni
(Helyes: c)
6. Mit jelent, ha egy mérési eredménynél azt olvasod: p99 = 4500ms, de az átlag 120ms?
a) Az átlag mérési hibás, a helyes értéket a p99 adja
b) A kérések 99%-a 4500ms alatt válaszol, és ez egy jó eredmény
c) A kérések 1%-a 4500ms-nél is hosszabb ideig vár – ez 100 felhasználóból 1-et érint
d) Nincs különbség a p99 és az átlag között, ugyanazt jelzik
(Helyes: c)
7. Miért nem hagyják bekapcsolva a profiling eszközt folyamatosan production-ban?
a) Mert a profiling eszközök illegálisak éles környezetben
b) Mert a profiling overhead-del jár és maga is lassítja az alkalmazást
c) Mert a profiling csak fejlesztői gépeken működik
d) Mert a profiling csak CPU-t mér, nem hálózatot
(Helyes: b)
8. Melyik állítás igaz a benchmarking helyes elvégzéséről?
a) Elég egyszer lefuttatni a mérést, az eredmény pontos lesz
b) Több iteráció átlagát kell nézni, mert a CPU terheltsége és cache-állapot befolyásolják az eredményt
c) Benchmarking csak terhelésteszt keretében végezhető
d) A benchmark eredménye mindig milliszekundumban adandó meg
(Helyes: b)
9. Melyik szituációban elegendő a manuális console.time() / time.time() mérés?
a) Production rendszer folyamatos monitorozásakor
b) SLA teljesítésének folyamatos bizonyításakor
c) Fejlesztés közben egy konkrét kódrészlet gyors teljesítményvizsgálatakor
d) 1000 párhuzamos felhasználó szimulálásához
(Helyes: c)
10. Egy diagnosztizálási folyamatban mi a helyes sorrend?
a) Javítás → mérés → lokalizálás → reprodukálás
b) Reprodukálás → mérés → lokalizálás → hipotézis → javítás → újramérés
c) Profilozás → hipotézis → reprodukálás → mérés
d) Lokalizálás → javítás → mérés → reprodukálás
(Helyes: b)