Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel

V ekosystéme PHP sú momentálne dva konektory pre prácu so serverom Tarantool - toto je oficiálne rozšírenie PECL tarantool/tarantool-php, napísaný v C a tarantool-php/client, napísaný v PHP. Ja som autorom toho posledného.

V tomto článku by som sa rád podelil o výsledky testovania výkonu oboch knižníc a ukázal, ako s minimálnymi zmenami v kóde môžete dosiahnuť zvýšenie výkonu o 3-5 (na syntetických testoch!).

Čo budeme testovať?

Otestujeme tie vyššie spomenuté synchrónne konektory prebiehajúce asynchrónne, paralelne a asynchrónne paralelne. 🙂 Nechceme sa dotknúť ani kódu samotných konektorov. V súčasnosti je k dispozícii niekoľko rozšírení na dosiahnutie toho, čo chcete:

  • Swoole ― vysoko výkonný asynchrónny rámec pre PHP. Používajú ho takí internetoví giganti ako Alibaba a Baidu. Od verzie 4.1.0 sa objavila magická metóda SwooleRuntime::enableCoroutine(), ktorý vám umožňuje „previesť synchrónne sieťové knižnice PHP na asynchrónne s jedným riadkom kódu“.
  • Async bol donedávna veľmi sľubným rozšírením pre asynchrónnu prácu v PHP. Prečo donedávna? Žiaľ, z mne neznámeho dôvodu autor vymazal úložisko a ďalší osud projektu je nejasný. Budem to musieť použiť jeden z vidličiek. Rovnako ako Swoole, aj toto rozšírenie vám umožňuje jednoducho zapnúť nohavice pohybom zápästia, aby ste umožnili asynchrónnosť nahradením štandardnej implementácie tokov TCP a TLS ich asynchrónnymi verziami. To sa vykonáva pomocou možnosti „async.tcp = 1".
  • paralelné ― celkom nové rozšírenie od známeho Joea Watkinsa, autora takých knižníc ako phpdbg, apcu, pthreads, pcov, uopz. Rozšírenie poskytuje API pre multithreading v PHP a je umiestnené ako náhrada za pthreads. Významným obmedzením knižnice je, že funguje len s verziou PHP ZTS (Zend Thread Safe).

Ako budeme testovať?

Spustite inštanciu Tarantool so zakázaným protokolovaním vopred (wal_mode = žiadny) a zvýšená vyrovnávacia pamäť siete (predčítanie = 1 * 1024 * 1024). Prvá možnosť eliminuje prácu s diskom, druhá umožní čítať viac požiadaviek z vyrovnávacej pamäte operačného systému a tým minimalizovať počet systémových volaní.

Pre benchmarky, ktoré pracujú s dátami (vkladanie, mazanie, čítanie atď.), sa pred spustením benchmarku (znovu) vytvorí priestor memtx, v ktorom sú primárne hodnoty indexu vytvorené generátorom usporiadaných celočíselných hodnôt ​(sekvencia).
Priestor DDL vyzerá takto:

space = box.schema.space.create(config.space_name, {id = config.space_id, temporary = true})
space:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}, sequence = true})
space:format({{name = 'id', type = 'unsigned'}, {name = 'name', type = 'string', is_nullable = false}})

Ak je to potrebné, pred spustením benchmarku sa priestor zaplní 10,000 XNUMX n-ticami formulára

{id, "tuplе_<id>"}

K n-ticám sa pristupuje pomocou náhodnej hodnoty kľúča.

Samotný benchmark je jediná požiadavka na server, ktorá sa vykoná 10,000 5-krát (otáčok), ktoré sa zase vykonávajú v iteráciách. Iterácie sa opakujú, kým všetky časové odchýlky medzi 3 iteráciami nebudú v rámci prijateľnej chyby 1 %*. Potom sa vezme priemerný výsledok. Medzi iteráciami je XNUMX sekundová pauza, aby sa zabránilo škrteniu procesora. Lua je garbage collector deaktivovaný pred každou iteráciou a je nútený spustiť sa po jej dokončení. Proces PHP sa spúšťa iba s rozšíreniami potrebnými pre benchmark, so zapnutým ukladaním výstupnej vyrovnávacej pamäte a zakázaným zberačom odpadu.

