Sans-IO: Rust'ın ağ hizmetleri için etkili sırrı
(firezone.dev)- Firezone, Rust kullanarak Android telefonlar, macOS bilgisayarlar veya Linux sunucularında ölçeklenebilir ve güvenli uzaktan erişim geliştiriyor
- Ağ bağlantılarını ve WireGuard tünellerini yönetmek için
connlibadlı bir bağlantı kütüphanesi kullanıyor - Birçok yinelemenin ardından, hızlı ve kapsamlı testler, derin özelleştirme ve yüksek güvenilirlik sunan sans-IO adlı tasarıma ulaştı
connlib, Rust ile yazılmıştır ve sans-IO tasarımını izler
- Rust'ın hızı ve bellek güvenliği sayesinde ağ hizmetleri geliştirmek için uygundur
tokioruntime'ı,tungsteniteWebSockets,boringtunWireGuard implementasyonu,rustlsile API trafiği şifreleme gibi bileşenler kullanılır- sans-IO tasarımı, çeşitli yerlerde soketler üzerinden bayt gönderip almak yerine protokolü saf bir durum makinesi olarak uygular
Rust'ın asenkron modeli ve "function coloring" tartışması
- Asenkron fonksiyonlar yalnızca diğer asenkron fonksiyonlardan çağrılabilir
- Asenkron bir fonksiyonun derinliklerindeki bir fonksiyon, onu çağıran tüm fonksiyonların da asenkron hale gelmesini gerektirir
- Bu durum, bağımlılıkların asenkron olup olmamasından bağımsız kod yazmak isteyenler için sorun yaratabilir
sans-IO'ya giriş
- sans-IO'nun temel fikri, OOP dünyasındaki dependency inversion principle'a benzer
- Politika (ne yapılacağı), implementasyon ayrıntılarına (nasıl yapılacağı) bağımlı olmamalıdır
- Veriyi
Transmityapısını kullanarak göndermek yerine,Transmitüretir
Dependency inversion uygulaması
- Veriyi
Transmityapısını kullanarak göndermek yerine,Transmitüretir - Event loop yan etkileri uygular ve gerçekten
UdpSocket::sendçağrısını yapar
Durum makinesi
- STUN binding request durum makinesi diyagramı iki duruma sahiptir:
SentveReceived - Durum makinesini uygulamak için
StunBindingyapısı ve ilgili fonksiyonlar tanımlanır
Event loop
- Event loop, durum makinesini çalıştırır ve veriyi işlemek için
poll_transmitilehandle_inputkullanır
Zaman soyutlaması
- Zaman tabanlı gereksinimleri işlemek için
poll_timeoutvehandle_timeoutAPI'leri kullanılır
sans-IO'nun öncülü
- sans-IO tasarımı, bağımlılıkların asenkron olup olmamasına dair kararı uygulamaya bırakır
- sans-IO tasarımı kolay bileşir, esnek API'ler sunar, test etmeyi kolaylaştırır ve Rust'ın özellikleriyle iyi uyum sağlar
Kolay bileşim
StunBindingAPI'si çoğu ağ protokolüne uygulanabilir- Firezone'un
snownetkütüphanesi, ICE ile WireGuard'ı birleştirerek ağ yapılandırmasından bağımsız çalışan "sihirli" bir IP tüneli sunar
Esnek API
- Event loop'u doğrudan yazmak, kodu ayarlamayı mümkün kılar ve bakımı kolaylaştırır
Hızlı testler
- sans-IO kodu yan etki içermediği için test edilmesi son derece kolaydır
- Firezone, bir referans durum makinesi uygulayıp bunu
connlib'in gerçek durumu ile karşılaştıran testler yürütür
Edge case'ler ve IO hataları
- sans-IO tasarımı, protokol implementasyonunu gerçek IO yan etkilerinden ayırarak edge case'leri ve hata işlemeyi kolaylaştırır
Rust + sans-IO: Mükemmel eşleşme mi?
- Rust, sahiplik ve değiştirilebilirliği açıkça modellediği için sans-IO tasarımıyla iyi uyum sağlar
- sans-IO tasarımı, durum değişikliklerini ifade etmek için
&mut'u serbestçe kullanır veasyncRust'tan farklı olarak yalnızca senkron API'ler kullanır
Dezavantajlar
- Event loop'u doğrudan yazmak ince hatalara yol açabilir
- Sıralı iş akışları daha fazla kod gerektirebilir
- Rust topluluğunda sans-IO tasarımı hâlâ yaygın olarak kullanılmıyor
Sonuç
- sans-IO kodu ilk başta alışılmadık gelebilir, ancak alışınca oldukça keyiflidir
- Rust, durum makinelerini modellemek için mükemmel araçlar sunar
- sans-IO tasarımı, hata işlemeyi girdi işlemenin bir parçası olmaya zorlayarak ağ kodu yazmanın doğru yolu gibi hissettirir
GN⁺ görüşü
- sans-IO tasarımı, Rust'ın sahiplik modeliyle iyi uyuştuğu için ağ protokolü implementasyonları için çok uygundur
- Event loop'u doğrudan yazmak, kodun esnekliğini artırır ve bakımını kolaylaştırır
- Testlerin kolay olması, güvenilir kod yazmada büyük avantaj sağlar
- Ancak Rust topluluğunda yaygın olmadığı için ilgili kütüphaneler yetersiz olabilir
- Yeni bir teknoloji benimsenirken öğrenme eğrisi ve topluluk desteği de dikkate alınmalıdır
1 yorum
Hacker News görüşleri
Rust'a
async/awaitsözdizimi gelmeden önce durum makineleri elle uygulanıyorduasync/awaitsözdizimi sayesinde üretkenlik büyük ölçüde arttıVT100 kütüphanesi yazarken Rust'ın kapsülleme deseni sorununu fark etmiş
Veriyi aktarmak için channel kullanılan tasarımla karşılaştırma
Haskell ekosisteminde mantık ile yürütmeyi ayırma fikri var
tokio::select!çağrısını nasıl kapsüllediklerinden bahsedilmiyorRust'ın async fonksiyonları durum makinelerine derlenir
PinyönetimiDurum açığa çıkarılırsa async fonksiyonlar "saf" hale gelebilir
Firezone etkileyici bir araç
Derleyicinin async kodu otomatik olarak sans-IO'ya dönüştürebilmesi güzel olurdu
Makale ve yorumları okuyunca, sanki hexagonal ya da ports/adapters mimari tarzını yeniden icat etmişler gibi görünüyor
Gerçek trafiğin gateway üzerinden mi geçtiğini, yoksa bunun yalnızca bağlantı kurulumunda mı kullanıldığını merak ediyor