Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel

U PHP ekosustavu trenutno postoje dva konektora za rad s Tarantool poslužiteljem - ovo je službena PECL ekstenzija tarantool/tarantool-php, napisano u C, i tarantool-php/klijent, napisano u PHP-u. Ja sam autor potonjeg.

U ovom članku želio bih podijeliti rezultate testiranja performansi obje biblioteke i pokazati kako uz minimalne izmjene koda možete postići povećanje performansi 3-5 (na sintetičkim testovima!).

Što ćemo testirati?

Testirat ćemo gore navedene sinkroni konektori koji rade asinkrono, paralelno i asinkrono-paralelno. 🙂 Također ne želimo dirati kod samih konektora. Trenutačno je dostupno nekoliko proširenja za postizanje onoga što želite:

  • Swoole ― asinkroni okvir visokih performansi za PHP. Koriste ga internetski divovi kao što su Alibaba i Baidu. Od verzije 4.1.0 pojavila se čarobna metoda SwooleRuntime::enableCoroutine(), koji vam omogućuje da "pretvorite sinkrone PHP mrežne biblioteke u asinkrone s jednom linijom koda."
  • Async je donedavno bio vrlo obećavajuće proširenje za asinkroni rad u PHP-u. Zašto donedavno? Nažalost, iz meni nepoznatog razloga, autor je izbrisao repozitorij i daljnja sudbina projekta nije jasna. Morat ću ga upotrijebiti jedan od vilica. Kao i Swoole, ovo proširenje vam omogućuje da jednostavno navučete hlače jednim pokretom zapešća kako biste omogućili asinkroniju zamjenom standardne implementacije TCP i TLS tokova njihovim asinkronim verzijama. To se radi putem opcije “async.tcp = 1”.
  • Paralelno ― prilično novo proširenje poznatog Joea Watkinsa, autora biblioteka kao što su phpdbg, apcu, pthreads, pcov, uopz. Proširenje pruža API za višenitnost u PHP-u i postavljeno je kao zamjena za pthreads. Značajno ograničenje biblioteke je to što radi samo sa ZTS (Zend Thread Safe) verzijom PHP-a.

Kako ćemo testirati?

Pokrenimo instancu Tarantoola s onemogućenim zapisivanjem unaprijed (wal_mode = nijedan) i povećan mrežni međuspremnik (čitanje unaprijed = 1 * 1024 * 1024). Prva opcija će eliminirati rad s diskom, druga će omogućiti čitanje više zahtjeva iz međuspremnika operativnog sustava i time minimizirati broj sistemskih poziva.

Za benchmarkove koji rade s podacima (umetanje, brisanje, čitanje, itd.), prije pokretanja benchmarka, (ponovno) će se stvoriti memtx prostor u kojem se primarne vrijednosti indeksa kreiraju pomoću generatora uređenih cjelobrojnih vrijednosti ​(slijed).
Prostorni DDL 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}})

Ako je potrebno, prije pokretanja benchmarka prostor se popunjava s 10,000 XNUMX torki oblika

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

Torkama se pristupa pomoću slučajne vrijednosti ključa.

Sam benchmark je jedan zahtjev prema poslužitelju koji se izvršava 10,000 5 puta (okretaja), koji se pak izvršavaju u iteracijama. Iteracije se ponavljaju dok sva vremenska odstupanja između 3 iteracija ne budu unutar prihvatljive pogreške od 1%*. Nakon toga se uzima prosječni rezultat. Postoji stanka od XNUMX sekunde između ponavljanja kako bi se spriječilo usporavanje procesora. Luin skupljač smeća je onemogućen prije svake iteracije i prisiljen je pokrenuti se nakon završetka. PHP proces se pokreće samo s ekstenzijama potrebnim za benchmark, s omogućenim izlaznim međuspremnikom i onemogućenim sakupljačem smeća.

* Broj okretaja, ponavljanja i prag pogreške mogu se promijeniti u postavkama referentne vrijednosti.

Testno okruženje

Dolje objavljeni rezultati napravljeni su na MacBookPro (2015), operativni sustav - Fedora 30 (verzija kernela 5.3.8-200.fc30.x86_64). Tarantool je pokrenut u dockeru s parametrom "--network host".

Verzije paketa:

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

* Nažalost, službeni konektor ne radi s PHP verzijom > 7.2. Za kompajliranje i pokretanje proširenja na PHP 7.3, morao sam koristiti zakrpa.

Nalazi

Sinkroni način rada

Tarantool protokol koristi binarni format MessagePack za serijalizaciju poruka. U PECL konektoru, serijalizacija je skrivena duboko u dubinama biblioteke i utječe na proces kodiranja iz korisničkog koda ne čini se mogućim. Čisti PHP konektor, naprotiv, pruža mogućnost prilagodbe procesa kodiranja proširenjem standardnog kodera ili korištenjem vlastite implementacije. Dostupna su dva enkodera, jedan se temelji na msgpack/msgpack-php (službeno proširenje MessagePack PECL), drugi je uključen rybakit/msgpack (u čistom PHP-u).

Prije usporedbe konektora izmjerit ćemo performanse MessagePack kodera za PHP konektor i u daljnjim testovima koristit ćemo onaj koji pokaže najbolji rezultat:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Iako je PHP verzija (Pure) inferiorna PECL ekstenziji u brzini, u stvarnim projektima ipak bih preporučio njezinu upotrebu rybakit/msgpack, jer je u službenom proširenju MessagePack specifikacija formata samo djelomično implementirana (na primjer, nema podrške za prilagođene tipove podataka, bez kojih nećete moći koristiti Decimal - novi tip podataka uveden u Tarantool 2.3) i ima broj drugih problem (uključujući probleme s kompatibilnošću s PHP 7.4). Pa, općenito, projekt izgleda napušteno.

