Multiplayer Oyun Geliştirirken Bilmeniz Gerekenler — Bölüm 2

Oğuzhan Yılmaz
Mage Games
Published in
7 min readJul 10, 2023

--

Birinci bölümde çok oyunculu sistemlerdeki kavramları tanımlamış, ağ topolojilerine yer vermiş ve kullanılan protokollerden bahsetmiştik. Bu bölümde biraz daha pratik bilgilerden bahsedeceğiz.

Konumuz İnternet üzerinden oynanan oyunlar olduğundan, ilk başta oyunu üzerinde koşturacağımız İnternet denen ağın acısıyla tatlısıyla nasıl çalıştığını kavramamızın iyi olacağını düşünüyorum 🪩 🕺

Bir Paketin Hikayesi

İnternet katmanlarını kitap gibi tek tek anlatmaktansa şu bizim Latency yaratan paketlerimizin kayıp balık Nemo misali macerası üzerinden ilerlesek daha çok eğleniriz gibi geliyor. Olayı hikayeleştirmeye çalışayım 👇

Bir heves cep telefonunuzdan Multiplayer bir FPS oyun açtınız. Direkt Team Deathmatch’a girip en yüksek skoru yapıp (CoD’u severim) kapatacağız. Cep Telefonunuz yerel ağınızdaki bir Wifi Access Point’ine bağlanmış ve yerel Ağ’da bulunan Router (modem), DHCP protokolü ile size IP adresi ve DNS sunucusu/ları atamış. İnternete çıkabiliyoruz, isim (Hostname) çözebiliyoruz! 💃

Oyunumuz ilk açıldığında belirli bir Hostname üzerinden Game Server’a bağlantı isteği göndermek için hazırlanır. Oyunun içindeki HTTP/S kütüphanesi server.cod.com gibi bir Hostname’e giriş (Login) isteğini oluşturuyor ve istek OS’un Kernel’ine iletiliyor. Hemen OS’un DNS istemcisi server.cod.com’un hangi IP adresinde çalıştığını öğrenmek için UDP protokolünü kullanarak DHCP’nin atamış olduğu DNS (Domain Name System) sunucularına (Örneğin: 8.8.8.8, 4.2.2.2) bir sorgu gönderiyor ve IP adresini A record üzerinden alıyor. Kernel artık hangi IP adresine socket açacağını biliyor ve gerekli bağlantıyı sağlayıp veri iletimine geçmek için TCP/IP seromonisini başlatıyor.

O sırada İstemcimiz TCP’nin Application katmanına HTTP 1.1 protokolüne uygun (Oyunun protokolünü HTTP var sayıyorum) bir Payload oluşturuyor. Payload’ın içine de USER_ID ve gizli bir kaç parametre de var. (bir JSON model olduğunu düşünelim)

Payload oluşturulduktan sonra oyunun içinden açılan bir Socket nesnesi ile Mobile işletim sisteminin Kernel’ine iletiliyor.

Kernel bu isteği alıyor ve Cep Telefonunun Network Interface’ine gönderiyor ve chipset paketi işliyor. NIC fiziksel olarak hangi MAC’de çalıştığını ve diğer uçta olan diğer fiziksel MAC’i (yani kablonun takılı olduğu diğer jack…) ARP sayesinde biliyor o nedenle gelen Paketi direkt ilk fiziksel MAC’e gönderiyor. Bu MAC genelde modem oluyor ve bir WAN IP adresi yani gerçek bir IPv4 almış oluyor. IP katmanından Paketin hedef IP adresine bakıyor ve ilgili bir sonraki MAC’e yönlendiriyor. Artık paket yerel ağımızdan İnternet Servis Sağlayıcının (SOL veya TT gibi) ağına geçti.

gibi…

Şimdi burada işin içine BGP (Border Gateway Protocol) giriyor. Servis Sağlayıcı, hedef IP adresinin hangi ağ üzerinden anons edildiği ASN (Autonomous System (AS) Numbers) sayesinde belirliyor ve BGP Routing Tables ile de Route Path’i en ucuz veya en kısa yoldan ayarlayıp bir sonraki Hop’a paketi atıyor bu da başka bir İnternet Servis Sağlayıcısı ise, aynı şeyi tekrar edip IP adresini Anons eden Router’a yönlendiriyor bu olay paket’i IP’nin sahibi Router’a iletilene kadar devam ediyor. Paket, IP adresini Anons eden ağa geldiğinde ise bu Router üzerinden iç ağdaki ilgili sunucuya yönlendiriliyor. Böylece paket ulaşmış oluyor ama daha bitmedi…

A Survey of BGP Security Issues and Solutions

Dedicated Game Server, sahip olduğu Ethernet kartının chipset’inden paketi Kernel’e iletiyor. Kernel gelen protokole’ün içinden Port’u çözüyor ve User Space’de çalışan Game Server’ın Port’una Paketi teslim ediyor.

Game Server, Paketi aldıktan sonra Protokolün Application katmanındaki veriyi açıyor (Burası önemli. İleride daha detaylı değineceğiz) uygulamanın ilgili objelerine değerlerini atıp (Marshalling/Deserialization) Logic’i çalıştırıyor. Logic dediğim istemci zıplamaya mı basmış veya ateş mi etmiş vs. gibi aksiyonlar. Bu girdiler sunucuya alınıyor ve diğer istemcilere iletiliyor ve bu olay eğer oyun 30FPS onanacak ise 16ms de bir tekrarlanıyor.

😓

Aşağıda ki grafik katmanları güzel özetlemiş… 👇

OSI Reference Model Layers

Paketin yerine ulaşmak için yaşadığı tüm bu macera gerçekten heyecan verici. Dikkat ederseniz uygulama olarak kontrol edebileceğimiz pek bir alan yok ama nasıl bir yelkenli ile giderken rüzgara uyum sağlıyoruz. Uygulamalarımızı da İnternet’in rüzgarına göre uyumlu hale getirebiliriz.

Oyunumuzun İnternet ile uyumlu çalışabilmesi için bazı gerçekleri kucaklamamız, benimsememiz hatta onlarla yaşamamız gerekir. Bunların en önemlilerini aşağıda sıralamaya çalıştım…

Ağ Homojen Değildir:
Heterojendir! 🤗

Etrafımızda bir çok cihaz var ve bu cihazların farklı farklı ağ kuralları var. Örneğin; Windows işletim sistemlerinde TTL (Time To Live) değeri 128 dir, Linux’de ise 64. Yani Client-Server arası iletişim 70 Hop ise Linux makine üzerinden gönderdiğiniz paket gitmeyecektir.
Bunun gibi birlikte çalışabilirliğe zarar verecek onlarca parametre var o nedenle standartlaşmış protokoller, modeller kullanmaya dikkat etmek tasarımlarınızda öncelikli olmalı. Ne kadar özel iş akışı ve protokol, o kadar uyumsuzluk yaratır.

Ağ Kararlı Değildir

Kaotiktir! 🤗

Ağ üzerinden gönderdiğiniz bir paket yerine ulaşmayabilir 🤷‍♂️, HTTP isteğiniz timeout’a düşebilir bunlar çok normaldir. Önemli olan bu senaryolara dayanıklı tasarımlar yapmamızdır.na
Örneğin, bir HTTP isteğinin fail olduğunu anlayıp tekrar deneyeceğimiz fonksiyonları tasarımımıza eklemeliyiz. Gerekirse Exponential Backoff ve hatta gerekirse Circuit Breaker gibi teknikler kullanmalıyız. Belki timeout’larımızı bir kaç saniye daha bekleyecek şekilde ayarlamalıyız. Bu değerleri siz kullanıcılarınıza göre optimize etmelisiniz bir nevi İnternet rodaj süresi gibi düşünün.

Bu fotoğrafı bizim FARR 35 teknesinde çekmiştim. Burada kullanacağımı tahmin etmiyordum :)

Transfer’in Maliyeti Yoktur

Vardır! 🤗

Ürettiğimiz verileri ağ üzerinden taşımak maliyetlidir o nedenle gönderip aldığımız her paketi bilmeliyiz ve maliyet hesabına katmalıyız. Maliyetten kastım aslında verinin oluşturulması ve taşınması sırasındaki işlemler.

Hepimizin bildiği gibi oyun içinde kullandığımız bir Ağ nesnesini (DTO gibi) paket haline getirmek için Serialization işlemi gerekiyor, gerçek dünyada ise bunun arasına bir de Encryption işlemi giriyor. Tahmin edeceğiniz üzere bu işlemler hatırı sayılır bir CPU gereksinimi duyar. Diğer bir deyişle işlem gücü! bir başka deyişle para!
İstemci tarafında problem değil fakat Hyper Scale sistemlerde koşan Dedicated Game Server’ımız Computing Time’a göre ücretlendirdiğini hatırlamamız gerekiyor.

Bu alan kontrol edebileceğimiz bir katman olduğundan mümkün olduğunda optimize edilebilir. Buraya özel zaman ayırmaktan çekinmeyin.

Not: Bu bölümde Peter Deutsch’un meşhur Fallacies of Distributed Computing maddelerinden esinlendim. Ha unutmadan! Peter’in ilk yazısı 7 maddeymiş sonradan James Gosling 8. maddeyi eklemiş. Trivial bilgi severim :)

En yakın değil, En ucuz!

