Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel

Sa PHP ecosystem mayroong kasalukuyang dalawang konektor para sa pagtatrabaho sa Tarantool server - ito ang opisyal na extension ng PECL tarantool/tarantool-php, nakasulat sa C, at tarantool-php/client, nakasulat sa PHP. Ako ang may-akda ng huli.

Sa artikulong ito, nais kong ibahagi ang mga resulta ng pagsubok sa pagganap ng parehong mga aklatan at ipakita kung paano, sa kaunting pagbabago sa code, makakamit mo ang 3-5 na pagtaas ng pagganap (sa mga sintetikong pagsubok!).

Ano ang susuriin natin?

Susubukan namin ang mga nabanggit sa itaas magkasabay mga connector na tumatakbo nang asynchronously, parallel, at asynchronously-parallel. πŸ™‚ Hindi rin namin gustong hawakan ang code ng mga connector mismo. Kasalukuyang mayroong ilang extension na magagamit upang makamit ang gusto mo:

  • Swoole ― isang high-performance na asynchronous na framework para sa PHP. Ginamit ng mga higanteng Internet tulad ng Alibaba at Baidu. Mula noong bersyon 4.1.0 ay lumitaw ang isang magic method SwooleRuntime::enableCoroutine(), na nagbibigay-daan sa iyong "i-convert ang mga kasabay na PHP network library sa mga asynchronous na may isang linya ng code."
  • Ang Async ay hanggang kamakailan ay isang napaka-promising na extension para sa asynchronous na trabaho sa PHP. Bakit hanggang kamakailan lang? Sa kasamaang palad, sa hindi ko malamang kadahilanan, tinanggal ng may-akda ang repositoryo at ang hinaharap na kapalaran ng proyekto ay hindi malinaw. Kailangan ko itong gamitin isang mula sa mga tinidor. Tulad ng Swoole, binibigyang-daan ka ng extension na ito na madaling i-on ang iyong pantalon gamit ang isang flick ng pulso upang paganahin ang asynchrony sa pamamagitan ng pagpapalit sa karaniwang pagpapatupad ng TCP at TLS stream ng kanilang mga asynchronous na bersyon. Ginagawa ito sa pamamagitan ng opsyon na "async.tcp = 1".
  • Pagpaparis ― isang medyo bagong extension mula sa kilalang Joe Watkins, may-akda ng mga library gaya ng phpdbg, apcu, pthreads, pcov, uopz. Nagbibigay ang extension ng API para sa multithreading sa PHP at nakaposisyon bilang kapalit ng mga pthread. Ang isang makabuluhang limitasyon ng library ay gumagana lamang ito sa ZTS (Zend Thread Safe) na bersyon ng PHP.

Paano tayo susubok?

Maglunsad tayo ng isang halimbawa ng Tarantool na hindi pinagana ang write-ahead logging (wal_mode = wala) at tumaas na buffer ng network (readahead = 1 * 1024 * 1024). Ang unang opsyon ay aalisin ang trabaho sa disk, ang pangalawa ay gagawing posible na magbasa ng higit pang mga kahilingan mula sa buffer ng operating system at sa gayon ay mabawasan ang bilang ng mga tawag sa system.

Para sa mga benchmark na gumagana sa data (pagpasok, pagtanggal, pagbabasa, atbp.), bago simulan ang benchmark, isang memtx space ay (muling gagawa, kung saan ang mga pangunahing index value ay nilikha ng isang generator ng ordered integer values ​​​(pagkakasunod-sunod).
Ang space DDL ay ganito ang hitsura:

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

Kung kinakailangan, bago patakbuhin ang benchmark, ang espasyo ay puno ng 10,000 tuple ng form

{id, "tuplΠ΅_<id>"}

Ang mga tuple ay ina-access gamit ang isang random na halaga ng key.

Ang benchmark mismo ay isang solong kahilingan sa server, na isinasagawa ng 10,000 beses (mga rebolusyon), na, naman, ay isinasagawa sa mga pag-ulit. Ang mga pag-ulit ay inuulit hanggang sa lahat ng oras na mga paglihis sa pagitan ng 5 mga pag-ulit ay nasa loob ng isang katanggap-tanggap na error na 3%*. Pagkatapos nito, ang average na resulta ay kinuha. Mayroong 1 segundong pag-pause sa pagitan ng mga pag-ulit upang maiwasan ang pag-thrott ng processor. Ang tagakolekta ng basura ni Lua ay hindi pinagana bago ang bawat pag-ulit at napipilitang magsimula pagkatapos nitong makumpleto. Ang proseso ng PHP ay inilunsad lamang gamit ang mga extension na kinakailangan para sa benchmark, na pinagana ang output buffering at ang basurero ay hindi pinagana.

* Maaaring baguhin ang bilang ng mga rebolusyon, pag-ulit at limitasyon ng error sa mga setting ng benchmark.

Kapaligirang pang eksperiment

Ang mga resultang na-publish sa ibaba ay ginawa sa isang MacBookPro (2015), operating system - Fedora 30 (kernel version 5.3.8-200.fc30.x86_64). Ang Tarantool ay inilunsad sa docker na may parameter na "--network host".

Mga bersyon ng package:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, bumuo ng a872fc2f86
PHP: 7.3.11 (cli) (ginawa: Okt 22 2019 08:11:04)
tarantool/kliyente: 0.6.0
rybakit/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ patch para sa 7.3)*
ext-msgpack: 2.0.3
ext-async: 0.3.0-8c1da46
ext-swoole: 4.4.12
ext-parallel: 1.1.3

