Kembali ke Blog

Rekayasa Hybrid Matchmaking: Bagaimana Pembagian Queue di Call of Duty Mengungkap Arsitektur Game Matchmaking Modern

Diterbitkan pada 24 Juli 2026
Rekayasa Hybrid Matchmaking: Bagaimana Pembagian Queue di Call of Duty Mengungkap Arsitektur Game Matchmaking Modern

Ringkasnya

Artikel ini membahas tantangan backend rekayasa game matchmaking architecture modern seperti yang diterapkan pada pembagian queue Call of Duty: Black Ops 7. Penulis membedah trilema matchmaking antara latency, skill delta, dan queue duration serta menyajikan implementasi algoritma ekspansi aturan dinamis menggunakan C#. Artikel ini juga memberikan praktik terbaik dalam mengatasi masalah lock contention terdistribusi, fragmentasi pool pemain, hingga orkestrasi dedicated server berskala besar.

Ketika Activision mengumumkan bahwa Call of Duty: Black Ops 7 akan membagi basis pemainnya ke dalam tiga queue matchmaking terpisah—Skill-Based Matchmaking (SBMM), Classic Connection-Based, dan Hybrid—hal ini membawa debat rekayasa backend yang sudah lama ada ke garis depan. Bagi game kompetitif, menentukan cara memasangkan pemain bukan sekadar preferensi desain game; ini adalah masalah game matchmaking architecture rumit yang menyeimbangkan batasan jaringan sub-milidetik, variansi skill matematis, fragmentasi pool, dan biaya compute cloud.

Membagi sistem matchmaking Anda menjadi beberapa queue terpisah sekilas terdengar seperti fitur preferensi pemain yang sederhana. Pada kenyataannya, hal ini melipatgandakan atau melipattigakan overhead rekayasa pada infrastruktur backend Anda. Saat Anda membagi basis pemain bersamaan (CCU) ke dalam queue yang terpisah, kerapatan tiket melonjak turun, queue time membengkak secara eksponensial di wilayah berdensitas rendah, dan algoritma alokasi server menghadapi churn yang lebih tinggi.

Dalam artikel ini, kita akan menganalisis trade-off teknis antara SBMM versus connection-first matchmaking, membedah matematika di balik ekspansi queue hybrid dinamis, memeriksa kode C# backend nyata untuk pemrosesan tiket, dan mengeksplorasi cara membangun pool matchmaking tangguh yang dapat di-scale dengan rapi.


Trilema Matchmaking yang Tak Terubahkan

Setiap arsitektur game matchmaking modern harus menyelesaikan masalah optimasi batasan (constraint optimization) yang terikat oleh tiga variabel yang saling bersaing:

  1. Latency (RTT): Waktu round-trip antara client pemain dan instance dedicated server yang dialokasikan (diukur dalam milidetik).
  2. Skill Delta ($\Delta$MMR): Kesenjangan matematis dalam representasi skill (MMR, Elo, atau TrueSkill) antar pemain dalam sebuah lobby.
  3. Queue Duration ($T_{queue}$): Total waktu yang dihabiskan pemain dalam posisi menunggu (idle queue friction) sebelum tiket match yang valid bertransisi menjadi alokasi server aktif.
                    Latency (RTT)
                      /       \
                     /         \
                    /   Ideal   \
                   /    Match    \
                  /               \
Skill Delta (ΔMMR) --------------- Queue Duration (T_queue)

Anda dapat dengan mudah mengoptimalkan dua dari variabel ini dengan mengorbankan variabel ketiga sepenuhnya:

  • Latency Rendah + Skill Delta Rendah: Menghasilkan queue time yang lama karena engine harus mencari pemain langka dengan skill yang pas dan juga bertempat tinggal dekat dengan datacenter cloud yang sama.
  • Queue Time Rendah + Skill Delta Rendah: Menghasilkan latency tinggi karena matchmaker harus memperluas radius pencarian geografisnya ke seluruh dunia untuk menemukan lawan dengan skill seimbang.
  • Queue Time Rendah + Latency Rendah: Menghasilkan variansi skill yang tinggi (pengalaman match publik "connection-first" yang klasik) karena matchmaker langsung mengambil client terdekat yang tersedia tanpa memedulikan metrik performa.

Ketika game seperti Black Ops 7 memperkenalkan tiga mode queue terpisah, sistem memaksa arsitektur matchmaking di bawahnya untuk mempertahankan tiga loop evaluasi aturan secara paralel di atas pool memori yang terfragmentasi.

Jika jumlah Concurrent Users (CCU) Anda di wilayah tertentu—misalnya, Amerika Selatan pada pukul 4 pagi—turun di bawah 2.000 pemain aktif, membagi para pemain tersebut ke dalam tiga pool terpisah akan mengikis densitas lokal untuk setiap queue menjadi hanya beberapa ratus pemain. Akibatnya, queue connection-first gagal menemukan dedicated server ber-ping rendah, dan queue SBMM menjadi macet (stall) secara tidak terbatas.


Membedah SBMM vs. Ping-First vs. Queue Hybrid

Untuk membangun backend yang mampu menangani jutaan tiket match, Anda harus terlebih dahulu memahami cara kerja masing-masing model arsitektur di balik layar.

1. Arsitektur Connection-Based (Ping-First)

Dalam engine connection-first, matriks skill sepenuhnya menjadi sekunder atau diabaikan. Tujuan utamanya adalah meminimalkan degradasi jaringan (jitter, packet loss, RTT tinggi).

  • Client Ping Probing: Saat membuka queue, game client mengirimkan ping beacon ICMP atau UDP ke serangkaian edge gateway regional (misalnya, us-east-1, eu-central-1, ap-southeast-1).
  • Generasi Ping Vector: Client menyusun vektor latency: [ us-east: 24ms, us-west: 78ms, eu-central: 142ms ] dan melampirankannya pada payload matchmaking.
  • Spatial Indexing: Matchmaker mengelompokkan pemain secara ketat ke dalam hash wilayah berdasarkan ambang batas latency yang dapat diterima (misalnya, $RTT < 50ms$).

Karena topologi jaringan menentukan pembuatan match, bucket pencarian pemain bersifat terprediksi, memungkinkan tiket diselesaikan dalam waktu $O(1)$ menggunakan queue spasial FIFO (First-In, First-Out) yang sederhana.

2. Arsitektur Skill-Based Matchmaking (SBMM)

SBMM memprioritaskan keadilan match dengan memodelkan kemampuan pemain menggunakan distribusi Gaussian multidimensi (misalnya, TrueSkill 2) atau varian Elo yang disesuaikan. Input utamanya mencakup rasio win/loss, rasio kill/death, damage per minute, dan rekam jejak performa terkini.

  • Evaluasi Jarak: Matchmaker menghitung jarak Euclidean atau Mahalanobis antara vektor pemain kandidat dalam ruang skill $N$-dimensi.
  • Biaya Sorting: Matchmaker tidak bisa mengandalkan queue FIFO sederhana. Mereka harus mempertahankan sorted set atau pohon spasial (seperti KD-tree) dari profil tiket untuk dengan cepat menemukan kandidat dalam variansi skill $\sigma$ yang dapat diterima.
  • Pengecilan Search Space: Seiring meningkatnya skill (misalnya, 0,5% pemain teratas), pool kandidat yang memenuhi syarat menyusut secara drastis. Hal ini memaksa sistem untuk menahan tiket secara tidak terbatas atau secara perlahan melonggarkan parameter ketatnya skill.

3. Arsitektur Dynamic Hybrid

Alih-alih memaksa pemain ke dalam pilihan queue yang di-hardcode, backend produksi modern sering kali mengimplementasikan model Dynamic Hybrid. Dalam skenario ini, setiap tiket match dimulai dengan batas SBMM yang ketat dan latency yang rendah. Seiring meningkatnya $T_{queue}$, fungsi rule decay secara kontinyu memperluas skill delta ($\Delta MMR$) dan batas latency ($RTT_{max}$) yang dapat diterima...

$$\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)$$

Di mana $\alpha$ dan $\beta$ adalah koefisien ekspansi, $\gamma$ mengontrol kecuraman kurva eksponensial, dan $t$ adalah durasi queue yang telah berlalu dalam detik.

