Hibrit Matchmaking Mühendisliği: Call of Duty'nin Queue Ayrımı Modern Game Matchmaking Architecture'ı Nasıl Gözler Önüne Seriyor
Özet olarak
Call of Duty: Black Ops 7'deki queue ayrımı, modern game matchmaking architecture sistemlerinin gecikme (latency), yetenek farkı ve queue süreleri arasındaki karmaşık dengesini gözler önüne seriyor. Bu makale; SBMM, connection-first ve dinamik hibrit queue modellerinin arkasındaki altyapı mimarisini ve C# kod uygulamalarını analiz etmektedir. Ayrıca dağıtık sistemlerde lock contention, yük dengeleme (load balancing) ve otomatik Dedicated Server provisioning süreçlerini yönetmek için en iyi mühendislik pratiklerini sunmaktadır.
Activision, Call of Duty: Black Ops 7'nin oyuncu kitlesini üç farklı matchmaking queue'suna—Skill-Based Matchmaking (SBMM), Klasik Connection-Based ve Hibrit—ayıracağını duyurduğunda, uzun süredir devam eden bir backend mühendisliği tartışmasını yeniden gündeme taşıdı. Rekabetçi oyunlar için oyuncuları nasıl eşleştireceğinize karar vermek yalnızca bir oyun tasarımı tercihi değildir; milisaniye altı ağ kısıtlamalarını, matematiksel yetenek varyansını (skill variance), pool fragmantasyonunu ve bulut bilgi işlem (cloud compute) maliyetlerini dengeleyen karmaşık bir game matchmaking architecture problemidir.
Matchmaking sisteminizi birden fazla farklı queue'ya bölmek yüzeyde basit bir oyuncu tercihi özelliği gibi görünebilir. Gerçekte ise backend altyapınızdaki mühendislik yükünü ikiye veya üçe katlar. Anlık oyuncu sayısını (CCU) ayrı queue'lara böldüğünüzde, ticket yoğunluğu hızla düşer, düşük yoğunluklu bölgelerde queue süreleri üssel olarak uzar ve server allocation algoritmaları ciddi bir yük ve çalkantıyla (churn) karşı karşıya kalır.
Bu makalede, SBMM ile connection-first matchmaking arasındaki teknik trade-off'ları analiz edecek, dinamik hibrit queue genişlemesinin arkasındaki matematiği inceleyecek, ticket işleme için gerçek backend C# kodlarını gözden geçirecek ve sorunsuz bir şekilde ölçeklenen dirençli matchmaking pool'larının nasıl inşa edileceğini keşfedeceğiz.
Değişmez Matchmaking Trilemma'sı
Her modern game matchmaking architecture, birbirleriyle çelişen üç değişken tarafından sınırlandırılmış bir kısıt optimizasyonu (constraint optimization) problemini çözmek zorundadır:
- Latency (RTT): Oyuncu client'ı ile tahsis edilen Dedicated Server instance'ı arasındaki gidiş-dönüş süresi (milisaniye cinsinden).
- Skill Delta ($\Delta$MMR): Belirli bir lobideki oyuncular arasındaki yetenek temsilinin (MMR, Elo veya TrueSkill) matematiksel farkı.
- Queue Duration ($T_{queue}$): Geçerli bir match ticket'ı aktif bir server allocation'a dönüşmeden önce oyuncunun bekleme durumunda harcadığı toplam süre.
Latency (RTT)
/ \
/ \
/ Ideal \
/ Match \
/ \
Skill Delta (ΔMMR) --------------- Queue Duration (T_queue)
Bu değişkenlerden herhangi ikisini, üçüncünün pahasına kolayca optimize edebilirsiniz:
- Low Latency + Low Skill Delta: Uzun queue süreleriyle sonuçlanır; çünkü oyun motoru aynı bulut datacenter'ına yakın yaşayan ve tamamen aynı yetenek seviyesindeki nadir oyuncuları aramak zorundadır.
- Low Queue Time + Low Skill Delta: Yüksek latency ile sonuçlanır; çünkü matchmaker eşit yetenekteki rakipleri bulabilmek için coğrafi arama yarıçapını dünya çapında genişletmek zorundadır.
- Low Queue Time + Low Latency: Yüksek skill variance ile sonuçlanır (klasik "connection-first" public match deneyimi); çünkü matchmaker performans metriklerine bakmaksızın en yakındaki kullanılabilir client'ları anında eşleştirir.
Black Ops 7 gibi bir yapım üç ayrı queue modu sunduğunda, altta yatan matchmaking architecture'ı parçalanmış bellek pool'ları üzerinde üç paralel kural değerlendirme döngüsü (rule evaluation loop) çalıştırmaya zorlar.
Belirli bir bölgedeki—örneğin gece saat 04:00'te Güney Amerika'daki—Concurrent Users (CCU) sayınız 2.000 aktif oyuncunun altına düşerse, bu oyuncuları üç ayrı pool'a bölmek her queue için yerel yoğunluğu yalnızca birkaç yüz oyuncuya düşürür. Sonuç olarak, connection-first queue'ları düşük ping'li Dedicated Server'lar bulmakta başarısız olur ve SBMM queue'ları süresiz olarak takılı kalır.
SBMM, Ping-First ve Hibrit Queue Yapılarının Analizi
Milyonlarca match ticket'ını işleyebilecek kapasitede bir backend inşa etmek için öncelikle her bir mimari modelin arka planda nasıl çalıştığını anlamanız gerekir.
1. Connection-Based (Ping-First) Architecture
Connection-first motorlarda yetenek matrisleri tamamen ikincil plandadır veya göz ardı edilir. Temel hedef ağ performansındaki düşüşleri (jitter, packet loss, yüksek RTT) en aza indirmektir.
- Client Ping Probing: Oyuncu queue'ya girdiğinde, game client'ı bölgesel edge gateway'lere (
us-east-1,eu-central-1,ap-southeast-1gibi) bir dizi ICMP veya UDP ping beacon'ı gönderir. - Ping Vector Generation: Client bir latency vektörü oluşturur:
[ us-east: 24ms, us-west: 78ms, eu-central: 142ms ]ve bunu matchmaking payload'una ekler. - Spatial Indexing: Matchmaker, oyuncuları kabul edilebilir latency eşiklerine göre (örn. $RTT < 50ms$) doğrudan bölge hash'lerine gruplar (bucket).
Ağ topolojisi maç oluşturma sürecini doğrudan belirlediği için oyuncu arama bucket'ları öngörülebilirdir; bu da basit FIFO (First-In, First-Out) mekânsal queue'lar kullanılarak ticket'ların $O(1)$ zaman karmaşıklığında çözümlenmesini sağlar.
2. Skill-Based Matchmaking (SBMM) Architecture
SBMM, oyuncu yeteneğini çok boyutlu Gauss dağılımları (örneğin TrueSkill 2) veya özelleştirilmiş Elo varyasyonları ile modelleyerek maç adaletini önceliklendirir. Temel girdiler arasında galibiyet/mağlubiyet oranları, kill/death oranları, dakika başına hasar ve son zamanlardaki performans gidişatı yer alır.
- Distance Evaluation: Matchmaker, aday oyuncu vektörleri arasındaki Öklid (Euclidean) veya Mahalanobis mesafesini $N$-boyutlu yetenek uzayında hesaplar.
- Sorting Cost: Matchmaker'lar basit FIFO queue'larına güvenemez. Kabul edilebilir bir skill variance ($\sigma$) dahilinde adayları hızlıca bulabilmek için ticket profillerinden oluşan sıralı kümeler (sorted sets) veya mekânsal ağaçlar (KD-trees gibi) tutmalıdırlar.
- Search Space Contraction: Oyuncu yeteneği arttıkça (örneğin oyuncuların en üst %0,5'lik kesimi), uygun aday pool'u ciddi şekilde daralır. Bu durum sistemi ticket'ları süresiz tutmaya ya da yetenek katılık parametrelerini kademeli olarak esnetmeye (decay) zorlar.
3. Dynamic Hybrid Architecture
Oyuncuları sabit queue seçeneklerine zorlamak yerine, modern production backend'leri sıklıkla bir Dynamic Hybrid (Dinamik Hibrit) model uygular. Bu yapıda her match ticket'ı katı SBMM ve düşük latency sınırlarıyla başlar. $T_{queue}$ arttıkça, bir kural esnetme (rule decay) fonksiyonu kabul edilebilir skill delta ($\Delta MMR$) ve latency limitini ($RTT_{max}$) sürekli genişletir...
$$\Delta MMR_{allowed}(t) = \Delta MMR_{base} + \alpha \cdot t^{\gamma}$$
$$RTT_{allowed}(t) = \min\left(RTT_{max_cap}, RTT_{base} + \beta \cdot \lfloor t / \Delta t_{step} \rfloor\right)$$
Burada $\alpha$ ve $\beta$ genişleme katsayılarıdır, $\gamma$ üssel eğrinin dikliğini kontrol eder ve $t$ saniye cinsinden geçen queue süresidir.
Dinamik esnetmeden faydalanarak, yoğun CCU dönemlerinde yüksek maç kalitesini korurken queue'ların sonsuz döngüde takılı kalmasını engellersiniz.
Kod Uygulaması: Dinamik Kural Genişletme Motoru
Aşağıda, dinamik bir matchmaking kural genişletme motorunun C# ile yazılmış, sahada test edilmiş bir uygulaması yer almaktadır. Bu servis, gelen ticket'ları aktif queue pool'larına göre değerlendirerek anlık ping uyumluluk matrislerini ve dinamik MMR variance üst sınırlarını hesaplar.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Horizon.Matchmaking.Engine
{
public class MatchmakingTicket
{
public string TicketId { get; set; } = Guid.NewGuid().ToString();
public string PlayerId { get; set; }
public double SkillRating { get; set; } // Elo/MMR representation
public Dictionary<string, int> RegionalPingMap { get; set; } = new(); // e.g., "us-east": 28
public DateTime EnqueuedAtUtc { get; set; }
}
public class DynamicMatchRules
{
public double MaxAllowedMmrDelta { get; set; }
public int MaxAllowedPingMs { get; set; }
}
public class MatchmakingEvaluator
{
private const double BaseMmrDelta = 50.0;
private const double MaxMmrCap = 600.0;
private const int BasePingMs = 35;
private const int AbsoluteMaxPingMs = 180;
private const double PingStepIntervalSeconds = 4.0;
/// <summary>
/// Calculates the expanded criteria for a ticket based on elapsed queue time.
/// </summary>
public DynamicMatchRules GetRelaxedRules(MatchmakingTicket ticket, DateTime currentUtc)
{
double elapsedTime = (currentUtc - ticket.EnqueuedAtUtc).TotalSeconds;
// Exponential expansion for skill tolerance to ensure high-skill players eventually match
double mmrExpansion = Math.Pow(elapsedTime, 1.35) * 4.5;
double calculatedMmrDelta = Math.Min(MaxMmrCap, BaseMmrDelta + mmrExpansion);
// Step-wise discrete expansion for latency tolerance (prevents constant server hopping)
int pingSteps = (int)Math.Floor(elapsedTime / PingStepIntervalSeconds);
int calculatedPingLimit = Math.Min(AbsoluteMaxPingMs, BasePingMs + (pingSteps * 15));
return new DynamicMatchRules
{
MaxAllowedMmrDelta = calculatedMmrDelta,
MaxAllowedPingMs = calculatedPingLimit
};
}
/// <summary>
/// Evaluates whether two tickets can be paired into a match session.
/// </summary>
public bool CanMatchTickets(MatchmakingTicket ticketA, MatchmakingTicket ticketB, DateTime currentUtc, out string selectedRegion)
{
selectedRegion = null;
DynamicMatchRules rulesA = GetRelaxedRules(ticketA, currentUtc);
DynamicMatchRules rulesB = GetRelaxedRules(ticketB, currentUtc);
// 1. Evaluate Skill Delta
double actualMmrDelta = Math.Abs(ticketA.SkillRating - ticketB.SkillRating);
if (actualMmrDelta > rulesA.MaxAllowedMmrDelta || actualMmrDelta > rulesB.MaxAllowedMmrDelta)
{
return false; // Skill variance too wide for current queue age
}
// 2. Evaluate Common Datacenter Ping Compatibility
int lowestCombinedPing = int.MaxValue;
foreach (var (region, pingA) in ticketA.RegionalPingMap)
{
if (ticketB.RegionalPingMap.TryGetValue(region, out int pingB))
{
// Match must satisfy BOTH players' dynamic ping limits
if (pingA <= rulesA.MaxAllowedPingMs && pingB <= rulesB.MaxAllowedPingMs)
{
int combinedPing = pingA + pingB;
if (combinedPing < lowestCombinedPing)
{
lowestCombinedPing = combinedPing;
selectedRegion = region;
}
}
}
}
return selectedRegion != null;
}
}
}
Bu Uygulamanın Önemli Teknik Detayları:
- Asymmetric Rule Satisfaction: Metot, her iki oyuncunun da genişleyen kısıtlamalarına uyulduğunu kontrol eder (
pingA <= rulesA.MaxAllowedPingMs && pingB <= rulesB.MaxAllowedPingMs). Queue'da henüz 2 saniyedir bekleyen yeni bir oyuncu, sırf diğer oyuncu 90 saniyedir bekliyor diye 150ms ping'li bir server'a çekilmez. - Discrete Ping Stepping: Latency sınırları, sürekli eğriler yerine ayrık zaman adımları (
PingStepIntervalSeconds) kullanılarak genişler. Bu sayede her tick döngüsünde gereksiz edge router yeniden atamalarının önüne geçilir. - Spatial Intersection: Eşleştirme, bölgesel haritalar arasındaki dictionary key kesişimlerine dayanır ve toplam gidiş-dönüş latency'si en düşük olan datacenter'ı seçer.
Backend Altyapı Zorlukları: Concurrency, Lock Contention ve Dedicated Server Provisioning
Eşleştirme algoritmalarını izole bir ortamda yazmak nispeten kolaydır. Asıl mühendislik zorluğu, bu sistemi yüz binlerce anlık ticket'ı işleyen dağıtık (distributed) node cluster'ları üzerinde çalıştırdığınızda ortaya çıkar.
[Player Clients]
│ (WebSockets / Low Latency)
▼
[Ingress Load Balancers]
│
▼
[Distributed Ticket Pool (e.g., Redis Cluster / Memory Grid)]
│
┌────┴────────────────────────┬────────────────────────┐
▼ ▼ ▼
[Worker Node 1] [Worker Node 2] [Worker Node 3]
│ │ │
└────┬────────────────────────┴────────────────────────┘
│ (Atomic Claim / Lua Mutex Lock)
▼
[Server Orchestration API] ──► Spin up Agones / Fleet Instances
1. Distributed Ticket Lock Contention
Birden fazla paralel matchmaker prosesi aynı merkezi ticket pool'unu taradığında kaçınılmaz olarak race condition'lar oluşur. İki ayrı worker thread'i aynı anda Ticket #1042'yi değerlendirip onu iki tamamen farklı lobiye eşleştirmeye çalışabilir.
Bunu çözmek için geliştiriciler, bir maç ataması gerçekleştirmeden önce dağıtık primitifler (Redis Lua script'leri veya memory grid atomic operasyonları gibi) kullanarak atomic lock talepleri yürütmelidir. Bir ticket başka bir match worker'ı tarafından kilitlenmişse, thread durumunu anında serbest bırakır ve geri çekilir (backtrack).
2. Yüksek Frekanslı Gerçek Zamanlı İletişim
Matchmaking durum güncellemeleri, gereksiz bağlantı el sıkışmalarında (connection handshake) muazzam bilgi işlem kaynaklarını tüketmeden standart HTTP polling'e dayanamaz. Client'ları tahmini queue süreleri ve dinamik ping aramaları hakkında bilgilendirmek için backend'lerin kalıcı, çift yönlü WebSockets veya uzun ömürlü gRPC stream'leri sürdürmesi gerekir.
Eğer multiplayer durumunuz için verimsiz polling döngülerine güveniyorsanız, gerçek zamanlı backend'lerde Unreal Engine WebSockets için HTTP polling'i nasıl terk edeceğinize dair rehberimize göz atın.
3. Server Allocation Handshake'leri ve Fleet Provisioning
Oyuncuları eşleştirmek mücadelenin yalnızca yarısıdır. Geçerli bir ticket grubu oluşturulduktan sonra:
- Matchmaker, bir Dedicated Server orkestratörü ile (ör. Agones, özel Kubernetes controller'ları) iletişime geçer.
- Seçilen datacenter'da katı bir zaman sınırı içinde (genellikle $< 1500ms$) temiz bir game server instance'ı talep edilmeli veya allocate edilmelidir.
- Server ayağa kalkar (spin up), dinleme UDP portunu bağlar ve IP/Port adres payload'unu döndürür.
- Matchmaker, bağlantı detaylarını tüm client WebSockets kanallarına dağıtır.
Dağıtık ticket pool'ları inşa etmek, lock contention'ı yönetmek, bölge tabanlı socket cluster'larını idare etmek ve Dedicated Server yaşam döngülerini manuel olarak orkestre etmek aylar süren bir altyapı çalışması gerektirir.
İşte bu noktada horizOn ciddi mühendislik yükünü ortadan kaldırır. Redis ticket depolarını bir araya getirmek, özel Agones cluster wrapper'ları yazmak ve server fleet ölçekleme script'lerini yönetmek yerine horizOn, kutudan çıktığı gibi tam yönetilen, ultra düşük latency'li matchmaking queue'ları ve server fleet orkestrasyonu sunar. Siz matchmaking kural setlerinizi yazarsınız; horizOn küresel dağıtımı, atomic ticket locking'i ve otomatik server allocation'ı sorunsuz bir şekilde halleder.
Modern Game Matchmaking Architecture İnşa Etmek İçin 5 En İyi Uygulama
İster yüksek tempolu rekabetçi bir shooter, ister bağımsız bir casual arcade oyunu geliştiriyor olun, sahada test edilmiş bu mimari ilkeleri takip edin:
1. Ticket Gönderiminden Önce Client Ping Vektörlerini Zorunlu Kılın
Datacenter'larınıza olan yakınlığı belirlemek için asla client IP Geo-IP sorgularına güvenmeyin. Geo-IP veritabanları edge routing için oldukça tutarsızdır ve anlık ISP yoğunluklarını göz ardı eder. Enqueue endpoint'ini çağırmadan önce her zaman game client'ını tüm bölgesel endpoint'lere UDP ping probe'ları ile doğrudan latency ölçümü yapmaya zorlayın.
2. Pool Fragmantasyonuna Karşı Önlem Alın
Aktif oyuncu kitleniz bunu net bir şekilde haklı çıkarmadığı sürece küçük oyun modları için ayrı queue'lar oluşturmaktan kaçının. Oyuncu kitlenizi oyun modlarına, harita tercihlerine ve matchmaking katılık queue'larına bölmek pool kalitesindeki düşüşü katlayarak artırır. Bölge başına queue başına düşen aktif CCU'nuz 1.000 oyuncunun altına düşerse, otomatik olarak dinamik tekil queue fallback modlarına geçin.
3. Server Provisioning'i Maç Değerlendirmesinden Ayırın (Decouple)
Matchmaker thread'lerinizin fleet orkestrasyon katmanınızdan asenkron şekilde çalıştığından emin olun. Sanal bir server instance'ının boot etmesini beklerken asla aktif bir matchmaker worker döngüsünü açık tutmayın. Server allocation'ları talep etmek ve instance'lar sağlıklı durum bildirdiğinde bağlantı payload'larını iletmek için bloklamayan (non-blocking) pub/sub mesaj queue'larını kullanın.
4. Akıllı Hibernation ile Atıl Server Maliyetlerini Optimize Edin
Matchmaking, yoğun oyun saatlerinde öngörülemez şekilde artar ve yoğun olmayan saatlerde keskin bir şekilde düşer. Yüzlerce game server instance'ını boşta (idle) çalıştırmak ciddi operational gelir kaybına yol açar. Dinamik fleet warm-up ve server hibernation kalıplarını uygulayın. Atıl server kullanımını optimize etmeye yönelik derinlemesine teknik bir analiz için sıfır atıklı server mimarisi ve Fortnite server optimizasyonu önerilerini incelediğimiz makalemizi okuyun.
5. Yüksek Latency Altında Netcode ve Replication Benchmark'ları Yapın
En gelişmiş matchmaking architecture bile yoğun olmayan saatlerde oyuncuları orta düzeydeki latency farklarıyla ($100-120ms$) eşleştirmek zorunda kalabilir. Server Netcode'unuzun paket gecikmesini sorunsuz bir şekilde kompanse edebilmesi için katı Client Prediction, Lag Compensation ve State Reconciliation kullandığından emin olun. Yüksek ping'li maçlarda client konumlarında takılma veya atlamalar oluyorsa, Unreal Engine multiplayer'da oyuncu konumu desync sorunlarının nasıl çözüleceğine dair rehberimize başvurun.
Özet ve Sonraki Adımlar
Activision'ın Call of Duty: Black Ops 7'de ayrı SBMM, Connection-First ve Hibrit queue'ları sunma kararı, matchmaking mimarisinin oyuncu memnuniyeti için ne kadar kritik olduğunu göstermektedir. Ancak queue'ları bölmek; devasa oyuncu yoğunluğu, düşük latency'li socket ağları, dinamik kural esnetme algoritmaları ve atomic ticket yönetimi gerektirir.
Bir sonraki multiplayer oyununuzu geliştirirken backend altyapısını, socket server'ları ve fleet allocation mantığını sıfırdan yazmak için aylarınızı harcamayın. horizOn'un geliştiricilerin ölçeklenebilir multiplayer oyun backend'lerini, otomatik matchmaking'i ve server orkestrasyonunu dakikalar içinde nasıl yayına almasını sağladığını öğrenin. Backend iş akışınızı hızlandırmak için horizOn'u bugün ücretsiz deneyin veya horizOn dokümantasyonunu inceleyin.