Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel

En la PHP-ekosistemo ekzistas nuntempe du konektiloj por labori kun la Tarantool-servilo - ĉi tio estas la oficiala PECL-etendo tarantool/tarantool-php, skribita en C, kaj tarantool-php/kliento, skribita en PHP. Mi estas la aŭtoro de ĉi-lasta.

En ĉi tiu artikolo, mi ŝatus kunhavigi la rezultojn de agado-testado de ambaŭ bibliotekoj kaj montri kiel, kun minimumaj ŝanĝoj al la kodo, vi povas atingi 3-5-efikecpliiĝon (pri sintezaj provoj!).

Kion ni provos?

Ni provos tiujn supre menciitajn sinkrona konektiloj kurantaj nesinkrone, paralele kaj nesinkrone-paralele. 🙂 Ni ankaŭ ne volas tuŝi la kodon de la konektiloj mem. Nuntempe ekzistas pluraj etendaĵoj disponeblaj por atingi tion, kion vi volas:

  • Swoole ― alt-efikeca nesinkrona kadro por PHP. Uzita de tiaj interretaj gigantoj kiel Alibaba kaj Baidu. Ekde versio 4.1.0 aperis magia metodo SwooleRuntime::enableCoroutine(), kiu permesas vin "konverti sinkronajn PHP-retajn bibliotekojn al nesinkronaj kun unu linio de kodo."
  • Async estis ĝis antaŭ nelonge tre promesplena etendaĵo por nesinkrona laboro en PHP. Kial ĝis antaŭ nelonge? Bedaŭrinde, pro nekonata kialo de mi, la aŭtoro forigis la deponejon kaj la estonta sorto de la projekto estas neklara. Mi devos uzi ĝin unu de forkoj. Kiel Swoole, ĉi tiu etendaĵo permesas vin facile enŝalti viajn pantalonojn per movo de la pojno por ebligi malsinkronion anstataŭigante la norman efektivigon de TCP kaj TLS-fluoj per iliaj nesinkronaj versioj. Ĉi tio estas farita per la opcio "async.tcp = 1".
  • Paralela ― sufiĉe nova etendaĵo de la konata Joe Watkins, aŭtoro de tiaj bibliotekoj kiel phpdbg, apcu, pthreads, pcov, uopz. La etendaĵo disponigas API por multifadenado en PHP kaj estas poziciigita kiel anstataŭaĵo por pthreads. Signifa limigo de la biblioteko estas, ke ĝi funkcias nur kun la versio ZTS (Zend Thread Safe) de PHP.

Kiel ni provos?

Ni lanĉu Tarantool-instancon kun skribo-antaŭa registrado malŝaltita (wal_mode = neniu) kaj pliigita reta bufro (legotablo = 1 * 1024 * 1024). La unua opcio forigos laboron kun la disko, la dua ebligos legi pli da petoj de la operaciuma bufro kaj tiel minimumigi la nombron da sistemaj vokoj.

Por komparnormoj, kiuj funkcias kun datumoj (enmeto, forigo, legado, ktp.), antaŭ ol komenci la komparnormon, memtx-spaco estos (re)kreita, en kiu la primaraj indeksaj valoroj estas kreitaj per generatoro de ordigitaj entjervaloroj. (sekvenco).
La spaco DDL aspektas jene:

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

Se necese, antaŭ ol ruli la komparnormon, la spaco estas plenigita per 10,000 opoj de la formo

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

Opoj estas aliritaj uzante hazardan ŝlosilvaloron.

La komparnormo mem estas ununura peto al la servilo, kiu estas ekzekutita 10,000 fojojn (revolucioj), kiuj, siavice, estas ekzekutitaj en ripetoj. La ripetoj estas ripetitaj ĝis ĉiuj tempaj devioj inter 5 ripetoj estas ene de akceptebla eraro de 3%*. Post ĉi tio, la averaĝa rezulto estas prenita. Estas 1-sekunda paŭzo inter ripetoj por malhelpi la procesoron de estrango. La rubkolektisto de Lua estas malfunkciigita antaŭ ĉiu ripeto kaj estas devigita komenci post kiam ĝi finiĝas. La PHP-procezo estas lanĉita nur kun la etendaĵoj necesaj por la komparnormo, kun eligo-buffering ebligita kaj la rubkolektilo malŝaltita.

* La nombro da revolucioj, ripetoj kaj erarsojlo povas esti ŝanĝita en la komparnormaj agordoj.

