deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak dev.to (home feed)

Pingora'nın nginx'e karşı görünen 6 kat kaybı, benchmark'taki bir blocking DNS çağrısına bağlandı

Bir container benchmark'ı, DNS çözümlemesi düzeltilene kadar Pingora'yı nginx'in 126k'sına karşı 21k req/s gösterdi; DNS çözümlemesi önbelleğe alındıktan sonra gerçek fark 1.49 katına indi.

Pingora'nın nginx'e karşı görünen 6 kat kaybı, benchmark'taki bir blocking DNS çağrısına bağlandı

Tutmayan altı katlık bir fark

dev.to'da yayınlanan bir yazıya göre bir geliştirici, Pingora 0.9.0'ı — Cloudflare'in edge tarafında çalıştırdığı Rust proxy kütüphanesini — gerçek bir dağıtıma uygun koşullarda nginx ile karşılaştırmayı amaçladı: iki vCPU'lu, CPU limiti olan küçük bir container pod'u, böylece hiçbir sayı host donanımına yaslanamıyordu.

İlk sonuç felaket görünüyordu. Pingora ile yazılmış minimal bir reverse proxy saniyede yaklaşık 21.000 istek hizmet verirken, nginx aynı kurulumda kabaca 126.000 isteği karşıladı — altı katlık bir fark. Yazarın sezgisi ise bu rakamın doğru olamayacağı yönündeydi: Cloudflare bu kadar yavaş bir teknolojiyle nginx'in yerini değiştirmezdi; dolayısıyla hatanın testte bir yerlerde olması gerekirdi.

Olağan şüphelileri elemektedir

Soruşturma, container benchmark'larını çarpıtan yaygın nedenleri metodik biçimde eledi. CPU throttling sorumlu değildi, çünkü çekirdeğin nr_throttled sayacı sıfırdı. Thread aşırı abone edilmesi dışlandı, çünkü tam olarak iki worker çalışıyordu. Bağlantı davranışı da uyumluydu; her iki proxy de yaklaşık 130 upstream bağlantısını elde tutuyordu.

Gerçek ipucu gecikmeydi. Container içinde istekler ortalama 4,78 ms sürerken, host üzerinde yapılan — backend'in 127.0.0.1 olarak belirtildiği — aynı test 0,45 ms'de tamamlanıyordu. İki koşum arasında farklılık gösteren tek değişken, backend'in nasıl adlandırıldığıydı.

getaddrinfo, her istekte, senkron olarak

Proxy'nin upstream peer seçimi, hedefini her istekte bir hostname ve port'u HttpPeer::new'a geçirerek oluşturuyordu. Bir adres yerine string ve port çifti verildiğinde, bu çağrı adı getaddrinfo ile çözümlüyor — tokio worker thread'i üzerinde yürütülen blocking bir işlem. Container içinde dolayısıyla her istek, Docker'ın gömülü çözümleyicisine bir DNS sorgusu gönderiyor ve yanıt beklerken worker'ı durduruyordu. Host üzerinde ise adres bir IP literal'ydi; çözümleme syscall gerektirmeyen basit bir parse'a dönüşüyordu ve maliyet neredeyse görünmüyordu.

Tek satırlık düzeltme ve dürüst rakamlar

Çare, adı başlangıçta bir kez çözümlemek, elde edilen SocketAddr'ı saklamak ve bu önbelleğe alınmış adresi sonraki her istekte HttpPeer::new'a vermekti. Değişiklikten sonra Pingora'nın aynı pod'daki throughput'u 21.000'den saniyede yaklaşık 89.000 isteğe çıktı. Altı katlık açık, framework'ün değil, istek başına yapılan ad çözümlemesinin eseriydi.

Proxy doğru yazıldığında, iki vCPU'lu ortamdaki kalan fark nginx lehine 1,49 kat oldu ve perf ile yapılan profil çıkarma bunu instruction sayısına bağladı: Pingora istek başına kabaca 1,7 kat daha fazla instruction çalıştırıyordu.

Yazı iki ek yapılandırma bulgusunu daha ortaya koyuyor. Pingora'nın varsayılan thread sayısı bir; açıkça artırılmadıkça tüm bir çekirdek boşta kalabiliyor. Ve CPU limiti olan bir pod'da CPU kotasından fazla thread çalıştırmak, p99'daki tail latency'yi kötüleştiren CFS throttling'e yol açıyor. Yazar, kurulumun tamamını, eşzamanlılık matrisini, perf ve strace profillerini ile thread throttling rakamlarını kendi sitesindeki daha uzun bir yazıda belgelemiş.

Neden önemli

Bu olay Pingora'dan çok benchmark hijyeniyle ilgili. Hot path üzerinde gizlenen blocking bir iş — burada istek başına bir kez yapılan ad çözümlemesi — kendini kusursuz biçimde framework yavaşlığı gibi gösteriyor ve container'lı ortamlar bunu daha da olası kılıyor, çünkü hostname'ler literal olarak parse edilmek yerine container runtime'ının DNS'i üzerinden çözümlenmek zorunda. Bir proxy'yi benchmark eden ya da üretimde çalıştıran herkes, upstream'leri IP adreslerine çözümlemeli ya da aramayı hot path dışında önbelleğe almalı ve thread sayılarını gerçek CPU kotasına göre boyutlandırmalı. Yazarın dediği gibi, bu iki karar, hangi framework'ü seçtiğinizden daha önemli olabilir.

  • #rust
  • #nginx
  • #dns
  • #performance
  • #benchmarking
  • #proxy

İlgili yazılar