Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma

PHP ekosisteminde şu anda Tarantool sunucusuyla çalışmak için iki konektör bulunmaktadır - bu resmi PECL uzantısıdır tarantool/tarantool-php, C ile yazılmış ve tarantool-php/istemci, PHP'de yazılmıştır. Ben ikincisinin yazarıyım.

Bu yazımda her iki kütüphanenin performans testi sonuçlarını paylaşmak ve kodda minimum değişiklik yaparak nasıl 3-5 performans artışı elde edebileceğinizi göstermek istiyorum (sentetik testlerde!).

Neyi test edeceğiz?

Yukarıda bahsedilenleri test edeceğiz senkron Eşzamansız, paralel ve eş zamanlı olmayan paralel çalışan konektörler. 🙂 Ayrıca konnektörlerin kodlarına da dokunmak istemiyoruz. Şu anda istediğinizi elde etmek için birkaç uzantı mevcut:

  • swoole - PHP için yüksek performanslı eşzamansız bir çerçeve. Alibaba ve Baidu gibi internet devleri tarafından kullanılıyor. 4.1.0 sürümünden bu yana sihirli bir yöntem ortaya çıktı SwooleRuntime::enableCoroutine(), "senkron PHP ağ kitaplıklarını tek satır kodla eşzamansız olanlara dönüştürmenize" olanak tanır.
  • Async, yakın zamana kadar PHP'deki asenkron çalışmalar için oldukça umut verici bir eklentiydi. Neden yakın zamana kadar? Maalesef bilmediğim bir nedenden dolayı yazar depoyu sildi ve projenin gelecekteki kaderi belirsiz. onu kullanmam gerekecek biri çatallardan. Swoole gibi, bu uzantı da TCP ve TLS akışlarının standart uygulamasını eşzamansız sürümleriyle değiştirerek eşzamansızlığı etkinleştirmek için bir bilek hareketiyle pantolonunuzu kolayca açmanıza olanak tanır. Bu “seçenek aracılığıyla yapılır”async.tcp = 1".
  • Paralel - phpdbg, apcu, pthreads, pcov, uopz gibi kitaplıkların yazarı, tanınmış Joe Watkins'ten oldukça yeni bir uzantı. Uzantı, PHP'de çoklu iş parçacığı için bir API sağlar ve pthread'lerin yerini alacak şekilde konumlandırılmıştır. Kütüphanenin önemli bir sınırlaması, yalnızca PHP'nin ZTS (Zend Thread Safe) sürümüyle çalışmasıdır.

Nasıl test edeceğiz?

Yazma öncesi günlük kaydı devre dışı bırakılmış bir Tarantool örneği başlatalım (wal_mode = yok) ve artırılmış ağ arabelleği (ileri okuma = 1 * 1024 * 1024). İlk seçenek diskle çalışmayı ortadan kaldıracak, ikincisi ise işletim sistemi arabelleğinden daha fazla istek okumayı mümkün kılacak ve böylece sistem çağrılarının sayısını en aza indirecektir.

Verilerle çalışan kıyaslamalar için (ekleme, silme, okuma vb.), kıyaslamayı başlatmadan önce, birincil dizin değerlerinin sıralı tamsayı değerlerinin bir oluşturucusu tarafından oluşturulduğu bir memtx alanı (yeniden) oluşturulacaktır ​(sıra).
DDL alanı şuna benzer:

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

Gerekirse, karşılaştırmayı çalıştırmadan önce alan formun 10,000 tuple'ı ile doldurulur.

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

Tuple'lara rastgele bir anahtar değeri kullanılarak erişilir.

Karşılaştırmanın kendisi, sunucuya yapılan tek bir istektir; bu, 10,000 kez (devir) gerçekleştirilir ve bu da yinelemeler halinde yürütülür. Yinelemeler, 5 yineleme arasındaki tüm zaman sapmaları %3'lük kabul edilebilir bir hata dahilinde olana kadar tekrarlanır*. Bundan sonra ortalama sonuç alınır. İşlemcinin yavaşlamasını önlemek için yinelemeler arasında 1 saniyelik bir duraklama vardır. Lua'nın çöp toplayıcısı her yinelemeden önce devre dışı bırakılır ve tamamlandıktan sonra başlamaya zorlanır. PHP işlemi yalnızca karşılaştırma için gerekli uzantılarla, çıktı arabelleği etkin ve çöp toplayıcı devre dışı bırakılarak başlatılır.