Testa medio

La rezultoj publikigitaj sube estis faritaj sur MacBookPro (2015), operaciumo - Fedora 30 (kerna versio 5.3.8-200.fc30.x86_64). Tarantool estis lanĉita en docker kun la parametro "--network host".

Pakaj versioj:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, konstruu a872fc2f86
PHP: 7.3.11 (cli) (konstruita: la 22-an de oktobro 2019 08:11:04)
tarantool/kliento: 0.6.0
rybakit/msgpack: 0.6.1
ekst-tarantool: 0.3.2 (+ diakilo por 7.3)*
ext-msgpack: 2.0.3
ekst-async: 0.3.0-8c1da46
ext-swoole: 4.4.12
ekst-paralelo: 1.1.3

* Bedaŭrinde, la oficiala konektilo ne funkcias kun PHP-versio > 7.2. Por kompili kaj ruli la etendon sur PHP 7.3, mi devis uzi flikaĵo.

Результаты

Sinkrona reĝimo

La Tarantool-protokolo uzas binaran formaton MesaĝPako por serigi mesaĝojn. En la PECL-konektilo, seriigo estas kaŝita profunde en la profundoj de la biblioteko kaj influas la kodigan procezon de userland-kodo. ne ŝajnas ebla. Pura PHP-konektilo, male, disponigas la kapablon personecigi la kodigan procezon etendante la norman kodilon aŭ uzante vian propran efektivigon. Estas du kodigiloj haveblaj el la skatolo, unu estas bazita sur msgpack/msgpack-php (oficiala etendo de MessagePack PECL), la alia estas ŝaltita rybakit/msgpack (en pura PHP).

Antaŭ ol kompari konektilojn, ni mezuros la rendimenton de MessagePack-kodigiloj por la PHP-konektilo kaj en pliaj provoj ni uzos tiun, kiu montras la plej bonan rezulton:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Kvankam la PHP-versio (Pure) estas malsupera al la etendo de PECL en rapideco, en realaj projektoj mi ankoraŭ rekomendus uzi ĝin. rybakit/msgpack, ĉar en la oficiala etendaĵo MessagePack la formatspecifo estas nur parte efektivigita (ekzemple, ne ekzistas subteno por kutimaj datumtipoj, sen kiuj vi ne povos uzi Decimal - novan datumtipo enkondukita en Tarantool 2.3) kaj havas nombro da aliaj problemoj (inkluzive de kongruaj problemoj kun PHP 7.4). Nu, ĝenerale, la projekto aspektas forlasita.

Do, ni mezuru la rendimenton de konektiloj en sinkrona reĝimo:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Kiel videblas de la grafikaĵo, la PECL-konektilo (Tarantool) montras pli bonan rendimenton kompare kun la PHP-konektilo (Kliento). Sed tio ne estas surpriza, ĉar ĉi-lasta, krom esti efektivigita en pli malrapida lingvo, efektive faras pli da laboro: nova objekto estas kreita kun ĉiu voko. peto и respondo (kaze de Elektu - ankaŭ kriterioj, kaj en la kazo de Ĝisdatigo/Upsert ― operacioj), apartaj estaĵoj konekto, Pakisto и Manlibro ili ankaŭ aldonas supre. Evidente, fleksebleco havas prezon. Tamen, ĝenerale, la PHP-interpretisto montras bonan rendimenton, kvankam estas diferenco, ĝi estas sensignifa kaj, eble, estos eĉ malpli kiam vi uzas antaŭŝarĝon en PHP 7.4, por ne mencii JIT en PHP 8.

Ni pluiru. Tarantool 2.0 lanĉis SQL-subtenon. Ni provu fari Elekti, Enigi, Ĝisdatigi kaj Forigi operaciojn uzante la SQL-protokolo kaj komparu la rezultojn kun la noSQL (binaraj) ekvivalentoj:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
La SQL-rezultoj ne estas tre imponaj (mi memorigu vin, ke ni ankoraŭ testas sinkronan reĝimon). Tamen, mi ne ĉagreniĝus pri tio antaŭtempe; SQL-subteno ankoraŭ estas aktiva disvolviĝo (relative lastatempe, ekzemple, subteno estis aldonita preparitaj deklaroj) kaj, juĝante laŭ la listo temoj, la SQL-motoro suferos kelkajn optimumigojn en la estonteco.

Asinkronigi

