
Pengujian dilakukan menggunakan Yandex Tank.
Symfony 4 dan PHP 7.2 digunakan sebagai aplikasi.
Tujuannya adalah untuk membandingkan karakteristik layanan pada beban yang berbeda dan menemukan opsi terbaik.
Untuk kenyamanan, semuanya dikumpulkan dalam wadah buruh pelabuhan dan diangkat menggunakan komposisi buruh pelabuhan.
Di bawah kucing ada banyak tabel dan grafik.
Kode sumber ada di sini .
Semua contoh perintah yang dijelaskan dalam artikel harus dijalankan dari direktori proyek.
Aplikasi
Aplikasi ini berjalan pada Symfony 4 dan PHP 7.2.
Jawaban hanya satu rute dan kembali:
- nomor acak;
- lingkungan
- pid dari proses;
- nama layanan yang digunakannya;
- variabel php.ini.
Contoh jawaban:
curl 'http://127.0.0.1:8000/' | python -m json.tool { "env": "prod", "type": "php-fpm", "pid": 8, "random_num": 37264, "php": { "version": "7.2.12", "date.timezone": "Europe/Paris", "display_errors": "", "error_log": "/proc/self/fd/2", "error_reporting": "32767", "log_errors": "1", "memory_limit": "256M", "opcache.enable": "1", "opcache.max_accelerated_files": "20000", "opcache.memory_consumption": "256", "opcache.validate_timestamps": "0", "realpath_cache_size": "4096K", "realpath_cache_ttl": "600", "short_open_tag": "" } }
PHP dikonfigurasi di setiap wadah:
- OPcache diaktifkan;
- cache bootstrap yang dikonfigurasi menggunakan komposer;
- Pengaturan php.ini sejalan dengan praktik terbaik Symfony .
Log ditulis dalam stderr:
/config/packages/prod/monolog.yaml
monolog: handlers: main: type: stream path: "php://stderr" level: error console: type: console
Tembolok ditulis dalam / dev / shm:
/src/Kernel.php
... class Kernel extends BaseKernel { public function getCacheDir() { if ($this->environment === 'prod') { return '/dev/shm/symfony-app/cache/' . $this->environment; } else { return $this->getProjectDir() . '/var/cache/' . $this->environment; } } } ...
Setiap komposisi buruh pelabuhan meluncurkan tiga kontainer utama:
- Nginx - membalikkan server proxy;
- Kode aplikasi aplikasi yang disiapkan dengan semua dependensi;
- PHP FPM \ Nginx Unit \ Road Runner \ React PHP - server aplikasi.
Pemrosesan permintaan terbatas pada dua instance aplikasi (berdasarkan jumlah inti prosesor).
Layanan
Manajer proses PHP. Ditulis dalam C.
Pro:
- tidak perlu melacak memori;
- tidak perlu mengubah apa pun dalam aplikasi.
Cons:
- PHP harus menginisialisasi variabel untuk setiap permintaan.
Perintah untuk meluncurkan aplikasi dengan komposisi buruh pelabuhan:
cd docker/php-fpm && docker-compose up -d
Manajer proses PHP. Itu ditulis dalam PHP.
Pro:
- menginisialisasi variabel sekali dan kemudian menggunakannya;
- tidak perlu mengubah apa pun dalam aplikasi (ada modul yang siap pakai untuk Symfony / Laravel, Zend, CakePHP).
Cons:
Perintah untuk meluncurkan aplikasi dengan komposisi buruh pelabuhan:
cd docker/php-ppm && docker-compose up -d
Server Aplikasi dari Tim Nginx. Ditulis dalam C.
Pro:
- Anda dapat mengubah konfigurasi menggunakan API HTTP;
- Anda dapat menjalankan banyak instance dari satu aplikasi secara bersamaan dengan berbagai konfigurasi dan versi bahasa;
- tidak perlu melacak memori;
- tidak perlu mengubah apa pun dalam aplikasi.
Cons:
- PHP harus menginisialisasi variabel untuk setiap permintaan.
Untuk meneruskan variabel lingkungan dari file konfigurasi unit nginx, Anda perlu memperbaiki php.ini:
; Nginx Unit variables_order=E
Perintah untuk meluncurkan aplikasi dengan komposisi buruh pelabuhan:
cd docker/nginx-unit && docker-compose up -d
Perpustakaan untuk pemrograman acara. Itu ditulis dalam PHP.
Pro:
- menggunakan perpustakaan, Anda dapat menulis server yang akan menginisialisasi variabel hanya sekali dan terus bekerja dengan mereka.
Cons:
- Anda harus menulis kode untuk server;
- perlu melacak memori.
Jika Anda menggunakan flag --reboot-kernel-after-request untuk pekerja, maka Symfony Kernel akan diinisialisasi ulang untuk setiap permintaan. Dengan pendekatan ini, Anda tidak perlu memonitor memori.
Perintah untuk meluncurkan aplikasi dengan komposisi buruh pelabuhan:
cd docker/react-php && docker-compose up -d --scale php=2
Server web dan pengelola proses PHP. Ditulis dalam Golang.
Pro:
- Anda dapat menulis pekerja yang akan menginisialisasi variabel hanya sekali dan terus bekerja dengan mereka.
Cons:
- Anda harus menulis kode untuk pekerja;
- perlu melacak memori.
Jika Anda menggunakan flag --reboot-kernel-after-request untuk pekerja, maka Symfony Kernel akan diinisialisasi ulang untuk setiap permintaan. Dengan pendekatan ini, Anda tidak perlu memonitor memori.
Perintah untuk meluncurkan aplikasi dengan komposisi buruh pelabuhan:
cd docker/road-runner && docker-compose up -d
Pengujian
Pengujian dilakukan menggunakan Yandex Tank.
Aplikasi dan Yandex Tank berada di server virtual yang berbeda.
Fitur server virtual dengan aplikasi:
Virtualisasi : KVM
CPU : 2 core
RAM : 4096 MB
SSD : 50 GB
Koneksi : 100MBit
OS : CentOS 7 (64x)
Layanan yang Diuji:
- php-fpm
- php-ppm
- nginx-unit
- pelari jalan
- road-runner-reboot (dengan flag --reboot-kernel-after-request )
- reaksi-php
- react-php-reboot (dengan flag --reboot-kernel-after-request )
Untuk pengujian 1000/10000 rps ditambahkan layanan php-fpm-80
Konfigurasi php-fpm digunakan untuk itu:
pm = dynamic pm.max_children = 80
Yandex Tank menentukan terlebih dahulu berapa kali perlu menembak target, dan tidak berhenti sampai kartrid habis. Tergantung pada kecepatan respons layanan, waktu pengujian mungkin lebih lama daripada yang ditentukan dalam konfigurasi pengujian. Karena itu, gambar dari berbagai layanan mungkin memiliki panjang yang berbeda. Semakin lambat layanan merespons, semakin lama jadwalnya.
Untuk setiap layanan dan konfigurasi Yandex Tank, hanya satu tes yang dilakukan. Karena itu, angka mungkin tidak akurat. Penting untuk mengevaluasi karakteristik layanan relatif satu sama lain.
100 rps
Konfigurasi Tank Phantom Yandex
phantom: load_profile: load_type: rps schedule: line(1, 100, 60s) const(100, 540s)
Tautan Laporan Detail
Persentil waktu respons
Pemantauan
Grafik

