Dropbox’ın Nginx’ten Envoy’a neden ve nasıl geçtiği
(dropbox.tech)<p>On milyonlarca eşzamanlı bağlantı, saniyede milyonlarca istek ve terabayt düzeyinde bant genişliği kullanan Dropbox’ın, Nginx’e kıyasla Envoy’un avantajlarını çok iyi anlattığı bir yazı<br />
<br />
Önceki yapı: nginx (açık kaynak sürüm) + python2 + Jinja2 + YAML <br />
→ Tek bir şey değişse bile tüm sistemin yeniden dağıtılması gerekiyordu<br />
→ Dinamik bölümler Lua ile geliştiriliyordu<br />
→ Karmaşık mantık ise Go tabanlı proxy Bandaid içinde işleniyordu<br />
<br />
Yaklaşık 10 yıl boyunca iyi çalıştı, ancak mevcut ortama artık pek uygun değil<br />
→ İç ve dış (özel) API’ler giderek REST’ten gRPC’ye geçiyor, bu yüzden proxy’nin transcoding özelliğine ihtiyaç duyuluyor<br />
→ Protocol Buffers, iç servis tanımlarının standartı haline geldi <br />
→ Tüm yazılımlar, dil fark etmeksizin Bazel ile derlenip test ediliyor<br />
→ Çalışanlar, başlıca altyapı projelerinin açık kaynak topluluklarına oldukça yoğun katkı veriyor<br />
<br />
Nginx, operasyon açısından da sürdürmesi pahalı bir yapı<br />
→ Config üretim mantığı fazla esnek ve YAML, Jinja2, Python arasında dağılmış durumda<br />
→ İzleme, Lua / log ayrıştırma / sistem tabanlı izleme karışımından oluşuyor<br />
→ Üçüncü taraf modüllere bağımlılık arttıkça kararlılık/performans etkileniyor ve sık yükseltmeler ek maliyet çıkarıyor <br />
→ nginx’in kendi dağıtım ve süreç yönetimi diğer servislerden oldukça farklı. syslog, logrotate gibi temel sistemlerden çok farklı şeylere yoğun biçimde bağımlı<br />
<br />
Bu yüzden, 10 yıl sonra ilk kez Nginx’in yerini alacak bir şey aramaya karar verdiler<br />
<br />
* Neden Bandaid’e (Dropbox’ın kendi geliştirdiği Go tabanlı proxy) geçmediler? <br />
→ Go, C/C++’a göre daha fazla kaynak tüketiyor. <br />
→ Go’nun TLS yığını FIPS desteği sunmuyor (ABD Federal Information Processing Standards)<br />
→ İç araç olduğu için dış topluluktan destek almak mümkün değil <br />
<br />
Bugünkü yapı: Envoy tabanlı trafik altyapısına geçiş <br />
<br />
----- Envoy’un Nginx’ten daha iyi olduğu noktalar ------<br />
<br />
* Performans *<br />
<br />
Nginx’in mimarisi event-driven / multi-process. SO_REUSEPORT & EPOLLEXCLUSIVE desteği var<br />
Event loop tabanlı olsa da tamamen non-blocking değil. Dosya açma/loglama sırasında event loop durabiliyor. (`aio`, `aio_write` ve Threadpool etkin olsa bile)<br />
Bu da tail latency’ye yol açıyor ve bazen saniyeler düzeyinde gecikme oluşabiliyor<br />
<br />
Envoy da benzer şekilde event-driven bir mimari kullanıyor, ancak process değil thread tabanlı <br />
SO_REUSEPORT desteği var (BPF filtre desteğiyle birlikte), ayrıca libevent üzerinden event loop sağlıyor <br />
Event loop içinde blocking I/O yok. Event logging de non-blocking şekilde uygulanmış.<br />
<br />
Teorik olarak benzer performans özellikleri göstermeleri bekleniyordu ve çoğu iş yükü testinde gerçekten de benzerdi.<br />
Ancak Nginx’in long tail tarafında gecikme süresi daha yüksekti. Bunun nedeni yoğun I/O sırasında event loop’un durmasıydı.<br />
<br />
İstatistik toplama devre dışıyken Nginx, Envoy ile benzer performans gösteriyor; ancak içeride kullanılan Lua tabanlı istatistik toplama aracı, yüksek RPS testlerinde Nginx’i 3 kat yavaşlatıyordu. (Bunun nedeni mutex ile senkronize edilen `lua_shared_dict`.) Dropbox’ın istatistik toplama yönteminde sorunlar olduğu doğru, ancak bunu verimli biçimde yeniden geliştirmekten vazgeçtiler. (Çünkü Nginx içine instrumentation eklemenin ileride yükseltmeleri zorlaştıracağını düşündüler.)<br />
<br />
Sonuç olarak bu sorunlar Envoy’da olmadığı için, geçişten sonra eski Nginx’in kullandığı sunucuların en fazla %60’ını serbest bırakabildiler.<br />
<br />
* Gözlemlenebilirlik *<br />
<br />
Ücretsiz Nginx sürümü, stub status modülü üzerinden yalnızca 7 istatistik sağlıyor <br />
Bu doğal olarak yetersiz kaldığı için `log_by_lua` handler ekleyerek daha fazla istatistik sağlıyorlardı.<br />
Ayrıca error.log ayrıştırıcısı üzerinden hata bilgisi dışa aktarılıyor ve nginx iç durum değerlerini dışa vermek için ayrı bir exporter da bulunuyordu.<br />
<br />
Temel bir Envoy kurulumu, Prometheus formatında binlerce farklı metrik sağlıyor <br />
Proxy trafik bilgilerinden sunucunun iç durum bilgilerine kadar,<br />
cluster/upstream/virtual host bazında istatistikler ve listener bazında TCP/HTTP/TLS downstream istatistikleri gibi pek çok veri mevcut<br />
<br />
Bu çeşitli istatistiklerin yanında Envoy, Tracing Provider’ın eklenti olarak kullanılmasına da izin veriyor.<br />
Bu, yalnızca trafik ekibi için değil uygulama geliştiricileri için de faydalı.<br />
<br />
Son olarak Envoy, gRPC üzerinden access log’ları stream edebiliyor.<br />
Bu sayede trafik ekibinin syslog-to-hive köprüsünü destekleme yükü azalıyor.<br />
Özel TCP/UDP listener eklemek yerine genel amaçlı bir gRPC servisi çalıştırmak çok daha kolay ve güvenli.<br />
<br />
* Entegrasyon *<br />
<br />
Nginx’in entegrasyonu çok Unix tarzı. Configuration oldukça statik.<br />
Config dosyalarına, TLS sertifikalarına, allowlist/blocklist gibi şeyler için dosyalara bağımlı.<br />
Basit ve geriye dönük uyumlu olduğu için birkaç shell script ile otomasyon mümkün,<br />
ancak sistem büyüdükçe test edilebilirlik ve standardizasyon giderek daha önemli hale geliyor.<br />
<br />
Envoy’un bu entegrasyon için kendine özgü bir yaklaşımı var.<br />
xDS adı verilen API’ler sunuyor ve protobuf ile gRPC kullanımını teşvik ediyor.<br />
Envoy, bu xDS’lere sorgu göndererek dinamik kaynakları buluyor.<br />
<br />
- Bu xDS artık Envoy’un ötesine geçerek Universal Data Place API (UDPA) adıyla L4/L7 load balancer’lar için fiilî standart olmaya doğru evriliyor; bizim deneyimimize göre de bu iyi ilerliyor. Envoy dışındaki Katran eBPF/XDP L4 load balancer’da da UDPA kullanmayı planlıyorlar.<br />
<br />
Dropbox içeride servisleri zaten gRPC üzerinden birbirine bağladığı için bu yaklaşım onlar için çok daha uygun.<br />
<br />
* Yapılandırma *<br />
<br />
Nginx’in büyük avantajlarından biri, insanlar tarafından okunması kolay olan yapılandırma dosyalarıydı. <br />
Ancak yapılandırma giderek karmaşıklaşıp otomatik üretildikçe bu avantaj ortadan kalktı.<br />
Dropbox’ta yapılandırma Python2, Jinja2, YAML vb. ile üretildiği için veri modeli de iç içe geçmiş ve karmaşık hale gelmişti.<br />
<br />
Envoy, yapılandırma için birleşik bir veri modeline sahip. Tüm ayarlar Protocol Buffer içinde tanımlanıyor. Bu, veri modelleme sorunlarını çözüyor ve ayarlara tip bilgisi ekliyor.<br />
Dropbox içinde protobuf yaygın olarak kullanıldığı için entegrasyonu da kolaylaştırıyor <br />
<br />
* Genişletilebilirlik * <br />
<br />
Nginx’i genişletmek için C modülleri yazmak gerekiyor. Güvenli modül geliştirmek için kıdemli geliştiricilere ihtiyaç var. Daha hafif modül geliştirme için Perl / JS arayüzleri sunsa da bunlar çok sınırlı. Bu yüzden en yaygın yöntem `lua-nginx-module` kullanmak. <br />
<br />
Envoy’un ana genişleme mekanizması C++ eklentileri; belgeleri nginx kadar iyi olmasa da kullanımı oldukça basit. Bunda temiz, iyi yorumlanmış arayüzlerin yanı sıra C++14 dili ve standart kütüphane de etkili <br />
<br />
Envoy’u diğer web sunucularından ayıran en büyük farklardan biri WebAssembly (WASM) desteği.<br />
Bu sayede Rust gibi farklı dillerle uzantı geliştirmeyi destekleyebiliyor. <br />
Dropbox henüz WASM kullanmıyor, ancak bir gün proxy-wasm için Go SDK desteği gelirse bu değişebilir<br />
<br />
* Derleme ve test *<br />
<br />
Nginx temel olarak özel shell tabanlı yapılandırma ve `make` tabanlı derleme kullanıyor. Basit ve iyi bir yaklaşım olsa da bunu Bazel ile derlenen bir monorepo’ya entegre etmek ciddi çaba gerektiriyor <br />
Nginx’te Perl tabanlı integration test’ler var ama unit test yok.<br />
<br />
Envoy’un derleme sistemi zaten Bazel tabanlı ve bunu monorepo’larına kolayca entegre etmişler.<br />
Ayrıca gtest/gmock tabanlı unit test’leri ve bir integration test framework’ü sağlıyor<br />
<br />
* Güvenlik *<br />
<br />
Nginx kod tabanı oldukça küçük ve dış bağımlılıkları da az olduğu için güvenlik açığı sayısı çok değil.<br />
<br />
Envoy’un kod tabanı daha büyük olduğundan doğal olarak saldırı yüzeyi daha geniş görünüyor. Bunun için Envoy, modern güvenlik pratiklerine yoğun biçimde dayanıyor. AddressSanitizer, ThreadSanitizer, MemorySanitizer vb. araçlar kullanılıyor. <br />
<br />
* Özellikler * <br />
<br />
Bu bölümde öznel görüşler daha fazla, bu yüzden buna göre değerlendirmek gerekir<br />
<br />
Nginx başlangıçta çok az kaynakla statik dosya sunan bir web sunucusu olarak ortaya çıktı. <br />
Yani temel işlevleri static serving, caching ve range caching<br />
Proxy açısından bakıldığında Nginx, günümüz altyapısının gerektirdiği pek çok özelliği barındırmıyor. <br />
Backend’e HTTP/2 bağlantısı kuramıyor, çoklu bağlantılı gRPC proxy desteği yok, gRPC transcoding de yapamıyor.<br />
Open-core lisans modeli nedeniyle bazı önemli özellikler “community version” içinde yer almıyor<br />
<br />
Envoy ise en baştan ingress/egress proxy olarak tasarlandı ve gRPC yükünün yoğun olduğu ortamlarda yaygın kullanılıyor.<br />
Web sunucusu özellikleri ise oldukça temel seviyede. Dosya sunamıyor, caching hâlâ geliştiriliyor, brotli desteği de yok vb. <br />
Bu tür ortamlar için Envoy’u upstream cluster olarak kullanan bir Nginx kurulumu da işletiliyor <br />
Envoy HTTP cache desteği kazandığında bu tür statik sunum ortamlarının da taşınabileceği öngörülüyor <br />
<br />
Envoy, gRPC ile ilgili pek çok özelliği destekliyor<br />
- gRPC proxying<br />
- Backend’lere HTTP/2<br />
- gRPC → HTTP bridge (+ reverse.) <br />
- gRPC-WEB <br />
- gRPC JSON transcoder<br />
<br />
Ayrıca Envoy, outbound proxy olarak da kullanılabiliyor <br />
- Egress Proxy<br />
- Courier gRPC kütüphanesi ile üçüncü taraf yazılımlar için service discovery <br />
<br />
* Topluluk *<br />
<br />
Nginx geliştirme süreci merkezî ve büyük ölçüde kapalı. <br />
Envoy geliştirmesi ise açık ve dağıtık. GitHub issue/PR üzerinden ilerliyor; mailing list/Slack gibi kanallarda da oldukça aktif </p><p>----- Dropbox’ın mevcut migration durumu -----<br />
<br />
Nginx ve Envoy’u son altı aydır birlikte çalıştırıyorlar ve DNS üzerinden trafiği kademeli olarak taşıyorlar <br />
Geçiş tamamen sorunsuz olmadı; küçük problemler yaşandı ama ciddi bir kesinti olmadı.<br />
"unusual" ya da "non-RFC" davranışlar nedeniyle karşılaştıkları sorunlara yönelik çözümleri de derlemişler (ayrıntılar için asıl metne bakılabilir)<br />
<br />
** Sıradaki işler **<br />
<br />
- HTTP/3 : Envoy da deneysel destek sunmaya başladı. UDP hızlandırması için Linux kernel yükseltildiğinde denemeyi planlıyorlar<br />
- İç xDS tabanlı load balancer ve Outlier Detection<br />
- WASM tabanlı Envoy genişletmeleri <br />
- Bandaid’i (Go tabanlı proxy) Envoy ile değiştirmek <br />
- Envoy Mobile ile mobil uygulamalarda da Envoy kullanmak</p>
3 yorum