* Počet otáčok, iterácií a prah chyby je možné zmeniť v nastaveniach benchmarku.

Testovacie prostredie

Nižšie publikované výsledky boli vytvorené na MacBookPro (2015), operačný systém - Fedora 30 (verzia jadra 5.3.8-200.fc30.x86_64). Tarantool bol spustený v docker s parametrom "--network host".

Verzie balíkov:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, zostava a872fc2f86
PHP: 7.3.11 (cli) (vytvorené: 22. októbra 2019 08:11:04)
tarantool/klient: 0.6.0
rybakit/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ záplata za 7.3)*
ext-msgpack: 2.0.3
ext-async: 0.3.0-8c1da46
ext-swoole: 4.4.12
ext-paralelné: 1.1.3

* Bohužiaľ, oficiálny konektor nefunguje s verziou PHP > 7.2. Na kompiláciu a spustenie rozšírenia na PHP 7.3 som musel použiť náplasť.

výsledky

Synchrónny režim

Protokol Tarantool používa binárny formát MessagePack na serializáciu správ. V konektore PECL je serializácia skrytá hlboko v hĺbke knižnice a ovplyvňuje proces kódovania z užívateľského kódu sa nezdá možné. Čistý konektor PHP naopak poskytuje možnosť prispôsobiť proces kódovania rozšírením štandardného kódovača alebo použitím vlastnej implementácie. Po vybalení sú k dispozícii dva kódovače, jeden je založený na msgpack/msgpack-php (oficiálne rozšírenie MessagePack PECL), druhé je zapnuté rybakit/msgpack (v čistom PHP).

Pred porovnaním konektorov zmeriame výkon kódovačov MessagePack pre konektor PHP a v ďalších testoch použijeme ten, ktorý vykazuje najlepší výsledok:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Aj keď je verzia PHP (Pure) v rýchlosti nižšia ako rozšírenie PECL, v reálnych projektoch by som ju stále odporúčal používať rybakit/msgpack, pretože v oficiálnom rozšírení MessagePack je špecifikácia formátu implementovaná len čiastočne (napríklad chýba podpora vlastných dátových typov, bez ktorých nebudete môcť používať Decimal - nový dátový typ zavedený v Tarantool 2.3) a má množstvo ďalších problémy (vrátane problémov s kompatibilitou s PHP 7.4). Vo všeobecnosti projekt vyzerá opustene.

Poďme teda zmerať výkon konektorov v synchrónnom režime:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Ako je zrejmé z grafu, konektor PECL (Tarantool) vykazuje lepší výkon v porovnaní s konektorom PHP (Client). To však nie je prekvapujúce, pretože tento druhý, okrem toho, že je implementovaný v pomalšom jazyku, v skutočnosti robí viac práce: s každým volaním sa vytvorí nový objekt žiadosť и Odpoveď (v prípade Select - tiež Kritériáa v prípade Update/Upsert ― operácie), samostatné subjekty Spojenie, Balič и psovod pridávajú aj réžiu. Je zrejmé, že flexibilita má svoju cenu. Vo všeobecnosti však interpret PHP vykazuje dobrý výkon, aj keď existuje rozdiel, je nevýznamný a možno bude ešte menší pri použití predbežného načítania v PHP 7.4, nehovoriac o JIT v PHP 8.

Poďme ďalej. Tarantool 2.0 pridal podporu pre SQL. Skúsme vykonať operácie Select, Insert, Update a Delete pomocou SQL protokolu a porovnajme výsledky s noSQL (binárnymi) ekvivalentmi:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Výsledky SQL nie sú veľmi pôsobivé (pripomínam, že stále testujeme synchrónny režim). Dopredu by som sa však nad tým nerozčuľoval, podpora SQL je stále v aktívnom vývoji (relatívne nedávno pribudla napr. pripravené výkazy) a súdiac podľa zoznamu otázky, SQL engine prejde v budúcnosti množstvom optimalizácií.

asynchrónne