* Sa kasamaang palad, ang opisyal na konektor ay hindi gumagana sa bersyon ng PHP > 7.2. Upang i-compile at patakbuhin ang extension sa PHP 7.3, kailangan kong gamitin patch.

Natuklasan

Synchronous mode

Gumagamit ang Tarantool protocol ng binary na format MessagePack para i-serialize ang mga mensahe. Sa PECL connector, nakatago ang serialization sa kaibuturan ng library at nakakaapekto sa proseso ng pag-encode mula sa userland code parang hindi pwede. Ang isang purong PHP connector, sa kabaligtaran, ay nagbibigay ng kakayahang i-customize ang proseso ng pag-encode sa pamamagitan ng pagpapalawak ng karaniwang encoder o sa pamamagitan ng paggamit ng iyong sariling pagpapatupad. Mayroong dalawang encoder na magagamit sa labas ng kahon, ang isa ay batay sa msgpack/msgpack-php (opisyal na extension ng MessagePack PECL), naka-on ang isa rybakit/msgpack (sa purong PHP).

Bago ihambing ang mga konektor, susukatin namin ang pagganap ng mga MessagePack encoder para sa PHP connector at sa karagdagang mga pagsubok ay gagamitin namin ang isa na nagpapakita ng pinakamahusay na resulta:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Kahit na ang bersyon ng PHP (Puro) ay mas mababa sa extension ng PECL sa bilis, sa mga totoong proyekto ay inirerekomenda ko pa rin ang paggamit nito rybakit/msgpack, dahil sa opisyal na extension ng MessagePack ang detalye ng format ay bahagyang ipinatupad lamang (halimbawa, walang suporta para sa mga custom na uri ng data, kung wala ito ay hindi mo magagamit ang Decimal - isang bagong uri ng data na ipinakilala sa Tarantool 2.3) at mayroong isang bilang ng iba mga problema (kabilang ang mga isyu sa compatibility sa PHP 7.4). Well, sa pangkalahatan, ang proyekto ay mukhang inabandona.

Kaya, sukatin natin ang pagganap ng mga konektor sa synchronous mode:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Tulad ng makikita mula sa graph, ang PECL connector (Tarantool) ay nagpapakita ng mas mahusay na performance kumpara sa PHP connector (Client). Ngunit hindi ito nakakagulat, dahil ang huli, bilang karagdagan sa ipinatupad sa isang mas mabagal na wika, ay talagang gumagawa ng mas maraming trabaho: isang bagong bagay ay nilikha sa bawat tawag Hiling ΠΈ tugon (sa kaso ng Select - din Pamantayan ng, at sa kaso ng Update/Upsert ― Mga Operasyon ), magkahiwalay na entity koneksyon, Packer ΠΈ handler nagdagdag din sila ng overhead. Malinaw, ang kakayahang umangkop ay may isang presyo. Gayunpaman, sa pangkalahatan, ang PHP interpreter ay nagpapakita ng mahusay na pagganap, bagama't may pagkakaiba, ito ay hindi gaanong mahalaga at, marahil, ay magiging mas kaunti kapag gumagamit ng preloading sa PHP 7.4, hindi banggitin ang JIT sa PHP 8.

Mag-move on na tayo. Nagdagdag ang Tarantool 2.0 ng suporta para sa SQL. Subukan nating magsagawa ng Select, Insert, Update at Delete operation gamit ang SQL protocol at ihambing ang mga resulta sa mga katumbas na noSQL (binary):

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Ang mga resulta ng SQL ay hindi masyadong kahanga-hanga (hayaan kong ipaalala sa iyo na sinusubukan pa rin namin ang synchronous mode). Gayunpaman, hindi ako magagalit tungkol dito nang maaga; Ang suporta sa SQL ay nasa ilalim pa rin ng aktibong pag-unlad (medyo kamakailan lamang, halimbawa, ang suporta ay idinagdag mga inihandang pahayag) at, ayon sa listahan isyu, ang SQL engine ay sasailalim sa ilang mga pag-optimize sa hinaharap.

async

