Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel

U PHP ekosustavu trenutno postoje dva konektora za rad sa Tarantool serverom ― to je službeni PECL dodatak tarantool/tarantool-php, napisan u C, i tarantool-php/client, napisan u PHP. Ja sam autor potonjeg.

U ovom članku bih želio podijeliti rezultate testiranja performansi obiju biblioteka i pokazati kako uz minimalne promjene u kodu može doći do 3-5% povećanja performansi (na sintetičkim testovima!).

Što ćemo testirati?

Testirat ćemo ranije spomenute sinkrone konektore, pokrenute asinkrono, paralelno i asinkrono-paralelno. 🙂 Također ne želimo dirati sam kod konektora. Trenutno je dostupno nekoliko dodataka koji omogućuju postizanje željenog:

  • Swoole ― visokoučinkovit asinkroni okvir za PHP. Koriste ga internetski divovi kao što su Alibaba i Baidu. Od verzije 4.1.0 uvedena je čarobna metoda SwooleRuntime::enableCoroutine(), koja "jednom linijom koda pretvara sinkrone mrežne biblioteke PHP u asinkrone".
  • Async ― do nedavno vrlo perspektivan dodatak za asinkroni rad u PHP-u. Zašto do nedavno? Nažalost, iz meni nepoznatog razloga, autor je uklonio repozitorij i daljnja sudbina projekta je neizvjesna. Morat ćemo se poslužiti jednim od forkova. Kao i Swoole, ovaj dodatak omogućava jednim potezom transformaciju rada u asinkronost zamjenom standardne implementacije TCP i TLS tokova njihovim asinkronim verzijama. To se postiže putem opcije "async.tcp = 1«.
  • Parallel ― prilično novi dodatak od poznatog Joea Watkina, autora knjižnica kao što su phpdbg, apcu, pthreads, pcov, uopz. Dodatak pruža API za višedretvenog rada u PHP-u i pozicionira se kao zamjena za pthreads. Značajno ograničenje knjižnice je to što radi samo s ZTS (Zend Thread Safe) verzijom PHP-a.

Kako ćemo testirati?

Pokrenut ćemo instancu Tarantoola s isključenim dnevnikom unaprijed zapisa (wal_mode = none) i povećanom mrežnom baferom (readahead = 1 * 1024 * 1024). Prva opcija isključuje rad s diskom, a druga omogućava čitanje više zahtjeva iz bafera operativnog sustava i time minimizira broj sistemskih poziva.

Za benchmarke koji rade s podacima (ubacivanje, brisanje, čitanje itd.) prije početka benchmarka bit će (ponovno) stvoren memtx-prostor u kojem se vrijednosti primarnog indeksa stvaraju generatorom urednih cijelih brojeva (sekvenca).
DDL prostora izgleda ovako:

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}})

Po potrebi, prije pokretanja benchmarka, prostor se ispunjava sa 10.000 trokuta u obliku

{id, "tuplе_"}

Pristup trokutima se ostvaruje kroz nasumičnu vrijednost ključa.

Sam benchmark predstavlja jedan zahtjev prema serveru, koji se izvršava 10.000 puta (revolucija), koje se, zauzvrat, izvršavaju u iteracijama. Iteracije se ponavljaju sve dok sva odstupanja u vremenu između 5 iteracija ne budu unutar prihvatljive pogreške od 3 %*. Nakon toga se uzima prosječan rezultat. Između iteracija pauza od 1 sekunde, kako se procesor ne bi pregrijao. Lua sakupljač smeća se isključuje prije svake iteracije i prisilno pokreće nakon njenog završetka. PHP proces se pokreće samo s potrebnim ekstenzijama za benchmark, s uključenim međuspremnikom izlaznih podataka i isključenim sakupljačem smeća.

* Broj revolucija, iteracija i prag pogreške može se mijenjati u postavkama benchmarka.

Testno okruženje

Objavljeni rezultati napravljeni su na MacBookPro (2015), operacijski sustav — Fedora 30 (verzija kernela 5.3.8-200.fc30.x86_64). Tarantool je pokrenut u Dockeru sa parametrom "--network host".

Verzije paketa:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, build a872fc2f86
PHP: 7.3.11 (cli) (izgrađeno: 22. listopada 2019. 08:11:04)
tarantool/client: 0.6.0
rybakit/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ patch za 7.3)*
ext-msgpack: 2.0.3
ext-async: 0.3.0-8c1da46
ext-swoole: 4.4.12
ext-parallel: 1.1.3

* Nažalost, službeni konektor ne radi s verzijom PHP > 7.2. Da bi se kompilirao i pokrenuo ekstenzija na PHP 7.3, bilo je potrebno koristiti patch.

Rezultati

Sinkroni način

Protokol Tarantoola koristi binarni format MessagePack za serijalizaciju poruka. U PECL konektoru serijalizacija je duboko skrivena u utrobi biblioteke i utjecati na proces kodiranja iz userland-koda nije moguće. Konektor na čistom PHP, s druge strane, omogućuje prilagodbu procesa kodiranja proširenjem standardnog kodera ili mogućnošću korištenja vlastite implementacije. Iz kutije su dostupna dva kodera, jedan temeljen na msgpack/msgpack-php (službeno proširenje MessagePack PECL), drugi — na rybakit/msgpack (na čistom PHP-u).

Prije usporedbe konektora, izmjerit ćemo performanse MessagePack kodera za PHP konektor, a u daljnjim testovima koristit ćemo onaj koji pokaže najbolje rezultate:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Iako PHP verzija (Pure) zaostaje za PECL proširenjem u brzini, u stvarnim projektima i dalje bih preporučio korištenje rybakit/msgpack, jer je u službenom proširenju MessagePack specifikacija formata implementirana samo djelomično (na primjer, nema podrške za korisničke tipove podataka, bez kojih nećete moći koristiti Decimal — novi tip podataka predstavljen u Tarantool 2.3) i ima niz drugih problema (uključujući probleme s kompatibilnošću s PHP 7.4). I općenito, projekt izgleda napušten.