Nu, nun ni vidu kiel la etendo Async povas helpi nin plibonigi la rezultojn supre. Por skribi nesinkronajn programojn, la etendaĵo disponigas API bazitan sur korutinoj, kiujn ni uzos. Ni malkovras empirie, ke la optimuma nombro da korutinoj por nia medio estas 25:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
"Disvastigu" 10,000 operaciojn tra 25 korutinoj kaj vidu kio okazas:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
La nombro da operacioj por sekundo pliiĝis pli ol 3 fojojn por tarantool-php/kliento!

Bedaŭrinde, la PECL-konektilo ne komenciĝis per ekst-async.

Kio pri SQL?

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Kiel vi povas vidi, en nesinkrona reĝimo la diferenco inter la binara protokolo kaj SQL fariĝis ene de la marĝeno de eraro.

Swoole

Denove ni malkovras la optimuman nombron da korutinoj, ĉi-foje por Swoole:
Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Ni ĉesu ĉe 25. Ni ripetu la saman lertaĵon kiel kun la etendo Async - distribuu 10,000 25 operaciojn inter 2 korutinoj. Krome, ni aldonos alian teston, en kiu ni dividos la tutan laboron en 5,000 du procezojn (tio estas, ĉiu procezo plenumos 25 XNUMX operaciojn en XNUMX korutinoj). Procezoj estos kreitaj uzante SwooleProcess.

Rezulto:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Swole montras iomete pli malaltan rezulton kompare kun Async kiam rulita en unu procezo, sed kun 2 procezoj la bildo ŝanĝiĝas draste (la numero 2 ne estis elektita hazarde; ĉe mia maŝino, estis 2 procezoj kiuj montris la plej bonan rezulton).

Cetere, la etendo Async ankaŭ havas API por labori kun procezoj, sed tie mi ne rimarkis neniun diferencon de ruli benchmarkojn en unu aŭ pluraj procezoj (eblas, ke mi fuŝis ie).

SQL vs binara protokolo:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Kiel ĉe Async, la diferenco inter binaraj kaj SQL-operacioj estas forigita en nesinkrona reĝimo.

Paralela

Ĉar la Paralela etendaĵo ne temas pri korutinoj, sed pri fadenoj, ni mezuru la optimuman nombron da paralelaj fadenoj:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Ĝi estas egala al 16 sur mia maŝino. Ni rulu konektilojn sur 16 paralelaj fadenoj:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Kiel vi povas vidi, la rezulto estas eĉ pli bona ol kun nesinkronaj etendoj (sen kalkuli Swoole funkciantan sur 2 procezoj). Notu, ke por la PECL-konektilo, la operacioj Ĝisdatigo kaj Upsert estas malplenaj. Ĉi tio estas pro tio, ke ĉi tiuj operacioj malsukcesis pro eraro - mi ne scias ĉu ĝi estis kulpo de ext-parallel, ext-tarantool, aŭ ambaŭ.

Nun ni komparu SQL-agadon:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel
Rimarku la similecon kun la grafeo por konektiloj kurantaj sinkrone?

Kune

Kaj finfine, ni resumu ĉiujn rezultojn en unu grafikaĵo por vidi la ĝeneralan bildon por la testitaj etendaĵoj. Ni aldonu nur unu novan teston al la diagramo, kion ni ankoraŭ ne faris - ni rulu Async-korutinojn paralele uzante Paralelon*. La ideo integri la suprajn etendojn jam estas estis diskutita aŭtoroj, sed neniu konsento estis atingita, vi devos fari ĝin mem.

* Ne eblis lanĉi Swoole-korutinojn kun Paralelo; ŝajnas, ke ĉi tiuj etendaĵoj estas malkongruaj.

Do, la finaj rezultoj:

Akceli PHP-konektilojn por Tarantool uzante Async, Swoole kaj Paralel

Anstataŭ konkludo

Laŭ mi, la rezultoj montriĝis sufiĉe indaj, kaj ial mi certas, ke ĉi tio ne estas la limo! Ĉu vi bezonas decidi ĉi tion en reala projekto nur por vi mem, mi nur diros, ke por mi ĝi estis interesa eksperimento, kiu ebligas al vi taksi kiom vi povas "elpremi" el sinkrona TCP-konektilo kun minimuma peno. Se vi havas ideojn por plibonigi benchmarkojn, mi volonte konsideros vian tiran peton. Ĉiuj kodoj kun lanĉaj instrukcioj kaj rezultoj estas publikigitaj aparte deponejoj.

fonto: www.habr.com

Aldoni komenton