* Benchmark ayarlarında devir sayısı, yinelemeler ve hata eşiği değiştirilebilir.

Test ortamı

Aşağıda yayınlanan sonuçlar, MacBookPro (2015) işletim sistemi - Fedora 30 (çekirdek sürümü 5.3.8-200.fc30.x86_64) üzerinde yapılmıştır. Tarantool docker'da şu parametreyle başlatıldı:--network host".

Paket sürümleri:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, a872fc2f86'yı derleyin
PHP: 7.3.11 (cli) (yerleşik: 22 Eki 2019 08:11:04)
tarantool/istemci: 0.6.0
rybakit/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ 7.3 için yama)*
harici msgpack: 2.0.3
harici eşzamansız: 0.3.0-8c1da46
harici ses: 4.4.12
harici paralel: 1.1.3

* Ne yazık ki, resmi bağlayıcı PHP sürüm > 7.2 ile çalışmıyor. Uzantıyı PHP 7.3'te derlemek ve çalıştırmak için kullanmak zorunda kaldım yama.

Bulgular

Senkron mod

Tarantool protokolü ikili bir format kullanır Mesaj Paketi mesajları serileştirmek için. PECL bağlayıcısında serileştirme, kitaplığın derinliklerinde gizlidir ve kullanıcı alanı kodundan kodlama sürecini etkiler mümkün değil. Saf PHP bağlayıcısı ise tam tersine, standart kodlayıcıyı genişleterek veya kendi uygulamanızı kullanarak kodlama sürecini özelleştirme yeteneği sağlar. Kutudan çıkan iki kodlayıcı mevcuttur; biri msgpack/msgpack-php (resmi Mesaj Paketi PECL uzantısı), diğeri açık rybakit/msgpack (saf PHP'de).

Bağlayıcıları karşılaştırmadan önce, PHP bağlayıcısı için Mesaj Paketi kodlayıcılarının performansını ölçeceğiz ve sonraki testlerde en iyi sonucu göstereni kullanacağız:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
PHP sürümü (Pure) hız açısından PECL uzantısından daha düşük olmasına rağmen, gerçek projelerde yine de onu kullanmanızı tavsiye ederim rybakit/msgpack, çünkü resmi Mesaj Paketi uzantısında biçim belirtimi yalnızca kısmen uygulanmıştır (örneğin, özel veri türleri için destek yoktur; bu olmadan Tarantool 2.3'te tanıtılan yeni bir veri türü olan Decimal'ı kullanamazsınız) ve diğerlerinin sayısı sorunları (PHP 7.4 ile uyumluluk sorunları dahil). Genel olarak proje terk edilmiş görünüyor.

Şimdi senkron modda konnektörlerin performansını ölçelim:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
Grafikten de görülebileceği gibi PECL konektörü (Tarantool), PHP konektörüne (Client) kıyasla daha iyi performans göstermektedir. Ancak ikincisinin daha yavaş bir dilde uygulanmasının yanı sıra aslında daha fazla iş yaptığı göz önüne alındığında bu şaşırtıcı değil: her çağrıda yeni bir nesne yaratılıyor Talep et и yanıt (Seçim durumunda - ayrıca Kriterlerve Güncelleme/Yükseltme durumunda ― Operasyon), ayrı varlıklar Bağlantısı, Paketleme и Handler aynı zamanda ek yük de eklerler. Açıkçası, esnekliğin bir bedeli var. Bununla birlikte, genel olarak PHP yorumlayıcısı iyi bir performans gösterir, ancak bir fark olmasına rağmen bu önemsizdir ve belki de PHP 7.4'te önyükleme kullanılırken daha da az olacaktır, PHP 8'deki JIT'den bahsetmeye bile gerek yok.

Hadi devam edelim. Tarantool 2.0, SQL desteğini ekledi. SQL protokolünü kullanarak Seç, Ekle, Güncelle ve Sil işlemlerini gerçekleştirmeye çalışalım ve sonuçları noSQL (binary) eşdeğerleriyle karşılaştıralım:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
SQL sonuçları pek etkileyici değil (hala senkronize modu test ettiğimizi hatırlatmama izin verin). Ancak, bu konuda önceden üzülmezdim; SQL desteği hala aktif olarak geliştirilme aşamasındadır (örneğin, nispeten yakın zamanda destek eklenmiştir) hazırlanan ifadeler) ve listeye bakılırsa sorunlarSQL motoru gelecekte bir dizi optimizasyondan geçecek.

zaman uyumsuz