Dengan memanfaatkan relaksasi dinamis, Anda mencegah queue hang yang tak terbatas sambil tetap menjaga kualitas match yang tinggi selama periode puncak CCU.


Implementasi Kode: Engine Ekspansi Aturan Dinamis

Berikut adalah implementasi C# teruji dari engine ekspansi aturan matchmaking dinamis. Layanan ini mengevaluasi tiket masuk terhadap pool queue aktif, menghitung matriks kompatibilitas ping secara real-time dan batas variansi MMR dinamis.

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;
        }
    }
}

Aspek Teknis Utama dari Implementasi Ini:

  • Pemenuhan Aturan Asimetris: Metode ini memastikan bahwa batasan ekspansi kedua pemain dihormati (pingA <= rulesA.MaxAllowedPingMs && pingB <= rulesB.MaxAllowedPingMs). Pemain baru yang berada di queue selama 2 detik tidak akan terseret ke server ber-ping 150ms hanya karena pemain lain sudah menunggu selama 90 detik.
  • Discrete Ping Stepping: Batas latency meluas menggunakan discrete time step (PingStepIntervalSeconds), bukan kurva kontinu. Hal ini menghindari re-assignment edge router yang tidak perlu pada setiap tick loop.
  • Spatial Intersection: Pemasangan mengandalkan interseksi key dictionary di seluruh map regional, memilih datacenter dengan kumulatif round-trip latency terendah.

Tantangan Infrastruktur Backend: Concurrency, Lock Contention, dan Dedicated Server Provisioning

Menulis algoritma match secara terisolasi memang sederhana. Kesulitan rekayasa yang sebenarnya muncul ketika Anda menjalankan sistem ini di seluruh kluster node terdistribusi yang menangani ratusan ribu tiket bersamaan.

