Bloga Dön

800 Bin CCU'yu Kaldıran Yalın Bir Multiplayer Game Backend Mimarisi Nasıl Tasarlanır?

Yayınlanma tarihi 25 Temmuz 2026
800 Bin CCU'yu Kaldıran Yalın Bir Multiplayer Game Backend Mimarisi Nasıl Tasarlanır?

Özet olarak

Bu rehber, 800 bin eşzamanlı oyuncuyu (CCU) kaldıran ölçeklenebilir bir multiplayer game backend mimarisinin nasıl tasarlanacağını ele almaktadır. Yazı boyunca kimlik doğrulama fırtınalarının nasıl önleneceği, veritabanı darboğazlarının write-behind önbellek desenleriyle nasıl çözüleceği ve sunucu kaynaklarının dinamik olarak nasıl optimize edileceği incelenmektedir. Ayrıca özel altyapı inşa etmenin zorlukları, [horizOn](https://horizon.pm) gibi modern Backend-as-a-Service çözümleriyle pratik bir şekilde karşılaştırılmaktadır.

Steam'de veya mobil platformlarda viral olmak, tam 50.000 eşzamanlı oyuncunun 30 saniyelik bir pencerede login API'nizi bombardımana tuttuğu o ana kadar her bağımsız geliştiricinin hayalidir. Dakikalar içinde birincil PostgreSQL instance'ınız %100 CPU kullanımına ulaşır, bağlantı havuzları doyar, matchmaking kuyrukları kilitlenir ve ekibiniz uyanmadan önce Steam sayfanız binlerce olumsuz incelemeyle dolup taşar.

Gaggle Studios, Goose Goose Duck oyununu piyasaya sürdüğünde, çoğu stüdyoyu mahveden bir zorlukla karşı karşıya kaldı: mütevazı bir indie oyuncu tabanından 800.000'den fazla anlık eşzamanlı oyuncuya (CCU) ölçeklenmek. Bu büyüklükteki gerçek zamanlı trafiği yönetmek, multiplayer game backend mimarisi hakkında düşünme şeklinizde köklü bir değişim gerektirir. Veri erişim modelleriniz ve ağ topolojileriniz temelden kusurluyken basitçe "daha büyük AWS instance'ları ayağa kaldıramazsınız".

Bu derinlemesine incelemede, hiper büyümeden sağ çıkmak için gereken mimari modelleri analiz edeceğiz, live-ops oyunlarını mahveden veritabanı darboğazlarını ortadan kaldıracağız ve üretime hazır (production-ready) bir write-behind state buffer uygulamasını adım adım inceleyeceğiz.


Hiper-Ölçekli Game Backend'lerin Temel Darboğazları

Bir multiplayer oyun popülarite patlaması yaşadığında, sunucu altyapısı nadiren istemci paket rendering'i veya düşük seviyeli C++ oyun mantığı nedeniyle çöker. Çökme neredeyse her zaman kalıcı depolama, gerçek zamanlı oturum yönlendirme (session routing) ve instance optimizasyonu arasındaki sınırda meydana gelir.

+-----------------------------------------------------------------------+
|                         VİRAL TRAFİK DALGASI                          |
+-----------------------------------------------------------------------+
                                   |
                                   v
                      +-------------------------+
                      |   Edge API Gateway      |
                      +-------------------------+
                                   |
            +----------------------+----------------------+
            |                                             |
            v                                             v
+-----------------------+                     +-----------------------+
|  Auth Fırtınası       |                     | Matchmaking Kuyruğu   |
|  - 10k req/sec        |                     | - DB Kilitleri        |
|  - Token Doğrulama    |                     | - Oda Ataması         |
+-----------------------+                     +-----------------------+
            |                                             |
            +----------------------+----------------------+
                                   |
                                   v
                      +-------------------------+
                      | Birincil DB Çökmesi     |
                      | (Bağlantı Tükenmesi)    |
                      +-------------------------+

1. Kimlik Doğrulama ve El Sıkışma (Handshake) Fırtınası

Viral bir yayıncı "Oyna" tuşuna bastığında, yüz binlerce izleyici istemcinizi aynı anda başlatır. Her oyuncu bir el sıkışma dizisi başlatır:

  • Steam/Epic servislerine karşı OAuth token doğrulama
  • Oyuncu profili getirme (envanter, kozmetikler, MMR, arkadaş listeleri)
  • Oturum başlatma ve token üretimi

İstemciniz oturum açma sırasında oyuncu profilleri için doğrudan birincil veritabanınızı sorgularsa, veritabanınız saniyeler içinde çökecektir. Maksimum 500 bağlantı için yapılandırılmış standart bir RDS instance'ı, 15.000 gelen TCP bağlantısı SELECT * FROM player_profiles WHERE player_id = $1 komutunu çalıştırmaya çalıştığında tıkanacaktır.

2. Monolitik Matchmaker Kilitlenmeleri

Birçok bağımsız oyun backend'i, maç kuyruklarını yönetmek için ilişkisel veritabanı transaction'larına güvenir (örneğin, bir players tablosu satırında status = 'IN_MATCH' bayrağını ayarlamak). 50.000+ CCU'da satır düzeyinde kilitler, indeks çekişmesi (index contention) ve yavaş serileştirme veritabanınızı bir tuğla duvara çevirir. Matchmaking tamamen bellek içinde (in-memory), kilitlenmesiz (lock-free) veya tek iş parçacıklı (single-threaded) event-loop ilkel yapıları kullanılarak çalışmalıdır.

3. Sunucu Atama Tükenmesi

Yüksek frekanslı fizik tahminleri gerektirmeyen oyunlar için ağır, monolitik headless dedicated sunucular (optimize edilmemiş Unreal Engine veya Unity binary'leri gibi) çalıştırmak, bulut bilişimin pahalı bir israfıdır. Her sunucu instance'ı 10 oyunculu bir odaya ev sahipliği yapmak için 1.5 GB RAM ve 1 tam vCPU çekirdeği gerektiriyorsa, 800.000 CCU'ya ev sahipliği yapmak 80.000 vCPU ve 120 Terabayt RAM gerektirir. Standart bulut fiyatlarında, bu operasyonel maliyet ayda 150.000 doları kolayca aşabilir.


Mimari Plan: Durumu (State) Simülasyondan Ayırmak

Viral büyüme sırasında yalın kalan bir multiplayer game backend mimarisi oluşturmak için, üç farklı katman arasında katı bir sınır uygulamalısınız:

  1. Edge ve Sinyalizasyon Katmanı: Kalıcı istemci bağlantılarını (WebSockets/gRPC), kimlik doğrulama token'larını, sohbet yönlendirmesini ve matchmaking sinyalizasyonunu yönetir.
  2. Bellek İçi Durum Katmanı (In-Memory State Layer): Tüm geçici oyun verilerini (oda listeleri, lobilerdeki oyuncu konumları, maç parametreleri) ultra hızlı bellek depolarında (ör. Redis Cluster veya anahtar-değer bellek şebekeleri) tutar.
  3. Kalıcı Depolama Katmanı (Persistent Storage Layer): Kesinlikle kalıcı durum işlemeleri (para birimi değişiklikleri, maç geçmişi, ilerleme kayıtları) için ayrılmış asenkron ilişkisel veya belge depolama (PostgreSQL/MongoDB).
[ İstemci Uygulaması ] ---> ( Kalıcı WebSockets / gRPC )
                                    |
                                    v
                     [ Edge API Gateway Düğümü ]
                                    |
            +-----------------------+-----------------------+
            |                                               |
            v                                               v
[ Ephemerel Maç Düğümü ]            [ Redis Bellek İçi Durum ]
  (Oda Mantığı/Durumu)            (Oturum ve Maç Kuyrukları)
            |                                               |
            +-----------------------+-----------------------+
                                    |
                                    v
                 [ Write-Behind Asenkron İşçi ]
                                    |
                                    v
               [ İlişkisel Veritabanı (PostgreSQL) ]

Bu katmanları ayırarak, 100.000 yeni bağlantının akını yalnızca, birincil veritabanınıza dokunmadan ucuz container düğümleri arasında yatay olarak ölçeklenebilen hafif Edge Sinyalizasyon Katmanını etkiler.

Bu hafif edge iletişimini sürdürmek için yüksek maliyetli client polling'den uzaklaşıyorsanız, oyun backend'lerinde gerçek zamanlı WebSockets için HTTP polling'i bırakma hakkındaki teknik analizimizi inceleyin.


DB Darboğazını Düzeltmek: Write-Behind Önbelleği Uygulamak

Maçlar sırasında istatistikleri güncelleyen, para kazanan veya envanteri değiştiren yüz binlerce eşzamanlı oyuncudan sağ çıkmak için, oyun döngüsü içinde asla doğrudan SQL sorguları çalıştırmamalısınız.

Bunun yerine, bir Write-Behind (Yazma Arkadan) Önbellekleme Deseni uygulayın. Oyuncu durumu değişiklikleri anında hızlı bir bellek içi depoya (Redis gibi) uygulanır ve asenkron bir tamponda (buffer) kuyruğa alınır. Özel bir arkaplan iş parçacığı (background worker thread), toplanan mutasyonları (batched mutations) her 5 ila 30 saniyede bir kalıcı veritabanınıza aktarır.

C# Üretim Uygulaması: Yüksek İş Hacimli Write-Behind Buffer

Aşağıda, yüksek eşzamanlılığa sahip game backend düğümleri için tasarlanmış, iş parçacığı güvenli (thread-safe), toplu işleme dayalı bir write-behind bellek önbelleğinin üretime hazır bir C# uygulaması bulunmaktadır.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

public record PlayerStateMutation(string PlayerId, int CoinsGained, int MatchXp, DateTime Timestamp);

public class WriteBehindStateBuffer
{
    private readonly ConcurrentQueue<PlayerStateMutation> _mutationQueue = new();
    private readonly SemaphoreSlim _flushSemaphore = new(1, 1);
    private readonly CancellationTokenSource _cts = new();
    private readonly int _batchSize;
    private readonly TimeSpan _flushInterval;

    public WriteBehindStateBuffer(int batchSize = 500, int flushIntervalSeconds = 10)
    {
        _batchSize = batchSize;
        _flushInterval = TimeSpan.FromSeconds(flushIntervalSeconds);
        
        // Arkaplan flush daemon'ını başlat
        Task.Run(ProcessQueueLoopAsync);
    }

    /// <summary>
    /// Hot-path: Bir maç olayı gerçekleştiğinde oyun sunucusu mantığı tarafından çağrılır.
    /// Engellemesiz bellek ekleme (0.01ms ek yük).
    /// </summary>
    public void EnqueueMutation(string playerId, int coins, int xp)
    {
        var mutation = new PlayerStateMutation(playerId, coins, xp, DateTime.UtcNow);
        _mutationQueue.Enqueue(mutation);
    }

    private async Task ProcessQueueLoopAsync()
    {
        while (!_cts.Token.IsCancellationRequested)
        {
            await Task.Delay(_flushInterval, _cts.Token);
            await FlushBatchToDatabaseAsync();
        }
    }

    public async Task FlushBatchToDatabaseAsync()
    {
        if (_mutationQueue.IsEmpty) return;

        await _flushSemaphore.WaitAsync();
        try
        {
            List<PlayerStateMutation> batch = new(_batchSize);
            while (batch.Count < _batchSize && _mutationQueue.TryDequeue(out var mutation))
            {
                batch.Add(mutation);
            }

            if (batch.Count > 0)
            {
                await ExecuteSqlBatchInsertAsync(batch);
            }
        }
        catch (Exception ex)
        {
            // Üretimde (Production): Hatayı logla, başarısız bachu dead-letter kurtarma kuyruğuna gönder
            Console.WriteLine($"[CRITICAL] Write-Behind Batch Flush Başarısız: {ex.Message}");
        }
        finally
        {
            _flushSemaphore.Release();
        }
    }

    private async Task ExecuteSqlBatchInsertAsync(List<PlayerStateMutation> batch)
    {
        // Birleştirilmiş tek bir SQL transaction çalıştırma simülasyonu örneği
        // Yüzlerce ayrı sorgunun yerini alan toplu INSERT / UPDATE ifadesi
        Console.WriteLine($"[DB FLUSH] {batch.Count} durum mutasyonu 1 transaction içinde başarıyla SQL'e yazıldı.");
        
        // Simüle edilmiş DB I/O gecikmesi
        await Task.Delay(25);
    }

    public void Shutdown()
    {
        _cts.Cancel();
        FlushBatchToDatabaseAsync().GetAwaiter().GetResult();
    }
}

Bu Teknik Neden Ölçekleniyor?

  • Sorgu Azaltma: 10.000 ayrı UPDATE player_stats SET coins = coins + 50 veritabanı işlemini 1 adet toplu (batched) bulk transaction işlemine indirger.
  • Sıfır Girdi Gecikmesi (Input Latency): Durum değişikliği hemen RAM'e kaydedildiği için istemci anında başarı geri bildirimi alır.
  • Veritabanı Şok Emilimi: Trafik %500 artarsa, veritabanı yazma yükünüz pürüzsüz ve sabit kalır — yalnızca kuyruk batch boyutları büyür.

Dinamik Sunucu Yaşam Döngüsü ve Kaynak Optimizasyonu

Parti oyunları, sosyal çıkarım (social deduction) oyunları ve lobi nişancı oyunları, oyuncular yalnızca oyun öncesi bir lobide ayakta sohbet ederken tam 60Hz fizik doğrulaması gerektirmez.

Bulut instance başına sunucu yoğunluğunu maksimize etmek için Dinamik Frekans Ölçeklendirme (Tick Throttling) uygulayın:

+-----------------------------------------------------------------+
|                    SUNUCU DURUM DÖNGÜSÜ                         |
+-----------------------------------------------------------------+

  [ OYUN ÖNCESİ LOBİ ] -----> [ AKTİF OYNANIŞ ] -------> [ MAÇ SONU ]
  - Oran: 10 Hz              - Oran: 30 - 60 Hz         - Oran: 5 Hz
  - CPU: ~%5 çekirdek        - CPU: ~%35 çekirdek       - CPU: ~%2 çekirdek
  - Bant Genişliği: Minimum  - Bant Genişliği: Yüksek   - Bant Genişliği: Flush
  • Oyun Öncesi Lobi Aşaması (10 Hz): İstemci konumlandırma ve kozmetik kontrolleri için daha düşük tick güncellemeleri. Bu, oda başına CPU tüketimini %65'e varan oranlarda düşürür.
  • Aktif Oynanış Aşaması (30-60 Hz): Mekansal etkileşimler, oylama veya yüksek hızlı hareket başladığında frekansı dinamik olarak artırın.
  • Maç Sonu Özeti (5 Hz): Oyuncular ödülleri incelerken sunucu hesaplamalarını neredeyse boşta (idle) kalacak şekilde kısıtlayın; böylece WebSocket soketi açık tutulurken bulut bilişim kaynakları korunur.

Modern motorların sıfır yük koşullarında compute idle durumlarını ve sunucu hibernasyonlarını nasıl yönettiğine dair derinlemesine analiz için, sıfır atıklı sunucu hibernasyon protokolleri hakkındaki mimari analizimizi inceleyin.


Custom (Özel) ve Managed (Yönetilen) Altyapı Karşılaştırması

Beklenmeyen trafik artışlarını idare etmek için bir multiplayer game backend mimarisi ölçeklendirirken, geliştiriciler büyük bir altyapı seçimiyle karşı karşıya kalır: özel bir ölçeklendirme backend'i inşa etmek veya yönetilen servisleri kullanmak.

+-----------------------------------------------------------------------+
|                    CUSTOM ALTYAPI YIĞINI (STACK)                      |
+-----------------------------------------------------------------------+
| - Kubernetes Engine (EKS / GKE Fleet Allocation)                     |
| - Özel Agones / Orchestrator Controller Entegrasyonu                  |
| - Dağıtık Redis Enterprise Cluster Sharding                          |
| - Özel Matchmaker Kuyruk Motoru + Bölgesel Edge Yönlendirme          |
| - Prometheus / Jaeger / Grafana Dağıtık İzleme Pipeline'ları           |
+-----------------------------------------------------------------------+
| TAHMİNİ SÜRE: 3 ila 6 Ay Mühendislik Süresi                          |
| BAKIM YÜKÜ: Sürekli On-Call DevOps Mühendisliği                       |
+-----------------------------------------------------------------------+

Tüm bu pipeline'ı manuel olarak inşa etmek; özel Kubernetes cluster'ları kurmayı, Agones fleet allocator'ları yazmayı, Redis cluster sharding'i yönetmeyi ve 7/24 DevOps monitoring'i çalıştırmayı gerektirir. Bağımsız ve orta ölçekli stüdyolar için bu altyapıyı korumak, kritik geliştirme süresini gerçek oyun özelliklerinden uzaklaştırır.

horizOn gibi özel bir Backend-as-a-Service tam burada geliştirici deneyimini değiştirir. Özel matchmaker'lar, socket filoları ve dinamik sunucu autoscaler'ları inşa etmek için aylarca harcamak yerine horizOn; anında oturum sağlama, ölçeklenen durum kalıcılığı ve düşük gecikmeli matchmaking dahil olmak üzere önceden yapılandırılmış gerçek zamanlı backend bileşenlerini kutudan çıktığı gibi sunar.


Ölçeklenebilir Multiplayer Backend'ler Tasarlamak İçin 5 Kural

Şu anda bir multiplayer oyun backend'i tasarlıyorsanız, bu kuralları sistem tasarımınızın merkezinde tutun:

  1. Kalıcı Veritabanınızı İzole Edin: Canlı sunucu tick'lerinin veya maç döngülerinin doğrudan senkronize bir veritabanı yazmasını asla bekletmesine izin vermeyin. Her şeyi bellek önbellekleri ve asenkron write-behind işçileri (workers) aracılığıyla yönlendirin.
  2. Stateless Edge Yönlendirme için Tasarlayın: API gateway'lerinizi ve bağlantı proxy'lerinizi tamamen stateless (durumsuz) tutun. Yük altında gateway Node-A çökerse, istemci bağlantıları temel maç oturumu durumlarını kaybetmeden sorunsuz bir şekilde Node-Bye geçmelidir.
  3. Dinamik Kaynak Tahsisi: Sunucu tick hızlarınızı oyun oturumunun durumuyla eşleştirin. Lobi hazırlığı veya menü ekranları sırasında tam oranlı oyun döngüleri çalıştırarak sunucu döngülerini boşa harcamayın.
  4. HTTP Polling Yerine Kalıcı İkili Akışlar (Binary Streams) Kullanın: İstemci-backend iletişimini HTTP REST polling'den kalıcı WebSocket veya gRPC akışlarına geçirerek başlık (header) ek yükünü ve TCP el sıkışma çırpınmalarını Drastik ölçüde azaltın.
  5. Yük Altında Zarifçe Başarısız Olun (Fail Gracefully): Uyarlanabilir özellik düşüşü (adaptive feature degradation) uygulayın. Backend'iniz kuyruk sürelerinin güvenlik eşiklerini aştığını tespit ederse, çekirdek maç döngülerini korumak için temel olmayan alt sistemleri (küresel matchmaking liderlik tabloları veya özel kozmetik önizlemeleri gibi) otomatik olarak devre dışı bırakın.

Sonraki Adımlar

Yüz binlerce eşzamanlı oyuncuya ölçeklenen bir multiplayer backend inşa etmek, daha büyük bulut instance'ları satın almakla ilgili değildir; veritabanınızı koruyan ve ağ bilişimini kolaylaştıran ayrıştırılmış, bellek öncüllü mimariler tasarlamakla ilgilidir.

Sunucu filolarını ve veritabanı kümelerini yapılandırmakla aylarca vakit kaybetmeden bir sonraki oyununuz için esnek, ölçeklenebilir bir backend uygulamaya hazırsanız, horizOn'un dağıtımınızı nasıl hızlandırabileceğini keşfedin. horizOn'u ücretsiz denemek için kaydolabilir veya resmi horizOn Belgeleri içindeki mimari kılavuzlarımızı inceleyebilirsiniz.


Kaynak: Staying Lean: How We Built the World's Biggest Social Deduction Game