Chat uygulamalarının mesajları nasıl anlık olarak ilettiğini ve sunucuyu nasıl aşırı yüklemeden koruduğunu hiç merak ettiniz mi?
<p>Geçenlerde, içerisinde entegre bir sohbet sistemi olan bir legacy Laravel uygulaması üzerinde çalıştım. İlk bakışta, her şey işlevsel görünüyordu — mesajlar gönderiliyor, alınıyor ve özellik "çalışıyordu".</p>
<p>Ama deneyim garip geliyordu.</p>
<p>Mesajlar gecikmeli geliyordu. Arayüz birkaç dakikadan sonra yavaşladı. Birden fazla sekme açmak durumu daha da kötüleştiriyordu. Açıkça bir şeyler ters gidiyordu.</p>
<p>Kodu incelemeye başladığımda sorunu keşfettim: uygulama sürekli olarak sunucudan yeni mesaj sormaktaydı. Bu, <strong>polling</strong> olarak bilinen bir teknik kullanıyordu.</p>
<p>Yani, her bağlı kullanıcı sürekli sunucuya soruyordu:</p>
<blockquote>
<p>"Şimdi yeni mesajlar var mı?"<br/>"Ya şimdi?"<br/>"Şimdi?"</p>
</blockquote>
<p>Bu yaklaşım, küçük dahili araçlar için işe yarayabilir, ancak ölçeklenebilir değil. Yeterince kullanıcıyla birlikte HTTP isteklerinin sayısı patlayarak artmakta — sunucu kaynaklarını tüketmekte ve hâlâ gecikmeli bir "gerçek zamanlı" deneyim sunmaktadır.</p>
<p>Bunun üzerine tüm sohbet sistemini, <strong>Laravel Reverb</strong> kullanarak doğru bir WebSocket tabanlı mimariyle yeniden inşa etmeye karar verdim.</p>
<p>Fark dramatikti:</p>
<ul>
<li>Gecikme önemli ölçüde azaldı</li>
<li>HTTP istek hacmi büyük ölçüde azaldı</li>
<li>Kullanıcı arayüzü gerçek anlamda gerçek zamanlı hale geldi</li>
</ul>
<p>Bu makalede, üretime hazır bir WebSocket çözümü oluşturma sürecimi Laravel 12, Reverb ve Nginx kullanarak sizlerle paylaşacağım.</p>
<hr/>
<h2>
<a name="1-why-polling-fails-at-scale" href="#1-why-polling-fails-at-scale"></a>
1. Polling'in Ölçeklenebilirlikte Başarısızlığı
</h2>
<p>Polling, basit görünmektedir. Client her birkaç saniyede bir sunucuya "Yeni mesajlar var mı?" diye sorar.</p>
<p>Yeni mesajlar varsa, sunucu bunları iletir. Yoksa boş bir yanıt döner.</p>
<p>Küçük ölçeklerde bu işe yarar. Ama matematiğe bakalım.</p>
<p>Bir kullanıcı her 3 saniyede bir sorgularsa:</p>
<ul>
<li>Dakikada 20 istek</li>
<li>Saatte 1,200 istek</li>
</ul>
<p>Şimdi 100 eşzamanlı kullanıcıyı hayal edin:</p>
<ul>
<li>Dakikada 2,000 istek</li>
<li>Saatte 120,000 istek</li>
</ul>
<p>Ve bu isteklerin çoğu… hiçbir şey döndürüyor.</p>
<p>Bu, üç önemli probleme yol açar:</p>
<p><strong>1. Kaynakların Gereksiz Yeri</strong> — Her bir HTTP isteği, sunucunun bağlantıyı kabul etmesi, Laravel framework'ünü başlatması, routing katmanına ulaşması, kimlik doğrulamasını kontrol etmesi ve muhtemelen veritabanına sorgu göndermesi gerektirir — sadece boş bir JSON dizisi döndürmek için. Bu, gerçek bir veri yükü olmaksızın CPU ve RAM tüketir.</p>
<p><strong>2. Yapay Gecikme</strong> — Eğer bir kullanıcı her 3 saniyede bir sorguluyorsa ve bir mesaj sorgulama bitiminden hemen sonra gönderilirse, alıcı kullanıcı bunu neredeyse 3 saniye sonra görecek. Modern bir sohbet uygulamasında bu 3 saniyelik gecikme bir ömür gibi gelir.</p>
<p><strong>3. Client Tarafı Degradasyonu</strong> — Birden fazla sekme açmak, o istekleri katlayarak artırır. Tarayıcılar aynı domaine eşzamanlı bağlantı sayısını sınırlar. Eğer polling bu bağlantıları tıkar ise, uygulamanızın geri kalanı (görüntüleri yüklemek veya form verilerini kaydetmek gibi) yavaşlar.</p>
<hr/>
<h2>
<a name="2-the-websocket-solution-from-asking-to-listening" href="#2-the-websocket-solution-from-asking-to-listening"></a>
2. WebSocket Çözümü: Sormaktan Dinlemeye
</h2>
<p>Client, sunucudan güncellemeler için sürekli olarak soracağına, sunucu sadece client'a bir şeyler olduğunda <em>haber verse</strong>.</p>
<p>İşte burada <strong>WebSockets</strong> devreye giriyor.</p>
<p>WebSocket, client ile sunucu arasında kalıcı, iki yönlü, tam-dupleks bir bağlantı kurar.</p>
<ul>
<li><strong>Bir kere bağlan</strong> — Client, bağlantıyı kurmak için tek bir HTTP isteği gönderir, bu bağlantı daha sonra WebSocket olarak "yükseltilir".</li>
<li><strong>Sürekli dinle</strong> — Bağlantı minimal yük ile açık kalır. Client basitçe bekler.</li>
<li><strong>Anında gönder</strong> — Kullanıcı A mesaj gönderdiğinde, sunucu o yükü kullanıcı B'ye doğrudan açık bağlantı üzerinden anında iletir.</li>
</ul>
<p>Zero wasted requests. Zero artificial delay. True real-time communication.</p>
<hr/>
<h2>
<a name="3-laravel-realtime-options" href="#3-laravel-realtime-options"></a>
3. Laravel Gerçek Zamanlı Seçenekleri
</h2>
<p>Tarihsel olarak, Laravel'de bunu başarmak zorlu bir karar vermeyi gerektiriyordu.</p>
<p>Yıllar boyunca, standart yaklaşım, <strong>Pusher</strong> gibi üçüncü taraf SaaS platformlarına güvenmekti. Kurulumu son derece kolay olmakla birlikte, üçüncü parti hizmetler, eşzamanlı bağlantı ve günlük mesaj limitleriniz arttıkça maliyetli hale gelebiliyor.</p>
<p>İsterseniz maliyetleri düşürmek için kendi sunucunuzu barındırmanız gerektiğinde, PHP ekosisteminin dışına çıkmanız gerekiyordu. <strong>Laravel WebSockets</strong> kullanmayı düşünebilirsiniz (bu, yerel olarak optimize edilmemiş uzun süreli bir PHP işlemi çalıştırmayı gerektiriyordu ve şimdi çoğunlukla terk edilmiş durumda).</p>
<p>Sonra <strong>Laravel Reverb</strong> ortaya çıktı.</p>
<p>Reverb, tamamen PHP ile yazılmış, devasa hızda, yüksek ölçeklenebilirlikte bir WebSocket sunucusu olarak, birinci parti bir paketi olarak tanıtıldı. Laravel'ın mevcut broadcasting sistemine mükemmel bir şekilde entegre olmaktadır.</p>
<hr/>
<h2>
<a name="4-setting-up-reverb-and-broadcasting" href="#4-setting-up-reverb-and-broadcasting"></a>
4. Reverb ve Broadcasting'i Kurmak
</h2>
<p>Laravel 12 kullanarak Reverb'i kurmak ve yapılandırmak son derece akıcıdır. Laravel 12, yayınlamayı varsayılan olarak etkinleştirmez, ancak ihtiyaç duyduğumuz her şeyi oluşturmak için tek bir güçlü Artisan komutu sunar.</p>
<div class="highlight js-code-highlight">
<pre class="highlight shell"><code># Install Broadcasting + Reverb + Node dependencies (Pusher, Echo)php artisan install:broadcasting
<p><strong>INFO</strong> 'broadcasting' yapılandırma dosyası yayınlandı. <br/>
<strong>INFO</strong> 'channels' rota dosyası yayınlandı.</p>
<p>Şimdi, <code>.env</code> dosyanızı kontrol edin. Laravel, yerel Reverb sunucunuz için anahtarları otomatik olarak oluşturmuştur:</p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>BROADCAST_CONNECTION=reverbREVERB_APP_ID=your_generated_id
REVERB_APP_KEY=your_generated_key
REVERB_APP_SECRET=your_generated_secret
REVERB_HOST=”localhost”
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY=”${REVERB_APP_KEY}”
VITE_REVERB_HOST=”${REVERB_HOST}”
VITE_REVERB_PORT=”${REVERB_PORT}”
VITE_REVERB_SCHEME=”${REVERB_SCHEME}”