Bagan 1.1 Rata-rata waktu respons per detik

Bagan 1.2 Rata-rata beban prosesor per detik

Bagan 1.3 Konsumsi memori rata-rata per detik
500 rps
Konfigurasi Tank Phantom Yandex
phantom: load_profile: load_type: rps schedule: line(1, 500, 60s) const(500, 540s)
Tautan Laporan Detail
Persentil waktu respons
Pemantauan
Grafik

Bagan 2.1 Rata-rata waktu respons per detik

Bagan 2.2 Rata-rata beban prosesor per detik

Bagan 2.3 Konsumsi memori rata-rata per detik
1000 rps
Konfigurasi Tank Phantom Yandex
phantom: load_profile: load_type: rps schedule: line(1, 1000, 60s) const(1000, 60s)
Tautan Laporan Detail
Persentil waktu respons
Pemantauan
Grafik

Bagan 3.1 Rata-rata waktu respons per detik

Bagan 3.2 Rata-rata waktu respons per detik (tanpa php-fpm, php-ppm, road-runner-reboot)

Bagan 3.3 Rata-rata beban prosesor per detik

Grafik 3.4 Konsumsi memori rata-rata per detik
10.000 rps
Konfigurasi Tank Phantom Yandex
phantom: load_profile: load_type: rps schedule: line(1, 10000, 30s) const(10000, 30s)
Tautan Laporan Detail
Persentil waktu respons
Pemantauan

Bagan 4.1 Rata-rata Waktu Respons per Detik

Bagan 4.2 Rata-rata waktu respons per detik (tanpa php-fpm, php-ppm)

Bagan 4.3 Rata-rata beban prosesor per detik

Bagan 4.4 Konsumsi memori rata-rata per detik
Ringkasan
Berikut adalah grafik yang menunjukkan perubahan dalam karakteristik layanan tergantung pada beban. Saat melihat grafik, perlu dipertimbangkan bahwa tidak semua layanan menjawab 100% dari permintaan.

Bagan 5.1 95% persentil dari waktu respons

Bagan 5.2 persen persentil dari waktu respons (tanpa php-fpm)

Grafik 5.3 Beban CPU Maksimum

Bagan 5.4 Konsumsi memori maksimum
Solusi optimal (tanpa mengubah kode), menurut saya, adalah manajer proses Unit Nginx. Ini menunjukkan hasil yang baik dalam kecepatan respons dan mendapat dukungan dari perusahaan.
Dalam kasus apa pun, pendekatan pengembangan dan alat-alat perlu dipilih secara terpisah, tergantung pada beban kerja Anda, sumber daya server dan kemampuan pengembang.
UPD
Untuk pengujian 1000/10000 rps ditambahkan layanan php-fpm-80
Konfigurasi php-fpm digunakan untuk itu:
pm = dynamic pm.max_children = 80