
Dalam ekosistem PHP, saat ini ada dua konektor untuk server Tarantool: ekstensi PECL resmi
tarantool / tarantool-php yang ditulis dalam C, dan
tarantool-php / klien yang ditulis dalam PHP. Saya penulis yang terakhir.
Pada artikel ini saya ingin berbagi hasil pengujian kinerja kedua perpustakaan ini dan menunjukkan bagaimana Anda dapat mencapai peningkatan kinerja 3x-5x (
pada tes sintetis! ) Dengan sedikit perubahan dalam kode.
Apa yang akan kita uji?
Kami akan menguji konektor sinkron yang disebutkan di atas yang diluncurkan secara asinkron, paralel, dan asinkron secara paralel. Kami juga tidak menginginkan perubahan untuk kode sumber konektor. Saat ini ada beberapa ekstensi yang tersedia yang dapat melakukan pekerjaan:
- Swoole , kerangka kerja asinkron berkinerja tinggi untuk PHP. Digunakan oleh raksasa internet seperti Alibaba dan Baidu. Sejak versi 4.1.0, kait runtime yang menakjubkan Swoole \ Runtime :: enableCoroutine () telah muncul, memungkinkan βuntuk mengubah pustaka jaringan PHP yang sinkron menjadi pustaka rutin bersama dengan menggunakan satu baris kodeβ.
- Async, ekstensi yang sangat menjanjikan untuk pekerjaan asinkron di PHP hingga saat ini. Kenapa sampai saat ini? Sayangnya, karena alasan yang saya tidak tahu, penulis menghapus repositori dan masa depan proyek dipertanyakan. Saya akan menggunakan salah satu garpu. Seperti Swoole, ekstensi ini memudahkan untuk mengaktifkan mode asinkron dengan mengganti implementasi aliran default PHP dengan mitra async mereka. Ini dilakukan melalui opsi β async.tcp = 1 β.
- Paralel , ekstensi yang cukup baru dari Joe Watkins yang terkenal, penulis perpustakaan seperti phpdbg, apcu, pthreads, pcov, uopz. Ekstensi menyediakan API multi-threading untuk PHP dan diposisikan sebagai pengganti pthreads. Keterbatasan perpustakaan yang signifikan adalah bahwa ia hanya berfungsi dengan versi ZTS (Zend Thread Safe) dari PHP.
Bagaimana kita akan menguji?
Kami akan menjalankan instance Tarantool dengan pencatatan write-ahead dinonaktifkan (
wal_mode = tidak ada ) dan buffer jaringan yang diperluas (
readahead = 1 * 1024 * 1024 ). Opsi pertama akan mencegah operasi IO ke disk drive, yang kedua akan memungkinkan membaca lebih banyak permintaan dari buffer sistem operasi dan dengan demikian meminimalkan jumlah panggilan sistem.
Untuk tolok ukur yang berfungsi dengan data (penyisipan, penghapusan, membaca, dll.), Ruang memtx akan dibuat (kembali) sebelum benchmark dimulai, dan nilai indeks awal untuk ruang ini akan dibuat oleh generator urutan.
Ruang DDL adalah sebagai berikut:
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} })
Jika perlu, sebelum memulai patokan, ruang diisi dengan 10.000 tupel dari formulir berikut:
{id, 'tuple_' .. id}
Tuples diakses menggunakan nilai kunci acak.
Benchmark adalah permintaan tunggal ke server yang dieksekusi 10.000 kali (revolusi), yang pada gilirannya dieksekusi dalam iterasi. Iterasi diulangi sampai semua penyimpangan waktu di antara 5 iterasi berada dalam margin kesalahan 3% *. Setelah itu, hasil rata-rata diambil. Di antara iterasi, ada jeda 1 detik untuk mencegah CPU dari pelambatan. Pengumpul sampah Lua dinonaktifkan sebelum setiap iterasi dan dipaksa untuk memulai setelah iterasi selesai. Proses PHP diluncurkan hanya dengan ekstensi yang diperlukan untuk tolok ukur, dengan buffering output diaktifkan dan pengumpul sampah dinonaktifkan.
* Jumlah putaran, iterasi dan ambang kesalahan dapat diubah dalam pengaturan benchmark.Lingkungan uji
Hasil yang diposting di bawah ini dibuat di MacBookPro (pertengahan 2015) dengan Fedora 30 (kernel versi 5.3.8-200.fc30.x86_64). Tarantool diluncurkan di buruh pelabuhan dengan pengaturan "
--network host ".
Versi paket:Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 03/19/3, bangun a872fc2f86
PHP: 7.3.11 (cli) (dibangun: 22 Okt 2019 08:11:04)
tarantool / klien: 0.6.0
rybakit / msgpack: 0.6.1
ext-tarantool: 0.3.2 (ditambal) *
ext-msgpack: 2.0.3
ext-async: 0.3.0-8c1da46
ext-swoole: 4.4.12
ext-parallel: 1.1.3
* Sayangnya, konektor resmi tidak berfungsi dengan PHP> 7.2. Untuk mengkompilasi dan menjalankan ekstensi pada PHP 7.3, saya harus menggunakan patch .Hasil
Sinkronkan (default)
Protokol Tarantool menggunakan format biner
MessagePack untuk membuat serialisasi pesan. Pada konektor PECL, serialisasi disembunyikan jauh di dalam perpustakaan, sehingga
tampaknya tidak mungkin untuk mempengaruhi proses pengkodean dari kode userland. Sebaliknya, konektor PHP murni memberikan kemampuan untuk menyesuaikan proses encoding, baik dengan memperluas salah satu encoders standar, atau dengan menggunakan implementasi Anda sendiri. Dua encoders tersedia di luar kotak: satu didasarkan pada
msgpack / msgpack-php (ekstensi PECL MessagePack resmi) dan yang lainnya didasarkan pada
rybakit / msgpack (PHP murni).
Sebelum kami melanjutkan untuk membandingkan konektor, mari kita mengukur kinerja encoders MessagePack untuk konektor PHP, sehingga kami menggunakan pemain terbaik selanjutnya dalam pengujian kami:
Meskipun versi PHP (Murni) tidak secepat ekstensi PECL, saya masih akan merekomendasikan menggunakan
rybakit / msgpack dalam proyek nyata, karena ekstensi PECL resmi mengimplementasikan spesifikasi MessagePack hanya sebagian (misalnya tidak ada dukungan untuk tipe data kustom, dan tanpa itu Anda tidak dapat menggunakan Desimal - tipe data baru yang diperkenalkan di Tarantool 2.3) dan memiliki sejumlah
masalah lain (termasuk masalah kompatibilitas dengan PHP 7.4). Dan proyek tersebut terlihat ditinggalkan secara umum.
Jadi, mari kita ukur kinerja konektor dalam mode sinkron:
Seperti yang dapat Anda lihat dari grafik, konektor PECL (Tarantool) berkinerja lebih baik daripada konektor PHP (Klien). Itu tidak mengherankan, mengingat bahwa yang terakhir, selain diimplementasikan dalam bahasa yang lebih lambat, sebenarnya lebih berfungsi: objek
Permintaan dan
Respons baru dibuat dengan setiap permintaan (dalam kasus Select ada juga
Kriteria , dan dalam kasus Pembaruan / Upsert ada
Operasi ),
Connection ,
Packer dan
Handler juga menambahkan beberapa overhead. Tidak perlu dikatakan bahwa fleksibilitas yang lebih tinggi disertai dengan biaya. Namun, juru bahasa PHP menunjukkan kinerja yang baik secara umum. Meskipun ada perbedaan, itu tidak signifikan dan mungkin mendapatkan lebih sedikit lagi dengan menggunakan preloading di PHP 7.4, belum lagi JIT di PHP 8.
Pindah sekarang. Tarantool 2.0 memperkenalkan dukungan SQL. Mari kita coba melakukan operasi Select, Insert, Update dan Delete menggunakan protokol SQL dan bandingkan hasilnya dengan setara dengan noSQL (biner):
Hasil SQL tidak terlalu mengesankan (izinkan saya mengingatkan Anda bahwa kami masih menguji mode sinkron). Namun, saya tidak akan marah tentang hal itu sebelum waktu: Dukungan SQL masih dalam pengembangan aktif (misalnya, dukungan untuk
pernyataan yang disiapkan telah ditambahkan belum lama ini) dan, sesuai dengan daftar
masalah , mesin SQL akan dapatkan sejumlah optimasi di masa depan.
Async
Baiklah, mari kita lihat sekarang bagaimana ekstensi Async dapat membantu kami meningkatkan hasil di atas. Untuk pemrograman asinkron, ekstensi menyediakan API berbasis coroutine, yang akan kita gunakan di sini. Pertama, seperti yang kita ketahui melalui pengujian, jumlah optimal coroutine untuk lingkungan kita adalah 25:
Kemudian kami menyebarkan 10.000 operasi di lebih dari 25 coroutine dan memeriksa hasilnya:
Jumlah operasi per detik telah meningkat lebih dari 3 kali untuk konektor PHP! Sayangnya, konektor PECL gagal diluncurkan dengan ext-async.
Dan bagaimana dengan SQL?
Seperti yang Anda lihat, dalam mode asinkron, perbedaan antara protokol biner dan SQL termasuk dalam margin of error.
Swoole
Sekali lagi, mari kita tentukan jumlah coroutine yang optimal, kali ini untuk Swoole:
Mari kita ambil 25. Sekarang, ulangi trik yang sama seperti dengan ekstensi Async: mendistribusikan 10.000 operasi antara 25 coroutine. Terlepas dari itu, mari kita tambahkan satu tes lagi, di mana kita membagi semuanya menjadi dua proses (mis. Setiap proses akan melakukan 5.000 operasi di 25 coroutine). Proses akan dibuat dengan bantuan
Swoole \ Process .
Hasil:
Swoole menunjukkan kinerja yang sedikit lebih rendah dibandingkan dengan Async ketika berjalan dalam satu proses, tetapi dengan 2 proses gambar berubah secara drastis (2 tidak dipilih secara tidak sengaja, pada mesin saya jumlah proses yang tepat ini menunjukkan hasil terbaik).
Ngomong-ngomong, ada juga API untuk bekerja dengan proses dalam ekstensi Async, tapi saya tidak melihat perbedaan antara meluncurkan tolok ukur dalam satu proses atau dalam beberapa proses (mungkin meskipun saya telah membuat beberapa kesalahan).
SQL versus protokol biner:
Seperti halnya Async, perbedaan antara operasi biner dan SQL akan diratakan dalam mode asinkron.
Paralel
Karena ekstensi Paralel adalah tentang utas, bukan coroutine, kita harus mengukur jumlah utas paralel yang optimal:
Ini 16 di mesin saya. Sekarang mari kita membandingkan konektor pada 16 utas paralel:
Seperti yang Anda lihat, hasilnya bahkan lebih baik daripada dengan ekstensi asinkron (kecuali Swoole diluncurkan dengan 2 proses). Perhatikan bahwa untuk konektor PECL, operasi Pembaruan dan Upsert tidak memiliki bilah. Ini karena operasi-operasi itu gagal karena kesalahan, dan saya tidak yakin apa yang harus disalahkan: ext-parallel, atau ext-tarantool, atau keduanya.
Sekarang mari kita tambahkan kinerja SQL ke dalam perbandingan:
Pernahkah Anda memperhatikan kesamaan dengan grafik untuk konektor yang diluncurkan secara serempak?
Semua menjadi satu
Akhirnya, mari gabungkan semua hasil dalam satu grafik untuk melihat keseluruhan gambar untuk ekstensi yang diuji. Kami akan menambahkan hanya satu tes baru ke grafik, yang belum kami lakukan: luncurkan Async coroutine secara paralel menggunakan Parallel *. Gagasan untuk mengintegrasikan ekstensi tersebut telah
dibahas oleh penulis tetapi tidak ada konsensus yang tercapai, jadi kita harus melakukannya sendiri.
* Saya gagal meluncurkan coroutine Swoole dengan Paralel; tampaknya ekstensi ini tidak kompatibel.Sekarang, hasil akhirnya:
Kesimpulan
Menurut saya, hasilnya cukup baik, tetapi ada sesuatu yang membuat saya yakin kita belum sampai! Jika Anda memiliki ide tentang cara meningkatkan tolok ukur, saya akan dengan senang hati meninjau permintaan penarikan Anda. Semua kode dengan instruksi dan hasil peluncuran diterbitkan dalam
repositori khusus.
Meninggalkan pada Anda untuk memutuskan apakah Anda akan membutuhkan ini dalam proyek nyata, saya hanya akan mengatakan bahwa itu adalah percobaan yang menarik yang memungkinkan saya untuk memperkirakan berapa banyak yang bisa dihasilkan dari konektor TCP yang sinkron dengan upaya minimal.