Teraz sa pozrime, ako nám rozšírenie Async môže pomôcť zlepšiť vyššie uvedené výsledky. Na písanie asynchrónnych programov poskytuje rozšírenie API založené na korutínach, ktoré budeme používať. Empiricky sme zistili, že optimálny počet korutínov pre naše prostredie je 25:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
„Rozložte“ 10,000 25 operácií na XNUMX korutín a uvidíte, čo sa stane:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Počet operácií za sekundu sa zvýšil viac ako 3-krát tarantool-php/client!

Je smutné, že konektor PECL nezačal s ext-async.

A čo SQL?

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Ako vidíte, v asynchrónnom režime sa rozdiel medzi binárnym protokolom a SQL dostal na hranicu chyby.

Swoole

Opäť zisťujeme optimálny počet korutínov, tentoraz pre Swoole:
Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Zastavme sa pri 25. Zopakujme si rovnaký trik ako pri rozšírení Async – rozdeľte 10,000 25 operácií medzi 2 korutín. Okrem toho pridáme ďalší test, v ktorom rozdelíme všetku prácu do 5,000 dvoch procesov (to znamená, že každý proces vykoná 25 operácií v XNUMX korutínach). Procesy budú vytvorené pomocou SwooleProcess.

výsledky:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Swole vykazuje mierne nižší výsledok v porovnaní s Async, keď je spustený v jednom procese, ale s 2 procesmi sa obraz dramaticky mení (číslo 2 nebolo zvolené náhodou; na mojom počítači to boli 2 procesy, ktoré vykazovali najlepší výsledok).

Mimochodom, rozšírenie Async má aj API na prácu s procesmi, ale tam som nezaznamenal rozdiel oproti spusteniu benchmarkov v jednom alebo viacerých procesoch (je možné, že som sa niekde pokazil).

SQL vs binárny protokol:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Rovnako ako pri Async je rozdiel medzi binárnymi a SQL operáciami eliminovaný v asynchrónnom režime.

paralelné

Keďže rozšírenie Parallel nie je o korutínach, ale o vláknach, zmerajte optimálny počet paralelných vlákien:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Na mojom stroji sa rovná 16. Spustite benchmarky konektorov na 16 paralelných vláknach:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Ako vidíte, výsledok je ešte lepší ako pri asynchrónnych rozšíreniach (nepočítajúc Swoole bežiaci na 2 procesoch). Všimnite si, že pre konektor PECL sú operácie Update a Upsert prázdne. Je to spôsobené tým, že tieto operácie zlyhali s chybou - neviem, či to bola chyba ext-paralel, ext-tarantool alebo oboch.

Teraz porovnajme výkon SQL:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel
Všimli ste si podobnosť s grafom pre konektory bežiace synchrónne?

Spolu

A nakoniec zhrňme všetky výsledky do jedného grafu, aby sme videli celkový obraz testovaných rozšírení. Pridajme do grafu len jeden nový test, ktorý sme ešte neurobili – spúšťajme paralelne Async coroutines pomocou Parallel*. Myšlienka integrácie vyššie uvedených rozšírení už existuje sa diskutovalo autori, ale nedospelo sa k žiadnemu konsenzu, budete to musieť urobiť sami.

* Nebolo možné spustiť Swoole coroutines s Parallel, zdá sa, že tieto rozšírenia sú nekompatibilné.

Takže konečné výsledky:

Zrýchlenie PHP konektorov pre Tarantool pomocou Async, Swoole a Parallel

namiesto záveru

Podľa môjho názoru sa výsledky ukázali ako celkom hodné a z nejakého dôvodu som si istý, že to nie je limit! Či už o tom musíte rozhodnúť v reálnom projekte len pre seba, poviem len toľko, že pre mňa to bol zaujímavý experiment, ktorý vám umožní zhodnotiť, koľko dokážete zo synchrónneho TCP konektora „vyžmýkať“ s minimálnou námahou. Ak máte nápady na zlepšenie benchmarkov, rád zvážim vašu požiadavku na stiahnutie. Všetok kód s pokynmi na spustenie a výsledkami je zverejnený v samostatnom úložiská.

Zdroj: hab.com

Pridať komentár