[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. Lock Contention Tiket Terdistribusi

Ketika beberapa proses matchmaker paralel memindai pool tiket pusat yang sama, race condition tak terhindarkan. Dua worker thread terpisah dapat mengevaluasi Tiket #1042 secara bersamaan dan mencoba memasangkannya ke dalam dua lobby yang sepenuhnya berbeda.

Untuk mengatasi hal ini, developer harus mengeksekusi atomic lock claim menggunakan primitif terdistribusi (seperti script Redis Lua atau operasi atomik memory grid) sebelum mengeluarkan match assignment. Jika sebuah tiket dikunci oleh match worker lain, thread tersebut segera melepaskan statusnya dan mundur (backtrack).

2. Komunikasi Real-Time Frekuensi Tinggi

Update status matchmaking tidak dapat mengandalkan HTTP polling standar tanpa membuang sumber daya compute yang besar untuk handshake koneksi yang sia-sia. Untuk menjaga client tetap terinformasi tentang estimasi durasi queue dan pencarian ping dinamis, backend harus mempertahankan WebSockets dual-channel yang persisten atau gRPC stream yang long-lived.

Jika saat ini Anda mengandalkan polling loop yang tidak efisien untuk status multiplayer Anda, lihat panduan kami tentang cara ditch HTTP polling for Unreal Engine WebSockets in real-time backends.

3. Server Allocation Handshake & Provisioning Fleet

Memasangkan pemain barulah separuh dari perjuangan. Setelah grup tiket yang valid terbentuk:

  1. Matchmaker menghubungi dedicated server orchestrator (misalnya, Agones, kustom Kubernetes controller).
  2. Instance game server yang bersih harus diklaim atau dialokasikan di datacenter terpilih dalam tenggat waktu yang ketat (biasanya $< 1500ms$).
  3. Server menyala (spin up), mengikat UDP listening port-nya, dan mengembalikan payload alamat IP/Port.
  4. Matchmaker mengirimkan detail koneksi ke semua client WebSocket.

Membangun pool tiket terdistribusi, menangani lock contention, mengelola socket cluster berbasis wilayah, dan mengorkestrasi siklus hidup dedicated server secara manual memerlukan pekerjaan infrastruktur berbulan-bulan.

Di sinilah horizOn mengeliminasi overhead rekayasa yang berat. Alih-alih merakit Redis ticket store, menulis wrapper kluster Agones kustom, dan mengelola script scaling fleet server, horizOn menyediakan queue matchmaking ultra-low-latency yang terkelola sepenuhnya serta orkestrasi fleet server langsung out of the box. Anda menulis rule set matchmaking Anda; horizOn menangani distribusi global, atomic ticket locking, dan alokasi server otomatis secara mulus.


5 Best Practice untuk Membangun Game Matchmaking Architecture Modern

Baik Anda sedang membangun competitive shooter berisiko tinggi atau game indie casual arcade, ikuti prinsip-prinsip arsitektur teruji berikut:

1. Wajibkan Client Ping Vector Sebelum Submission Tiket

Jangan pernah mengandalkan Geo-IP lookup pada IP client untuk menentukan kedekatan dengan datacenter Anda. Database Geo-IP sangat tidak akurat untuk edge routing dan mengabaikan kongesti ISP secara real-time. Selalu paksa game client untuk mengukur latency langsung via UDP ping probe ke seluruh endpoint regional sebelum memanggil endpoint enqueue.

2. Lindungi Sistem dari Fragmentasi Pool

Hindari membuat queue terpisah untuk mode game minor kecuali jika basis pemain aktif Anda benar-benar membenarkannya. Membagi basis pemain Anda ke dalam berbagai mode game, preferensi map, dan queue ketatnya matchmaking memperparah degradasi pool. Jika CCU aktif per queue Anda turun di bawah 1.000 pemain di suatu wilayah, beralihlah secara otomatis ke mode fallback single-queue dinamis.

3. Pisahkan Provisioning Server dari Evaluasi Match

Pastikan thread matchmaker Anda beroperasi secara asinkron dari layer orkestrasi fleet Anda. Jangan pernah menahan worker loop matchmaker aktif tetap terbuka saat menunggu instance server virtual melakukan boot. Manfaatkan pub/sub message queue non-blocking untuk meminta alokasi server dan mengirimkan payload koneksi ketika instance melaporkan status sehat.

4. Optimalkan Biaya Idle Server dengan Hibernasi Cerdas

Lonjakan matchmaking terjadi secara tak terduga selama jam sibuk pemain dan turun drastis di luar jam sibuk. Membiarkan ratusan instance game server dalam kondisi idle tanpa pemain membuang pendapatan operasional yang signifikan. Implementasikan pola warm-up fleet dinamis dan hibernasi server. Untuk analisis teknis mendalam tentang mengoptimalkan penggunaan idle server, baca artikel kami tentang architecting zero-waste servers and Fortnite server optimization proposals.

5. Benchmark Netcode dan Replikasi di Bawah Latency Tinggi

Bahkan arsitektur matchmaking paling canggih sekalipun sesekali akan memasangkan pemain di lintas jarak latency moderat ($100-120ms$) pada jam-jam sepi. Pastikan netcode server Anda memanfaatkan client prediction, lag compensation, dan state reconciliation yang kuat untuk bertahan dari delay paket secara mulus. Jika posisi client mengalami tearing atau melompat selama match ber-ping tinggi, konsultasikan panduan kami tentang how to fix player location desync in Unreal Engine multiplayer.


Ringkasan & Langkah Selanjutnya

Keputusan Activision untuk menawarkan queue eksplisit SBMM, Connection-First, dan Hybrid di Call of Duty: Black Ops 7 mengilustrasikan betapa krusialnya arsitektur matchmaking bagi kepuasan pemain. Namun, membagi queue memerlukan densitas pemain yang luar biasa, jaringan socket low-latency, algoritma dynamic rule decay, dan penanganan tiket atomik.

Jika Anda sedang membangun game multiplayer berikutnya, jangan buang waktu berbulan-bulan menulis infrastruktur backend, socket server, dan logika alokasi fleet dari awal. Pelajari bagaimana horizOn memberdayakan developer untuk mengodeploy backend game multiplayer yang scalable, matchmaking otomatis, dan orkestrasi server dalam hitungan menit. Coba horizOn secara gratis hari ini atau jelajahi dokumentasi horizOn untuk mempercepat workflow backend Anda.


Source: Call of Duty: Black Ops 7 will very soon offer three different matchmaking systems, and you'd be right to be confused