Well, ngayon tingnan natin kung paano makakatulong sa amin ang extension ng Async na pahusayin ang mga resulta sa itaas. Upang magsulat ng mga asynchronous na programa, ang extension ay nagbibigay ng API batay sa mga coroutine, na aming gagamitin. Nalaman namin sa empirically na ang pinakamainam na bilang ng mga coroutine para sa aming kapaligiran ay 25:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
"Ipagkalat" ang 10,000 na operasyon sa 25 coroutine at tingnan kung ano ang mangyayari:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Ang bilang ng mga operasyon sa bawat segundo ay tumaas ng higit sa 3 beses para sa tarantool-php/client!

Nakalulungkot, ang PECL connector ay hindi nagsimula sa ext-async.

Paano ang tungkol sa SQL?

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Tulad ng nakikita mo, sa asynchronous mode ang pagkakaiba sa pagitan ng binary protocol at SQL ay naging nasa margin ng error.

Swoole

Muli naming nalaman ang pinakamainam na bilang ng mga coroutine, sa pagkakataong ito para sa Swoole:
Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Huminto tayo sa 25. Ulitin natin ang parehong trick tulad ng sa extension ng Async - ipamahagi ang 10,000 na operasyon sa pagitan ng 25 coroutine. Bilang karagdagan, magdaragdag kami ng isa pang pagsubok kung saan hahatiin namin ang lahat ng gawain sa 2 dalawang proseso (iyon ay, ang bawat proseso ay magsasagawa ng 5,000 na operasyon sa 25 coroutine). Ang mga proseso ay gagawin gamit ang SwooleProcess.

Mga resulta:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Ang swole ay nagpapakita ng bahagyang mas mababang resulta kumpara sa Async kapag tumakbo sa isang proseso, ngunit sa 2 proseso ang larawan ay nagbabago nang malaki (ang numero 2 ay hindi napili ng pagkakataon; sa aking makina, ito ay 2 proseso na nagpakita ng pinakamahusay na resulta).

Sa pamamagitan ng paraan, ang extension ng Async ay mayroon ding isang API para sa pagtatrabaho sa mga proseso, ngunit doon ay hindi ko napansin ang anumang pagkakaiba sa pagpapatakbo ng mga benchmark sa isa o higit pang mga proseso (posible na ako ay nagkamali sa isang lugar).

SQL vs binary protocol:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Tulad ng sa Async, ang pagkakaiba sa pagitan ng binary at SQL na mga pagpapatakbo ay inalis sa asynchronous mode.

Pagpaparis

Dahil ang Parallel extension ay hindi tungkol sa mga coroutine, ngunit tungkol sa mga thread, sukatin natin ang pinakamainam na bilang ng mga parallel na thread:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Ito ay 16 sa aking makina. Patakbuhin natin ang mga benchmark ng connector sa 16 na parallel na mga thread:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Tulad ng nakikita mo, ang resulta ay mas mahusay kaysa sa mga asynchronous na extension (hindi binibilang ang Swoole na tumatakbo sa 2 proseso). Tandaan na para sa PECL connector, ang Update at Upsert operations ay walang laman. Ito ay dahil sa ang katunayan na ang mga operasyong ito ay nabigo nang may isang error - hindi ko alam kung ito ay kasalanan ng ext-parallel, ext-tarantool, o pareho.

Ngayon ihambing natin ang pagganap ng SQL:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel
Pansinin ang pagkakatulad sa graph para sa mga konektor na tumatakbo nang sabay-sabay?

Magkasama

At panghuli, ibuod natin ang lahat ng resulta sa isang graph para makita ang pangkalahatang larawan para sa mga nasubok na extension. Magdagdag lang ng isang bagong pagsubok sa chart, na hindi pa natin nagagawa - patakbuhin natin ang mga Async coroutine nang magkatulad gamit ang Parallel*. Ang ideya ng pagsasama ng mga extension sa itaas ay na napag-usapan mga may-akda, ngunit walang naabot na pinagkasunduan, kakailanganin mong gawin ito sa iyong sarili.

* Hindi posibleng ilunsad ang Swoole coroutine na may Parallel; mukhang hindi tugma ang mga extension na ito.

Kaya, ang mga huling resulta:

Pinapabilis ang mga konektor ng PHP para sa Tarantool gamit ang Async, Swoole at Parallel

Sa halip ng isang konklusyon

Sa palagay ko, ang mga resulta ay naging karapat-dapat, at sa ilang kadahilanan sigurado ako na hindi ito ang limitasyon! Kung kailangan mong magpasya dito sa isang tunay na proyekto para lamang sa iyong sarili, sasabihin ko lang na para sa akin ito ay isang kawili-wiling eksperimento na nagbibigay-daan sa iyo upang suriin kung gaano karaming maaari mong "pisilin" mula sa isang kasabay na TCP connector na may kaunting pagsisikap. Kung mayroon kang mga ideya para sa pagpapabuti ng mga benchmark, ikalulugod kong isaalang-alang ang iyong kahilingan sa paghila. Ang lahat ng code na may mga tagubilin sa paglunsad at mga resulta ay nai-publish sa isang hiwalay mga repositoryo.

Pinagmulan: www.habr.com

Magdagdag ng komento