Laravel uygulamalarında gerçek zamanlı özellikler geliştirmeye bir süredir devam ediyorum. Kendinize özel yayın yapma (self-hosted broadcasting) her zaman bir bedelle birlikte geldi. Ya Pusher/Ably’ye bağlantı başına ücret ödüyorsunuz, ya da kendiniz barındırıyorsunuz. Kendinize özel barındırma, Reverb (tek iş parçacıklı PHP, 1,000’in üstündeki bağlantılar için ext-ev + Redis gerektirir) veya PHP yığınınızın yanına oturan Soketi (Node runtime) gerektiriyordu.
İki şey beni sürekli zorluyordu: bağlantı başına bellek kullanımı ve bir yavaş istemci tüm diğerlerinin olay döngüsünü bloke ettiğinde neler olacağı.
Bu nedenle, Ripple‘ı geliştirdim — Pusher uyumlu bir WebSocket sunucusu, Rust ile yazıldı — böylece hiç kimseye istemci kodu üzerinde tek bir satır bile değiştirmesini istemeden iki sorunu da çözebileceğimi görmek istedim.
Tasarım Kısıtlaması: İstemci Üzerinde Hiçbir Şey Değiştirme
Tasarım Kısıtlaması: İstemci Üzerinde Hiçbir Şey Değiştirme
En önemli karar uyumluluk oldu. Ripple, Pusher Channels protokolünü konuşuyor, böylece mevcut kurulumunuz hiçbir değişiklik olmaksızın çalışıyor:
- Laravel Echo
- pusher-js
- pusher-php-server
- mobil SDK’lar
wsHost / wsPort adresinizi Ripple’a yönlendirdikten sonra işiniz bitti. Redis yok, Node yok, PHP uzantıları yok. Bu, tek bir statik ikili dosya olarak gelir — Docker imajı yaklaşık 5 MB FROM scratch olarak tasarlanmıştır.
composer require ripple/ripple-laravel
php artisan ripple:install
php artisan ripple:start
Neden Rust?
Neden Rust?
Reverb, tek iş parçacıklı bir PHP olay döngüsüdür. Bu, zor bir sınırdır: bir çekirdek üzerinde çalışır ve 1,000’in üzerinde bağlantıya ölçeklenmek için ext-ev/ext-uv ve Redis gerektirir.
Ripple, tüm çekirdeklerde doğrudan çalışır ve bağlantı başına bellek tüketimi, mütevazı bir sunucunun on binlerce bekleyen bağlantıyı barındırmasına izin verecek kadar küçüktür.
Sayılar
Sayılar
AWS c6i.xlarge üzerinde Reverb ile baştan sona karşılaştırıldığında, her iki sunucu da 2 çekirdeğe paralel çalıştırıldı. Tam metodoloji ve uyarılar, repo’nun bench/RESULTS.md dosyasında mevcut:
| Metri̇k | Ripple | Reverb (ayarları yapılmış) |
|---|---|---|
| 60,000 bekleyen bağlantı | 770 MiB, %100 kurulu | denenmedi |
| 40k bağlantıdaki bellek | 512 MiB (~12.8 KB/bağlantı) | 834 MiB (~20 KB/bağlantı) |
| 50k teslimat/s — p50 / p99 | 14.7 / 32 ms | 24.6 / 254 ms |
| 1 olaydan 10k aboneye dağıtım | p50 94 ms | p50 122 ms |
Bu sayılar, belirli donanım için geçerlidir — bunları göreli olarak değerlendirin, mutlak değer olarak değil. Ayrıca, bu yapıda Soketi’yi henüz kullanmadım, bu nedenle Soketi sayıları burada yok. Ölçmediğim karşılaştırmaları yayınlamak istemiyorum.
Asıl Önem Verdiğim Kısım: Yavaş Tüketiciler
Asıl Önem Verdiğim Kısım: Yavaş Tüketiciler
Hammade verimlilik testleri kolay kısım. Üretimde sorun çıkaran başlıca stres noktası daha ince detaylarla ilgilidir: kötü bir mobil bağlantıya sahip bir istemci, mesajları yeterince hızlı boşaltamaz, bu nedenle bu birikim artar ve — sunucunun türüne bağlı olarak — bu baskı herkesi olumsuz etkileyebilir.
Bir akışta Reverb, sınırsız şekilde tampon belleği tutarken, p99 gecikmesi tüm istemciler için yüzlerce saniyeye kadar çıkar. Ripple, her bağlantının tamponunu sınırlar, dağıtım işlemini engellemeden devam ettirir ve yavaş giden bağlantıyı keserek geri kalanını zorlaştırmaktan kaçınır. Bellek sabit kalır.
Bu, her şeyden çok, devam etmeyi sağladı.
Oturum Devam Ettirme (Gurur Duyduğum Tek Uzantı)
Oturum Devam Ettirme (Gurur Duyduğum Tek Uzantı)
Standart Pusher istemcileri, yeniden bağlantı gerçekleştiğinde mesajları kaybeder — bir mobil dalgalanma veya dağıtım nedeniyle olaylar kaybolur.
Ripple, bir uygulamada her dağıtım çerçevesinin bir kanal için sıralı numarası taşıdığı ve sunucunun son N olayı tuttuğu opt-in bir uzantıya sahiptir (history_size = N). Yeniden bağlantı sırasında istemci, en son gördüğü sıralı numarayı gönderir ve kaybedilen olaylar sıralı bir şekilde yeniden iletilir. Yaklaşık 40 satırlık bir Echo/pusher-js eşlikçisi ile birlikte gelir ve yetkilendirme güvenliğidir — oturum devami, daha önce imzalanmış bir abonelik gerektirir.
Kutuda Başka Neler Var
Kutuda Başka Neler Var
Presence kanalları, istemci olayları, webhooks, /metrics altında Prometheus metrikleri, /ripple adresinde bir Horizon tarzı Laravel kontrol paneli, rustls ile yerel TLS ve güncelleme sırasında akıştaki mesajları boşaltan ve doğru kapanış çerçevesi göndererek istemcilerin temiz bir şekilde yeniden bağlanmasını sağlayan nazik duraklatma.
Henüz Erken
Henüz Erken
Ripple henüz v0 seviyesinde ve MIT lisansına sahiptir. Henüz büyük ölçeklerde test edilmedi, bu nedenle dikkatli gözlemleriniz değerli. Protokol kenar durumları ve özellikle benchmark metodolojisi üzerinde eleştirilerinizi bekliyorum.
Repo: https://github.com/madisoheib/Ripple
Laravel üzerinde gerçek zamanlı uygulamalar yürütüyorsanız, kurulumunuzun hangi alanlarının zorlandığını duymak isterim.
Kaynak: Orijinal Makale