Dakle, izmjerimo performanse konektora u sinkronom načinu rada:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Kao što se može vidjeti iz grafikona, PECL konektor (Tarantool) pokazuje bolje performanse u usporedbi s PHP konektorom (Klijent). Ali to nije iznenađujuće, s obzirom da potonji, osim što je implementiran u sporijem jeziku, zapravo radi više posla: sa svakim pozivom kreira se novi objekt Zatražite и Odgovor (u slučaju Select - također Kriteriji, a u slučaju ažuriranja/upsertiranja ― operacije), odvojene cjeline priključak, Paker и sekundant dodaju i režijske troškove. Očito, fleksibilnost ima svoju cijenu. Međutim, općenito, PHP interpreter pokazuje dobre performanse, iako postoji razlika, ona je beznačajna i možda će biti čak i manja kada se koristi predučitavanje u PHP 7.4, a da ne spominjemo JIT u PHP 8.

Idemo dalje. Tarantool 2.0 uveo je SQL podršku. Pokušajmo izvesti operacije odabira, umetanja, ažuriranja i brisanja pomoću SQL protokola i usporedimo rezultate s noSQL (binarni) ekvivalentima:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Rezultati SQL-a nisu baš impresivni (dopustite mi da vas podsjetim da još uvijek testiramo sinkroni način). Međutim, ne bih se uzrujavao zbog toga prije vremena; SQL podrška je još uvijek u aktivnom razvoju (relativno nedavno, na primjer, podrška je dodana pripremljene izjave) i, sudeći po popisu pitanja, SQL mehanizam proći će niz optimizacija u budućnosti.

Asinkroniziraj

Pa, sada da vidimo kako nam proširenje Async može pomoći da poboljšamo gore navedene rezultate. Za pisanje asinkronih programa, proširenje pruža API temeljen na korutinama, koje ćemo koristiti. Empirijski smo utvrdili da je optimalan broj korutina za naše okruženje 25:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
"Raširite" 10,000 25 operacija na XNUMX korutina i pogledajte što će se dogoditi:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Broj operacija u sekundi povećao se za više od 3 puta tarantool-php/klijent!

Nažalost, PECL konektor nije započeo s ext-async.

Što je sa SQL-om?

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Kao što vidite, u asinkronom načinu rada razlika između binarnog protokola i SQL-a postala je unutar granice pogreške.

Swoole

Opet saznajemo optimalan broj korutina, ovaj put za Swoole:
Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Zaustavimo se na 25. Ponovimo isti trik kao s Async ekstenzijom – rasporedimo 10,000 25 operacija između 2 korutina. Dodatno ćemo dodati još jedan test u kojem ćemo sav posao podijeliti u 5,000 dva procesa (odnosno, svaki proces će izvesti 25 operacija u XNUMX korutina). Procesi će se kreirati pomoću SwooleProcess.

Rezultati:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Swole pokazuje nešto niži rezultat u usporedbi s Async-om kada se izvodi u jednom procesu, ali s 2 procesa slika se dramatično mijenja (broj 2 nije odabran slučajno; na mom stroju su 2 procesa pokazala najbolji rezultat).

Inače, proširenje Async također ima API za rad s procesima, ali tu nisam primijetio nikakvu razliku od pokretanja benchmarkova u jednom ili više procesa (moguće je da sam negdje zabrljao).

SQL u odnosu na binarni protokol:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Kao i kod Async, razlika između binarnih i SQL operacija eliminirana je u asinkronom načinu rada.

Paralelno

Budući da proširenje Parallel nije o korutinama, već o nitima, izmjerimo optimalan broj paralelnih niti:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Jednako je 16 na mom stroju. Pokrenimo usporedne testove konektora na 16 paralelnih niti:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Kao što vidite, rezultat je još bolji nego s asinkronim proširenjima (ne računajući Swoole koji radi na 2 procesa). Imajte na umu da su za PECL konektor operacije Update i Upsert prazne. To je zbog činjenice da ove operacije nisu uspjele s pogreškom - ne znam je li kriv ext-parallel, ext-tarantool ili oboje.

Sada usporedimo performanse SQL-a:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel
Primjećujete sličnost s grafikonom za konektore koji rade sinkrono?

Zajedno

I na kraju, sažmimo sve rezultate u jedan grafikon kako bismo vidjeli ukupnu sliku za testirana proširenja. Dodajmo samo jedan novi test grafikonu, koji još nismo napravili - pokrenimo Async korutine paralelno koristeći Parallel*. Ideja o integraciji gore navedenih proširenja već postoji raspravljalo se autora, ali nije postignut konsenzus, morat ćete to učiniti sami.

* Nije bilo moguće pokrenuti Swoole korutine s Parallelom; čini se da su ova proširenja nekompatibilna.

Dakle, konačni rezultati:

Ubrzavanje PHP konektora za Tarantool korištenjem Async, Swoole i Parallel

Umjesto zaključka

Po mom mišljenju, rezultati su se pokazali prilično vrijednim i iz nekog razloga sam siguran da to nije granica! Trebate li to odlučiti u stvarnom projektu samo za sebe, reći ću samo da je za mene bio zanimljiv eksperiment koji vam omogućuje da procijenite koliko možete "iscijediti" iz sinkronog TCP konektora uz minimalan napor. Ako imate ideje za poboljšanje referentnih vrijednosti, rado ću razmotriti vaš zahtjev za povlačenjem. Sav kod s uputama za pokretanje i rezultatima objavljen je u zasebnom izdanju spremišta.

Izvor: www.habr.com

Dodajte komentar