Oyunumuzun İnternet üzerinde koşması ile ilgili bir tasarım yaparken coğrafi düşünmeye eğilimli oluruz ama aslında İnternet coğrafi değil karasal ve deniz kablolarının durumuna göre çalışır. Tabiki Türkiye’ye hizmet vermek için İstanbul’da bir sunucunuzun olması avantajlıdır ama ISP’niz bu avantajı ortadan kaldıracak hareketler yapabilir.

İnternet üzerinde trafik en yakın yoldan değil, en ucuz yoldan gider.

Örneğin Türkiye’mizde İstanbul’a bir Game Server konumlandırdık ve oyuncularımızın ortalama 20ms Latency ile sunucuya bağlanmasını sağladık çok güzel. Derken, bir gün Latency ortalamamız 50ms’ye yükseldiğini fark ediyoruz. Biraz inceledikten sonra İzmir’den belirli bir ISP’den bağlanan kullanıcıların Latency’lerinin ortalamayı yükselttiğini fark ediyoruz.
Hemen İzmir’den Game Server’ımıza bir traceroute komutu çalıştırıyoruz ve istemcinin Game Server’ımıza ulaşmak için geçtiği yolların İstanbuldan değil Ankara’dan döndüğünü görüyoruz. Ortalamayı yükselten olay bu Route Change.

Gördüğünüz gibi daha iyi online oyun deneyimi sunabilmek için elimizde olmayan bu topolojik değişikliklerini yakalayacak hassas izleme ve ölçme sensörlerimizin olması gerekiyor ki doğru karaları daha fazla alalım.

www.submarinecablemap.com

Sınırlarımız

Oyunlarımızda paketlerimiz oldukça optimize etmeye özen gösteriyoruz. Bunun sonucunda mümkün olduğunda düşük paket boyutlarına ulaşabiliyoruz ama küçük olması daha hızlı gideceği anlamına gelmiyor.
Bu aşamada hızımızı küçükde olsa donanımsal sınırların etkilediğini de göz önüne almak gerekebilir. Siz protokolünüzü ne kadar iyi ve optimum tasarlamış olsanız da paketin bir cihazdan diğerine gönderilmesinin asgari bir sınırı vardır.

Device Latency!

Bazen bu gecikmeleri hesaplayıp DGS konumlandırmalarını daha iyi planlayabilmek için temel bazı hesaplamaları göz önüne almak yardımcı olabiliyor.
Kabaca fikir sahibi olmamız adına konumlandırdığımız sunucumuza paketimizin ne kadar zamanda gideceğini, kaç km gezdiğini bilmek Local ISP seçiminde yardımcı olabiliyor. Kabaca aşağıdaki gibi ön tanımlı değerlerle yapacağımız hesaplamalar bize yardımcı olacaktır.

  1. Işığın boşluktaki hızı 3E5 km/s
  2. Işığın fiberdeki hızı, ışığın boşluktaki hızının kabaca %66'sıdır yani 3E5 * 0.66 = 1.98E5 km/s
  3. Paket single mode fiber’de 4.9µs (mikrosaniye) de 1 kilometre gider.

Örneğin:
Sunucumuza 20ms gecikmemiz olan bir ortamdayız. Bu gecikmenin ne kadarı cihazlar arası gecikme, bulmak için öncelikle paketin fiber içinde kaç km gittiğini bulmak lazım.

20ms * 1000ms (1s) * 1.98E5 km/s = 3.960 Km

Paketimiz fiber kablo içnde 3.960 km yol yaparak Game Server’ımıza ulaşıyor. Kilometre başına 4.9µs olduğunu biliyoruz. (Hesaplamalarda genelde 5µs tercih edilir)

3.960Km/5µs=792µs yani yaklaşık 1ms Device Latency’miz var diyebiliriz. Yani 19ms Hardware + Application katmanındaki olaylar. Şimdi DGS’yi konumlandırmaya karar verdiğimi yerel ISP’lerden ikisi aynı lokasyonda olmasına rağmen birinin Device Latency’si 1ms diğerinin ise 4ms bunun dolayısıyla karar verirken destekleyici bir unsur olabiliyor bu ölçüm.

Kapanış

Tüm bu İnternet cilveleri ile karşı karşıya kaldığımızda insanın gerçekten tüm ipleri ele alıp kendi ağını kurup işletmesi mantıklı geliyor. Esas önmeli olan ağ da entropiyi düşürmek, bunun içinde kendi kurallarınızın çalıştığı ağlar yaratıp istemcinin paketini mümkün olan en kısa yoldan bu ağa taşıyarak avantaj elde edilebilir…

Üçüncü bölümde artık oyuncuya yaklaşıp algoritmalara gireceğiz, oyunumuzu internet ortamına nasıl uyduracağımız ile ilgili hilelere birlikte bakacağız. Görüşmek üzere… 🍻

Ek okumalar;

--

--