Linux çekirdeği için QUIC
(lwn.net)- QUIC protokolünün Linux çekirdeğine resmen entegre edilmesine yönelik ilk yama gönderildi
- Amaç, mevcut TCP'nin sahip olduğu sınırlamaları (gecikme, head-of-line blocking, ara cihazların neden olduğu protokol katılaşması vb.) iyileştirmek
- QUIC, UDP tabanlı olarak çoklu akış desteği ve uçtan uca şifreleme sunuyor; çekirdeğe alınması halinde daha geniş platform ve donanım kullanımının önü açılabilir
- İlk çekirdek içi uygulamanın performansı mevcut TCP ve çekirdek TLS'e kıyasla daha düşük ölçüldü, ancak gelecekte donanım offloading ve optimizasyonlarla performansın artması bekleniyor
- Şu anda Samba, çekirdek tabanlı SMB/NFS, curl gibi projelerde destek tartışmaları aktif biçimde sürüyor, ancak ana dala birleşmesi zaman alacak gibi görünüyor
QUIC protokolünün ortaya çıkış arka planı ve TCP'nin sınırlamaları
- QUIC, mevcut internette TCP'nin taşıdığı çeşitli sorunları çözmek amacıyla geliştirildi
- TCP bağlantı sürecindeki 3-way handshake kaynaklı gecikme, yetersiz çoklu akış desteği ve paket kaybına bağlı head-of-line blocking gibi sorunlar web kullanım deneyimini düşürüyor
- TCP meta verileri şifrelenmeden iletildiği için bilgi sızıntısı riski bulunuyor; ayrıca internetteki middlebox'lar bağlantı bilgisine dayanarak trafiği filtreliyor ve bu da protokol katılaşmasına (ossification) yol açıyor
- TCP'yi iyileştirme girişimleri de (ör. Multipath TCP) mevcut TCP gibi davranmadan düzgün çalışamıyor
QUIC'in özellikleri ve teknik avantajları
- QUIC, UDP üzerinde çalışır ve bağlantı kurulurken ayrı bir 3-way handshake olmadan hızlı bağlantı kurulumu sağlayabilir
- Paket kaybının tüm akışı etkilememesi için çoklu akış aktarım tasarımı benimsenmiştir
- QUIC ile ilgili aktarım verileri her zaman uçtan uca şifrelenir (TLS tabanlı), böylece ara cihazlar iç mesajlara erişemez
- UDP paketlerinin geçebildiği bir ağ ortamında QUIC de normal şekilde çalışabilir
Linux çekirdeğinde QUIC entegrasyon yamasının özeti
- Sunulan yamada IPPROTO_QUIC adlı yeni bir protokol türü tanıtılıyor ve mevcut socket() sistem çağrısı kullanılabiliyor
- TCP'ye benzer şekilde bind(), connect(), listen(), accept() gibi çağrılar kullanılabiliyor, ancak sonrasındaki işleme biçiminde farklılıklar var
- TLS oturum yönetimi ile kimlik doğrulama/şifreleme süreci kullanıcı alanında işleniyor; bağlantıdan sonra her iki uçta da TLS handshake tamamlanmadan veri gönderimi ve alımı yapılamıyor
- İlk bağlantının ardından TLS müzakere sonuçları önbelleğe alınarak, iki sistem yeniden bağlandığında hız önemli ölçüde artırılabiliyor
Performans açısından zorluklar ve beklentiler
- Gönderilen çekirdek içi QUIC uygulaması, performans açısından mevcut çekirdek TLS ve TCP karşısında henüz geride kalıyor
- Çekirdek içi TLS'e kıyasla verim 3 kat daha düşük; şifreleme devre dışı bırakıldığında bile TCP'ye göre verim en fazla 4 kat daha düşük
- Bunun nedenleri arasında segmentation offloading desteğinin olmaması, gönderim yolunda ek veri kopyalama ve başlık şifreleme süreci gösteriliyor
- Gelecekte donanım offloading desteği eklenir ve çekirdek içi uygulama optimize edilirse performansın artması bekleniyor
Benimsenme durumu ve ileriye dönük görünüm
- Samba sunucu/istemcisi, çekirdek SMB ve NFS dosya sistemleri, curl gibi çeşitli projelerde çekirdek içi QUIC desteği aktif olarak tartışılıyor
- Yama yaklaşık 9.000 satır büyüklüğünde ve şu anda yalnızca düşük seviye destek kodunu içeriyor. Tam uygulama için ek yamalar planlanmış durumda
- Kod incelemesi ve birleştirme tartışmaları daha yeni başladı; gerçek kullanım için daha fazla zamana ihtiyaç duyulacağı öngörülüyor
- Yakın zamanda Homa protokolünün çekirdeğe alınmasının 9 ay boyunca 11 gönderim gerektirdiği düşünüldüğünde, QUIC'in de ana dala 2026'dan sonra girmesi bekleniyor
1 yorum
Hacker News görüşleri
ssl_preread_server_nameekleyerek belirli alan adı isteklerini başka bir NGINX instance'ınaproxy_passettimİlk instance yalnızca ham TLS akışını iletiyor (
proxy_protocoldahil), ikinci instance ise gerçek TLS sonlandırmasını üstleniyorBu yöntem failover uygularken etkili oluyor - sunucunun birincil yolu devre dışı kalırsa DNS A kaydını failover makinesindeki NGINX'e güncelliyorum ve bu instance belirli alan adı isteklerini ayrı bir yol üzerinden asıl backend'e yönlendiriyor
Tüm TLS yapılandırmasını kopyalamak gerekmediği için kullanışlı
Ancak bu yöntem HTTP/3 için geçerli değil
HTTP/3, QUIC tabanlı, UDP üzerinde çalışıyor ve handshake sırasında SNI'ı şifrelediği için
ssl_preread_server_nameile alan adına göre yönlendirme yapılamıyorHTTP/3'te SNI tabanlı yönlendirmeyi destekleyecek bir alternatif olup olmadığını ya da bu özellik gerekiyorsa hâlâ HTTP/1.1 veya HTTP/2 over TLS'te mi kalmak gerektiğini merak ediyorum
Pratikte istemci uygulamasına göre davranış değişiyor (Chromium'un HTTPS kayıt desteği durumu için sorun bağlantısına bakın), ancak QUIC bağlantısı başarısız olursa istemci şeffaf biçimde HTTP/1.1/2'ye fallback yapıyor ve Alt-Svc başlığını da dikkate alıyor
Planlı bir failover ise, Alt-Svc başlığı göndermeyip alternatif instance'a timeout olmasını bekleyebilirsiniz
QUIC yönlendirmesi gerçekten gerekiyorsa, neyse ki SNI bilgisi her zaman ilk pakette bulunur, dolayısıyla paket incelemesiyle yönlendirme yapılabilir
cloudflare'ın udpgrm aracı buna referans olabilir ve bu, ECH (Encrypted Client Hello) olmadığında kullanılabilir
ECH varsa yönlendiricinin yönlendirme kararı verebilmesi için çözme anahtarına sahip olması gerekir ve protokol düzeyinde kademeli failover da tasarlanabilir
Somut kod uygulaması udpgrm örneğinde görülebilir
Saldırgan o sunucuya erişebiliyorsa SSL sertifikasını yeniden çıkarması da kolay olur; bu yüzden karmaşık bir failover sistemi düşünmektense TLS'i doğrudan sonlandırmak daha mantıklı
Ben şahsen QUIC'in performans ve güvenilirlik avantajlarını birebir yeniden üretebilmiş değilim
Yıllardır tekrar tekrar test ediyorum ama performans vb. nedenlerle çoğu zaman devre dışı bırakıyorum
DNS tabanlı failover da fiilen yansıyana kadar birkaç dakika sürüyor ve tarayıcı gibi basit istemcilerde failover pek iyi çalışmıyor
Bu yüzden doğrudan
onerrorhandler kullanıp ikinci yolu yükleme yöntemini kullanıyorumÖrneğin reklam takibi için bu tür bir kod kullanıyorum ve fetch API'yi de aynı şekilde wrap ederek sunuyorum
Bu yöntem, denediğim diğer her şeyden çok daha verimli
Tarayıcı QUIC bağlantısında başarısız olsa bile (hatta DNS'te ilan edilmiş olsa bile) otomatik olarak HTTP/1 ya da HTTP/2 over TLS'e fallback yapıyor, dolayısıyla mevcut failover yöntemleri aynen kullanılabiliyor
HTTP/3'ün tasarım özelliklerinden biri, TLS katmanına kadar endpoint bilgisini açığa çıkarmaması
Ben bunu kişisel olarak bir avantaj olarak görüyorum
HAProxy ham TLS proxy yapabiliyor ama host adına göre yönlendirme yapamıyor
Cloudflare tunnel, TLS sonlandırmadan host adına göre yönlendirme yapabilen özel bir özelliğe sahip, ancak bunu kullanmak için DNS'in de Cloudflare'a yönlenmesi gerekiyor
Bununla ilgili xkcd karikatürüne bakılabilir
TCP+TLS ortamında Encrypted Client Hello kullanıldığında da aynı sınırlamanın olup olmadığını merak ediyorum
Cevabın büyük ölçüde aynı olacağını düşünüyorum
Bu tartışma bana bu sorunları adım adım çözmeye yönelik gibi geliyor
İleride ağ kartlarının donanımsal destek verme ihtimali de var
Ancak bugünlerde internet trafiğinin çoğu mobil ile sunucu arasında aktığı için, asıl gücünü QUIC ve HTTP/3 orada gösteriyor
Diğer kullanım alanlarında TCP kullanılmaya devam edilebilir
Dışarıdan eskisi gibi birden fazla connection varmış gibi görünür ama içeride cache'lenir gibi bir şey olabilir
Ben açıkça bir connection nesnesi alıp onun üzerinden ayrı stream'ler açılan bir modeli tercih ederdim, ama mevcut yaklaşımı da kabul edebilirim
İlgili tartışmaya bakınca, bu bir uzantı özelliği değilse sunucu tarafında da connection kurulduktan sonra yeni stream oluşturulabiliyor
İstemci tarafında aslında stream olmasına rağmen bunu "connection" gibi ayrı bir soyutlama altında sunmak zor ve temelde tamamen yeni bir API soyutlaması gerekiyor gibi görünüyor
Muhtemelen her yeni stream için recvmsg ile file descriptor alınan bir yapı olur diye düşünüyorum
Mosh gibi ağ sorunlarına dayanıklı ama OpenSSH'in tüm özelliklerini de (SFTP, SOCKS, port forwarding, state yönetimi, roaming vb.) aynen kullanabildiğim bir yapı isterdim
OpenSSH'in çekirdek desteğinden yararlanıp yararlanamayacağını merak ediyorum
Mosh'a bakın
Hatta QUIC tabanlı ayrı bir oturum açma protokolü oluşturmak daha mantıklı olabilir
Çeşitli yaklaşımlar hâlihazırda prototip aşamasında ilerliyor
Buna rağmen mevcut QUIC çekirdek implementasyonunun Linux'a kıyasla 3-4 kat daha yavaş olduğu ve performans farkının yakında kapanabileceği söyleniyor
Hız QUIC'in avantajıysa ama gerçekte daha yavaşsa, QUIC kullanmak için ne sebep var diye merak ediyorum
PR yazarının da performans düşüşünün bir kısmının protokol tasarımından kaynaklandığını söylediği düşünüldüğünde, TCP tarafında ayrıca düzeltilmesi gereken başka şeyler olup olmadığını soruyorum
Bunların çoğu "henüz optimize edilmedi" diye özetlenebilir
Örneğin segment offload desteğinin olmaması, iletim yolunda ek veri kopyalama, header şifrelemesinden gelen ek yük gibi etkenler var ve bunların çoğu büyük olasılıkla çözülebilir
Buradaki benchmark çok ideal bir ortamda yapıldı
Gerçek dünyada özellikle mobil ortamlar ağ dalgalanmalarına çok daha açık olduğu için TCP'nin yapısal sınırlamaları daha belirgin hale geliyor
Nitekim HTTP/2 gibi teknolojilerle TCP üzerinde de QUIC'e benzer pek çok işlev zaten uygulanıyor
Sonuçta QUIC, OSI'nin 5. katmanı ve üstünde çalışan bütünleşik bir ağ yığını gibi; TCP ise 3. katman düzeyinde bir motor olduğu için yapısal olarak birebir kıyaslamak zor
Her şeyden önce QUIC'in avantajı daha hızlı connection kurulumu ve yeniden bağlanma sağlaması
IP değiştiğinde bile oturum sürekliliğini koruyabiliyor
Multiplexing ve non-blocking stream yapısı, üst seviye protokollerin tasarımını ciddi ölçüde basitleştiriyor
Bu yapının çekirdeğe girmesi performans optimizasyonu açısından da büyük alan açar
Gelecekte TCP'nin sınırları üzerine katman katman çözüm inşa etmek yerine, QUIC gibi daha gelişmiş temel teknolojileri gündelik olarak daha fazla kullanmamız gerekecek
Paket kaybı olduğunda, sonraki tüm iletimler geri kazanılana kadar gecikiyor; bu da yapısal bir HOL blocking sorunu yaratıyor
Yani mesele sadece hız değil, gecikmeyi iyileştirmek
Teknik açıklamaya bakılabilir
Çekirdek ile kullanıcı alanı arasındaki context switch başlıca darboğaz
Userspace networking (ör. NIC'e doğrudan erişim) çekirdeğe giriş ihtiyacını ortadan kaldırıyor
Buna karşılık çekirdek alanında özellik sunmak (ör. sendfile, in-kernel TLS, NIC offloading, diskten NIC'e doğrudan DMA) da toplam context switch ve veri kopyalama maliyetini düşürüyor
Güncel QUIC yığınları şu anda iki tarafın avantajlarını da tam kullanamıyor
Paket giriş çıkışı syscall tabanlı ve veri kopyalamadan kaçınamıyorlar
io_uring gibi yöntemlerle batch IO yapılırsa switch sayısı azalır ama kopyalama maliyeti ortadan kalkmaz
Bir yanda kernel bypass + DMA, diğer yanda sendfile/ktls benzeri kullanıcı alanını aradan çıkaran yapılar var
QUIC'in çekirdek implementasyonunda şu an iki tarafın avantajı da yok
DMA ile kartın kendisine yazabiliyorsanız ya da çekirdek syscall'larıyla aktarıyorsanız performans farkı büyük olabilir
Userspace networking ancak bu tür privilege geçişleri ve DMA yapıları söz konusu olduğunda anlamlı hale geliyor
Bu daha çok büyük ölçekli şirketlerde (MOFAANG vb.) kullanılıyor
Teoride io_uring'in bu avantajları genelleştirmesi bekleniyor ama henüz pratik kullanım aşamasında değil
Bu yüzden TCP/IP büyük işletim sistemlerinde çekirdekte kalıyor
Çekirdeğin görevinin bellek, donanım ve görev yönetimi olduğunu düşünürdüm; IP üstü protokoller userland'de işlenmeli değil mi diye soruyorum
Tersine, bu yığınları userspace'e ayırmak da bazı durumlarda performans avantajı getiriyor
TCP/UDP, port tabanlı socket yönlendirmesini çekirdekte arabuluculuk ederek birden fazla programın aynı anda TCP/UDP kullanmasını sağlıyor
QUIC, UDP üstünde çalıştığı için tartışmanın özü yine geçerli
Vurgu, doğrudan IP üstündeki protokollerin userspace'te çalıştırılamamasına yapılıyor
İnternetin biraz daha hızlanacağını umuyorum
5G gibi bağlantı ortamlarında fark çok hissedilmeyebilir ama yine de değerli bir ilerleme
Ayrı bir bağlantı handshake yapısına sahip olması ilginç
Ben QUIC'in TLS'i kendi içinde barındırdığını sanıyordum; meğer durum biraz farklıymış
Yine de bu teknolojiyle oyunlardaki latency'nin daha da düşebileceğini düşünüyorum
Hesaplama kaynakları ve ağ verimliliği arttıkça talep de artıyor
Oyunlar ya da bilimsel hesaplamalarda "daha iyi sonuç" için bu sorun olmayabilir
Ama web'de reklam, takip ve JavaScript artışı nedeniyle çoğu zaman ters etki yaratıyor
sendmsg()verecvmsg()syscall'larını kullanan farklı bir yapıya geçtiği söyleniyorBu yaklaşımın neden seçildiğine, neden QUIC'e uygun ayrı system call'lar tasarlanmadığına dair bir açıklama da olsaydı iyi olurdu