Dakle, izmjerimo performanse konektora u sinhronom režimu:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Kao što se može vidjeti s grafikona, PECL konektor (Tarantool) pokazuje bolje performanse u usporedbi s konektorom na PHP-u (Client). No, to ne iznenađuje, s obzirom na to da potonji, osim što je implementiran na sporijem jeziku, zapravo obavlja više posla: pri svakom pozivu stvara se novi objekt Request i Response (u slučaju Select ― još i Criteria, a u slučaju Update/Upsert ― Operations), odvojene entitete Connection, Packer i Handler također dodaje dodatno opterećenje. Očito je da za fleksibilnost treba platiti. Međutim, općenito, PHP interpreter pokazuje dobre performanse, iako razlika postoji, ona nije značajna i možda će biti još manja korištenjem preloading-a u PHP 7.4, ne spominjući JIT u PHP 8.

Idemo dalje. U Tarantool 2.0 dodana je podrška za SQL. Pokušajmo izvršiti operacije Select, Insert, Update i Delete koristeći SQL protokol i usporedimo rezultate s noSQL (binarnih) ekvivalentima:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Rezultati SQL-a nisu previše impresivni (podsjećam da još uvijek testiramo sinhroni režim). Međutim, ne bih se previše brinuo zbog toga unaprijed, podrška za SQL je još uvijek u aktivnom razvoju (relativno nedavno, na primjer, dodana je podrška za prepared statements) i, sudeći po popisu issues, SQL engine očekuje niz optimizacija.

Asinkrono

Pa da vidimo kako će proširenje Asinkrono pomoći u poboljšanju gornjih rezultata. Za pisanje asinkronih programa proširenje pruža API temeljen na korutinama, koji ćemo iskoristiti. Eksperimentišemo i utvrđujemo da je optimalan broj korutina za naše okruženje 25:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
»Raspoređujemo« 10,000 operacija među 25 korutina i gledamo što smo postigli:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Broj operacija u sekundi povećan je više od 3 puta za tarantool-php/client!

Nažalost, PECL konektor se nije pokrenuo s ext-async.

A što je s SQL-om?

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Kao što vidite, u asinkronom režimu razlika između binarnog protokola i SQL-a postala je unutar greške.

Swoole

Ponovo utvrđujemo optimalan broj korutina, sada za Swoole:
Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Ostaćemo na 25. Ponovimo istu stvar kao i s proširenjem Asinkrono ― raspodelimo 10,000 operacija među 25 korutina. Osim toga, dodajemo još jedan test, u kojem ćemo podeliti sav rad na 2 procesa (tj. svaki proces će izvršiti 5,000 operacija u 25 korutina). Procesi će se kreirati pomoću SwooleProcess.

Rezultati:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Swole pokazuje malo niži rezultat u poređenju s Asinkronim kada se pokreće u jednom procesu, ali s 2 procesa situacija se drastično menja (broj 2 nije izabran slučajno, na mojoj mašini su baš 2 procesa pokazala najbolje rezultate).

Usput, i u proširenju Asinkrono postoji API za rad s procesima, međutim, nisam primetio razliku u pokretanju benchmarkova u jednom ili više procesa (nije isključeno da sam napravio neku grešku).

SQL vs binarni protokol:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Kao i s Asinkronim, razlika između binarnih i SQL operacija se smanjuje u asinkronom režimu.

Parallel

Budući da proširenje Paralelno nije o korutinama, već o procesima, izmerićemo optimalan broj paralelnih procesa:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
On iznosi 16 na mojoj mašini. Pokrenimo benchmarke konektora na 16 paralelnih procesa:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Kao što vidite, rezultat je čak i bolji nego s asinkronim proširenjima (ne računajući Swoole pokrenut na 2 procesa). Imajte na umu da za PECL konektor na mestima Update i Upsert operacija nema podataka. To je zbog toga što su te operacije završile greškom ― ne znam da li je krivnja ext-parallel, ext-tarantool ili obojica.

Sada uporedimo performanse SQL-a:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel
Primijetili ste sličnost s grafikom za konektore pokrenute sinkrono?

Sve zajedno

Na kraju, sažet ćemo sve rezultate u jedan grafikon kako bismo vidjeli cjelokupnu sliku za testirane ekstenzije. Na grafikon ćemo dodati samo jedan novi test koji do sada nismo radili - pokrenut ćemo Async korutine paralelno s Parallel*. Ideja integracije gore spomenutih ekstenzija već je raspravljana od strane autora, ali konsenzus nije postignut, morat ćemo to učiniti sami.

* Nije uspjelo pokrenuti Swoole korutine s Parallel, čini se da su ove ekstenzije nespojive.

Dakle, konačni rezultati:

Ubrzanje PHP konektora za Tarantool uz Async, Swoole i Parallel

Umjesto zaključka

Po mom mišljenju, rezultati su prilično dobri i nekako sam uvjeren da to još nije max! Trebate li to u stvarnom projektu, isključivo je na vama da donesete odluku, samo ću reći da je za mene ovo bio zanimljiv eksperiment koji omogućava procjenu koliko se može "izvući" iz sinkroniziranog TCP konektora uz minimalan trud. Ako imate ideje za poboljšanje benchmarkova - rado ću razmotriti vaš pull request. Sav kod s uputama za pokretanje i rezultatima objavljen je u zasebnom repozitoriju.

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster