OpenStats - benchmarking
Při vývoji a nasazování aplikací je velmi důležité výkonnostní testování - umožňuje například správně rozvrhnout databázové tabulky do tablespaců, zjistit výkonnostní limity systému, apod. Pro potřeby projektu OpenStats jsem si napsal jednoduchý vícevláknový benchmarkovací nástroj v Javě, který čte SQL příkazy ze souboru a provádí je na databázi. Podívejme se jak tento nástroj použít, a na orientační výsledky.
Zmíněná utilitka je tvořena jedinou třídou OpenStatsBench, umístěnou v adresáři misc/ - tato třída čte soubory SQL příkazů produkované skriptem build-data-bench.php, a provádí je nad zvolenou databází. Vygenerujme data pro testování:
$ php build-data-bench.php -d 7 -s 10000 -a 10 -p 2 -v 1000 -u 5000 -q 100 \
-t 5 -l eng:ces -f 2009-01-01 > bench.sql
Výše uvedený příkaz vygeneruje data pro sedm dní, přičemž pro každý den bude vytvořeno přibližně 10000 sessions, každá session bude mít 10 akcí, každá akce 2 parametry které mohou nabývat 1000 různých hodnot. Sessions budou náhodně přiřazovány 5000 unikátních návštěvníků (unikátní ID). Akce budou navázány na 100 stránek (s ID od 1 do 100) a 5 typů akcí (s ID od 1 do 5). Použity budou 2 jazyky (eng a ces), a počáteční datum bude 2009-01-01.
Vygenerovaná data jsou přesměrována do souboru bench.sql, který je následně použit jako vstup samotného benchmarkovacího nástroje napsaného v Javě - třídy OpenStatsBench. Ta obsahuje definici několika vláken, z nichž jedno (tzv. feeder) čte SQL příkazy ze souboru a vkládá je do fronty, ze kterého si je následně berou další vlákna (tzv. executor) a spouštějí je na databázi. Přitom vlákna sledují statistiku kolik jakých insertů provedly (do které tabulky), a jak dlouho jim jejich provedení trvalo. Na konci běhu pak vypíší krátkou statistiku (viz. dále).
$ javac OpenStatsBench.java
$ java -cp postgresql-jdbc.jar:. OpenStats.java --file bench.sql --executors 3 \
--host localhost --port 5432 --dbname ostest --user osuser --pass ospass
Prvním příkazem utilitku zkompilujete, druhým příkazem ji spustíte - přitom zadáváte vstupní soubor ze kterého se data mají číst (byl vygenerován skriptem build-data-bench.php), počet vláken provádějících SQL příkazy (v našem případě 3), a spojení na databázi (host, port, jméno databáze, uživatel a heslo).
Příklad výstupu třídy OpenStatsBench
Následující text obsahuje ukázkové výsledky této utility - ačkoliv nejsou úplně nejhorší, berte prosím v potaz že pochází z mého pracovního počítače (AMD Athlon 64 X2 4400+, 2GB DDR2 RAM, běžné SATA 7.2k disky bez RAIDu), takže výsledky na libovolném kvalitním serveru s kvalitním SCSI / SAS řadičem, rychlými disky, spoustou paměti a výkonným procesorem by měly být znatelně lepší. Kromě toho statistiky samozřejmě závisí také na nastaveních PostgreSQL.
Spustíme-li OpenStatsBench příkazem uvedeným výše (3 runnery, apod.), dostaneme zhruba takovýto výstup (pro každý executor samostatná statistika):
================== Executor 0 ================== Sessions: 3330 in 7328 ms (454 rows / sec) Actions: 33300 in 74929 ms (444 rows / sec) Parameters: 66600 in 141071 ms (472 rows / sec) ------------------------------------------------- Total: 103230 in 223328 ms (462 rows / sec) ================== Executor 1 ================== Sessions: 3349 in 7399 ms (452 rows / sec) Actions: 33490 in 74561 ms (449 rows / sec) Parameters: 66980 in 141445 ms (473 rows / sec) ------------------------------------------------- Total: 103819 in 223405 ms (464 rows / sec) ================== Executor 2 ================== Sessions: 3321 in 8045 ms (412 rows / sec) Actions: 33210 in 74474 ms (445 rows / sec) Parameters: 66420 in 140859 ms (471 rows / sec) ------------------------------------------------- Total: 102951 in 223378 ms (460 rows / sec)
Je vidět že rychlost vkládání do jednotlivých tabulek výrazně neliší (ve všech případech dosahuje cca 1300 řádek / s).
Pokud by vás zajímalo zatížení systému během testu (kvůli určení úzkých míst - CPU / disky apod.), lze využít například utilitku "dstat" - příklad typického výstupu během testu je (jen několik řádek):
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system-- usr sys idl wai hiq siq| read writ| recv send| in out | int csw 53 21 9 10 1 5|8192B 19M| 0 0 | 0 0 |3882 12k 53 21 11 8 2 7| 0 19M| 0 0 | 0 0 |4036 12k 47 20 9 17 1 6| 0 20M| 0 0 | 0 0 |3670 11k 57 21 11 5 0 5| 0 18M| 0 0 | 0 0 |3642 12k 49 23 9 9 2 7| 0 19M| 0 0 | 0 0 |3983 12k 50 22 10 9 2 7| 0 19M| 0 0 | 0 0 |3933 11k 52 20 10 8 3 6|8192B 19M| 0 0 | 0 0 |4078 12k ....
Příkazem "top" naopak zjistíte zajímavé informace o jednotlivých procesech:
top - 17:58:02 up 1:33, 1 user, load average: 2.20, 0.75, 0.44 Tasks: 116 total, 4 running, 112 sleeping, 0 stopped, 0 zombie Cpu(s): 53.3%us, 21.3%sy, 0.0%ni, 8.5%id, 9.8%wa, 1.8%hi, 5.3%si, 0.0%st Mem: 2059928k total, 1406112k used, 653816k free, 55912k buffers Swap: 4144760k total, 224k used, 4144536k free, 976444k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 9122 postgres 20 0 36196 5164 3540 R 44 0.3 0:31.22 postmaster 9120 postgres 20 0 36168 5096 3484 S 44 0.2 0:31.26 postmaster 9121 postgres 20 0 36176 5176 3548 R 41 0.3 0:31.84 postmaster 9101 vampire 20 0 829m 35m 7972 S 22 1.7 0:20.42 java
Je vidět že 3 "postmaster" procesy obsluhující požadavky vláken "executorů" vytěžují CPU zhruba stejně (41% - 44%), nicméně režie vláken Javy není zanedbatelná (22%). Proto doporučuji tento nástroj spouštět na jiném stroji než je umístěna databáze, tak aby jeho běh neovlivňoval výsledky.