Şimdi Async uzantısının yukarıdaki sonuçları iyileştirmemize nasıl yardımcı olabileceğini görelim. Eşzamansız programlar yazmak için uzantı, kullanacağımız eşyordamlara dayalı bir API sağlar. Deneysel olarak çevremiz için en uygun eşyordam sayısının 25 olduğunu bulduk:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
10,000 işlemi 25 ortak rutine "yayın" ve ne olacağını görün:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
Saniyedeki işlem sayısı 3 kattan fazla arttı tarantool-php/istemci!

Ne yazık ki PECL konektörü ext-async ile başlamadı.

SQL'den ne haber?

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
Gördüğünüz gibi asenkron modda ikili protokol ile SQL arasındaki fark hata payı dahilinde hale geldi.

swoole

Yine bu sefer Swoole için en uygun eşyordam sayısını bulduk:
Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
25'te duralım. Async uzantısıyla aynı numarayı tekrarlayalım; 10,000 işlemi 25 ortakyordam arasında dağıtalım. Ayrıca tüm işi 2 iki sürece böleceğimiz (yani her bir süreç 5,000 koroutinde 25 işlem gerçekleştirecek) bir test daha ekleyeceğiz. Süreçler kullanılarak oluşturulacak Swoole Süreci.

Sonuçlar:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
Swole, tek bir işlemde çalıştırıldığında Async'e kıyasla biraz daha düşük bir sonuç gösteriyor, ancak 2 işlemle resim önemli ölçüde değişiyor (2 sayısı tesadüfen seçilmedi; benim makinemde en iyi sonucu veren 2 işlemdi).

Bu arada, Async uzantısının işlemlerle çalışmak için bir API'si de var, ancak orada bir veya daha fazla işlemde kıyaslama çalıştırmaktan herhangi bir fark görmedim (bir yerde hata yapmış olabilirim).

SQL ve ikili protokol:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
Async'te olduğu gibi, asenkron modda ikili ve SQL işlemleri arasındaki fark ortadan kalkar.

Paralel

Paralel uzantı eşyordamlarla değil iş parçacıklarıyla ilgili olduğundan, paralel iş parçacıklarının optimal sayısını ölçelim:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
Benim makinemde 16'ya eşit. 16 paralel iş parçacığı üzerinde bağlayıcı kıyaslamaları çalıştıralım:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
Gördüğünüz gibi sonuç, eşzamansız uzantılardan bile daha iyidir (2 işlemde çalışan Swoole'u saymazsak). PECL bağlayıcısı için Güncelleme ve Yükseltme işlemlerinin boş olduğunu unutmayın. Bunun nedeni, bu işlemlerin bir hatayla başarısız olmasıdır - bunun ext-parallel, ext-tarantool veya her ikisinin hatası olup olmadığını bilmiyorum.

Şimdi SQL performansını karşılaştıralım:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma
Eş zamanlı çalışan bağlayıcılara ilişkin grafikle benzerliğe dikkat ettiniz mi?

Birlikte

Son olarak, test edilen uzantıların genel resmini görmek için tüm sonuçları tek bir grafikte özetleyelim. Grafiğe henüz yapmadığımız yeni bir test ekleyelim - Paralel* kullanarak Async eşyordamlarını paralel olarak çalıştıralım. Yukarıdaki uzantıları entegre etme fikri zaten tartışılan yazarlar, ancak fikir birliğine varılamadı, bunu kendiniz yapmanız gerekecek.

* Swoole eşyordamlarını Parallel ile başlatmak mümkün olmadı; bu uzantıların uyumsuz olduğu görülüyor.

Yani, nihai sonuçlar:

Async, Swoole ve Paralel kullanarak Tarantool için PHP bağlayıcılarını hızlandırma

Bunun yerine bir sonuca

Bana göre sonuçlar oldukça değerli çıktı ve bazı nedenlerden dolayı bunun sınır olmadığından eminim! Buna gerçek bir projede yalnızca kendiniz için karar vermeniz gerekip gerekmediği, benim için bunun senkronize bir TCP konektöründen minimum çabayla ne kadar "sıkabileceğinizi" değerlendirmenize olanak tanıyan ilginç bir deney olduğunu söyleyeceğim. Karşılaştırma ölçütlerini iyileştirmeye yönelik fikirleriniz varsa, çekme isteğinizi değerlendirmekten memnuniyet duyarım. Başlatma talimatlarını ve sonuçlarını içeren tüm kodlar ayrı bir kitapta yayınlanır depolar.

Kaynak: habr.com

Yorum ekle