Oyunlar, Networking ve Cloud

July 06, 2022

Selamlar,

Daha önce bilgimin kısıtlı olduğu, derinlemesine öğrenmek istediğim bu konu hakkında bir süredir araştırma yaptığım için aklımda kalan bilgilerden bazılarını paylaşmak istedim.

Tabii bu yazı özelinde de tüm detaylara değinmek mümkün değil zira üzerine kitap yazılabilecek kadar derin ve alengirli bir alan.

Kadından erkeğine, gencinden yaşlısına, müslümanından pastafaryanına kadar günümüzde en az bir online oyun ile tecrübe yaşamış kişi sayısı gittikçe artmakta. Oyunların hazırlanış süreciyle ilgili olarak teknik dünyadan olmayan faniler en fazla “lan nasıl yapıyorlar bunları ya?” diye düşünürken, işin mutfağından olan kişiler de genelde “lan nasıl yapıyorlar bunları ya?” şeklinde tepki veriyor.

o1

Bu yazı her ne kadar oyun yapımına dair süreçlerle ilgili bir bilgi kapsamayacak olsa da, hayatında en azından bir kereliğine de olsa Half Life veya Counter Strike oynamış bireyleri ilgilendirebilecek; “AWP’yi (4-6) seçtim, sağ tıkladım zoom açıldı, ateş ettim, peki bu süre boyunca neler yaşandı da binlerce kilometre ötede yaşayan birisinin kontrol ettiği sanal terörist saniyesinde ölüverdi?” sorusuna az da olsa ışık tutmaya çalışacak.

İlk olarak network mimarilerini tanıyalım.

P2P (Peer-to-Peer) vs CS (Client-Server)

Aslında peer-to-peer mantığını, teknik detaylarını bilmese bile (aklına ilk olarak Limewire gelenler like) çoğu kişi duymuştur. P2P mimarilerde oyun içindeki veri akışı oyuncular arasında gerçekleşir. Client-Server mimarisinde ise tahmin ettiğiniz üzere veri alışverişi oyuncuyla ana sunucu arasındadır.

Peki mimari neye göre seçiliyor?

Aslında ikisinin de avantajları ve dezavantajları mevcut. Mesela P2P mimarisinde bir ana sunucuya ihtiyaç olmadığı için en basitinden masraf konusunda avantajlı olunuyor, fakat bu yapıda da veri akışı bir merkezi sunucuya uğramadığı için hileyle baş etmesi yerine göre imkansız bir hal alabiliyor. Client-Server mimarisinde ise hile konusu üzerinde çok düşünülmesi gereken bir konu olmaktan çıktığı gibi (elbette istisnaları mevcut), ölçeklenebilirlik ve gecikme hızı konusunda da (senaryoya göre) avantaj sağlanabiliyor. Tabii birden çok oyuncunun yer aldığı online oyunlarda bir sunucu üzerinden trafiği sağlamak kesin olarak gecikme hızını -latency- çözecek diye bir şey yok. En basitinden sunucunun bulunduğu coğrafya, ülke, bölge gibi faktörler oyuncuların sunucu veya sunuculara olan uzaklığıyla da doğrudan ilişkili. Bu noktada oyunculara en iyi performansı sağlayabilmek adına mesh topolojisinin kullanıldığı bir backbone bağlantısının kullanılması elzem olabiliyor. Bu da bizi para - çokomel eğrisine getiriyor. Haliyle günümüzde belirli bir başarıyı yakalamış indie oyun yapımcılarının neden cloud sağlayıcılarından hatırı sayılı miktarda kredi alabildiğini de anlıyoruz.

o2

leavemealone

Hile konusunda ufak bir parantez açmak istiyorum. Cheat Engine’i bilenler bilir, özellikle zaman bazlı değişikliklerde browser tabanlı oyunlarda hile yapılmasına olanak sağlıyor. Bunu mobil cihazlarda süre karşılığı kredi veren oyunların cihaz tarihini ileriye aldıktan sonra kredilerin dolmasına benzetebiliriz. CE’i ilk defa bu tip bir amaçla kullanan kişiler, bunun her oyunda işe yaramadığını gördükten sonra “uff niye olmuyo ya” tribine girerler. Mesela mobilde veya tarayıcıda oynanan bir oyunun bilgileri localde tutuluyorsa CE ile kaynaklara veya süreye müdahale etmek problem olmuyor. Ancak oyun bilgilerini backend tarafında dinamik olarak tutan ve bunu ana sunucu üzerinden servis eden bir oyundan bahsettiğimizde, her ne kadar CE kaynaklara müdahale etse de, saniyesinde otomatik olarak verilerin düzeldiğini veya en kötü sayfa yenilendiğinde orijinal haline geldiğini görüyoruz.

Veri yolculuğu

Peki, dağıtmadan az önceki soruya dönelim. Online bir oyunda hedefi seçtiniz ve ateş ettiniz, bu sırada neler oldu? Aslında şu şekilde özetlemek mümkün:

  • Mouse’a tıklandığında (klavye tuşlaması da olabilir) OSI katmanının fiziksel aşaması başlar, yapılan eylemin 0 ve 1’ler dünyasındaki karşılığı elektrik sinyallerine çevrilir ve aynı şekilde router’a ulaşır.
  • Data Link aşamasından (buranın detayına girmiyorum) sonra oyuncunun kullandığı ISP üzerindeki hop noktaları vasıtasıyla veri paketi oyun sunucusuna ulaşmak üzere yola çıkar.
  • Bu yolculukta Transport katmanında TCP ya da UDP protokolü kullanılarak veri yolculuğu sağlanır ki burada ufak bir dipnot eklemem gerekiyor; QoS ve QuE kavramları özellikle performans konusunda bu aşamada kullanılabilecek yapılardır.
  • Diğer katmanların veri paketiyle olan iletişimleri de tamamlandıktan sonra paket oyun sunucusuna varır ve tüm bunlar gerçekleştikten sonra oyuncunun ekranında belki skor bildirimi görülür belki de rakip /all zaaaa xd yazar, bilemeyiz.

o5x

Diğer OSI katmanlarının detaylarına bu yazıda girmeyeceğim. Ben yukarıda tek bir paket gibi betimlesem de, aslında client ve server arasında saniyede yaklaşık 25-30 paket gidip gelmektedir.

Ek olarak şunu da bilelim; aslında oyuncunun envanter bilgisi, silah seçildiğinde gerçekleşen animasyon, X silahı için bir mermi sıktıktan sonra ikincisinin ne zaman yapılabileceği bilgisi gibi farklı tipte değişkenlerin durumu sunucudan client’a aktarılır ve buradan kullanılır. Envanter bilgisinin tutulması gibi görece statik bilgilerden ziyade eyleme dayalı durumlarda gecikme hissiyatının minimize edilmesi yine networkingi ilgilendiren konulardan sadece birisidir.

Veri akışını biraz daha açmak gerekiyor çünkü oyunlardaki network mimarisinde aslında iki tip veri söz konusu. Kullanıcıdan bir input alındığında ki bu sadece tetiğe basılması veya zıplama gibi bir eylem değil de harita içerisinde yer değiştirmek de olabilir, mesela yer değişikliğinde oyuncu bu bilgiyi sunucuya iletir, sunucu da aynı şekilde bunu oyundaki diğer kullanıcılara aktarır. İkinci durum ise aynı oyuncunun bu hareketinden sonra diğer oyuncuların haritadaki yerlerinin ilk kullanıcıya göre olan güncelleme bilgisidir. İkisi arasındaki fark; ilk veri tipinde oyuncu pozisyonunu diğer oyuncular aynı şekilde alırken, ikincisinde oyuncuların tamamı farklı bir matematiksel konumu işaret edeceği için buradaki hesaplama da ayrı yapılır.

Bu iki durumun arasında farklı bazı noktalar da mevcut, oyun tipine göre de değişiklik gösteren bir olay. P2P vs CS modellerine veri tiplerinin gönderim şekli costing açısından fark yaratabiliyor. Çünkü CS modelinde oyuncuların tamamından bilgiyi alıp bunu işleyerek göndermek P2P’ye göre daha masraflı hale geliyor.

İnterpolasyon ve Ekstrapolasyon

Anlık olarak diğer oyuncuların haritadaki durum bilgilerinin hedef oyuncuya dönmesi aslında yazıldığı kadar basit bir olay değil. Hatta oyuncularla birlikte objelerin de anlık konum ve durum bilgilerinin işlenmesinin arkasında matematiksel iki terim yatıyor: interpolasyon ve ekstrapolasyon (bir diğer adıyla dead reckoning).

Yaa bilgisayar / yazılım mühendisliğinde okuyup “Calculus II, kod yazarken ne işime yarayacak yaw” diyordunuz, gördünüz mü?

o7

Kabaca özetlemek gerekirse; interpolasyonda bir X objesinin son geçerli konumunun, anlık durumdan önceki süre zarfında kullanılan nesnelere göre hesaplama yapılır. Oyun sunucusunun saniyede gönderdiği frame sayısına göre bir interpolasyon gecikmesi uygulanır ve t süresinden önceki duruma göre nesnelerin güncel konumu hesaplanarak client’a iletilir. Güncel ana gelindiğinde bir sonraki hareket öncesinde interpolasyon süresine göre güncelleme yapılır.

Burada yine bir paket alışverişi söz konusu olduğu için, herhangi bir nedenden ötürü paketlerin iletilememesi oyunda anlık dengesizlikler yaratabilir. Bunu anlık peak yapan gecikme durumlarında görülebilen tutarsızlıklara benzetebiliriz.

Ekstrapolasyonda ise işler biraz daha farklı, buradaki olay tahmine bağlı ilerliyor. Bir oyunda arka arkaya yapılması çok muhtemel bir eylemi düşünelim, mesela oyuncu spesifik bir konumda bir nesnenin üzerine çıkarken iki kere space tuşuna basmak zorunda, böyle bir senaryoda oyuncunun ilk düzlemdeki konumu ve 2 x space sonrası bulunacağı pozisyon tahmin edilebilir. Buradaki bilgiler sunucusu tarafında gerekli değildir, akıcı bir oyun deneyimi olması açısından client tarafında işlenir.

İnterpolasyon ve ekstrapolasyonun da TCP/UDP’de olduğu gibi kullanım amaçları ve alanları birden çok değişkene göre farklılık gösterebiliyor. Ekstrapolasyonun daha çok oyuncunun hareket eylemlerine yönelik bir işlem olduğunu söylemek yanlış olmaz sanıyorum. İki tarafta da hesaplamalar yapılırken belirli algoritmalar kullanılıyor.

Bu kavramlar sadece konum bilgisini değil, bir diğer önemli alt başlıklardan birisi olan çarpışma algılamayı (collision detection) da yakından ilgilendiriyor.

TCP vs UDP

Şimdi Transport katmanına kısa bir geri dönüş yapalım.

Öncelikle şunu belirtmek gerekir; online oyun mimarisinde IP üzerinden TCP ya da UDP protokolü kullanılmak zorunda değil. Hatta bazı meşhur eski oyunları (Doom, Duke Nukem, Red Alert vs.) LAN üzerinden oynarken IPX kullanıldığını söylemeliyim. Burada bir diğer opsiyon da custom protokol yazmak(mış), ben de yeni öğrendim. Custom prokoller de kendi içerisinde kümelere bölünüyor, buralar biraz derinlere indiği için okuyucuları da boğmak istemiyorum. Bunun yanısıra C ve C++ ile yazılmış, kullanımı ücretsiz hazır kütüphaneler de mevcut. Hatta bunlardan birisi Meta’ya ait ve Oculus için tasarlanmış.

Özellikle network / system admin pozisyonundaki adayların hayatları boyunca mülakatlarda en az bir defa karşılaştıkları meşhur “TCP ve UDP’nin farkları nelerdir?” sorusunun temel yanıtı aslında oyun mimarisini de yakından ilgilendiriyor. TCP için ne diyoruz? Güvenilir. Yani paket alışverişinin tamamlandığına dair emin olabiliyoruz. Peki bunun oyunlardaki avantaj / dezavantaj karşılığı nasıl? En basitinden veri iletim hızı UDP’ye nazaran daha düşük olduğu için latency üzerine düşünmek gerekiyor. Mesela latency’nin önem arz etmediği oyunlarda (turn based buna örnek verilebilir) TCP daha makul bir seçim olabilir ancak özellikle anlık reflekslerin önemli olduğu, online oyun dünyasının bok çukurları olarak tanımlanabilecek LoL (Türkiye sunucusu) veya CS (Orta doğu ve Rusya sunucusu) gibi rekabetçi oyunlarda milisaniyelerin öneminden bahsettiğimizde bayrağı net bir şekilde UDP alıyor.

o3

Her şeye rağmen bu sorunun kesin olarak UDP veya TCP kullanılmalı şeklinde bir cevabı olmadığını söylesek yanlış olmayacaktır. Birincil olarak az önce bahsettiğimiz gibi oyun tipi her ne kadar önem arz etse de donanımsal ve diğer bazı değişkenler karar mekanizmasında etki edebilir.

Daha fazla bilgi edinmek isteyenler için

Bu konu hakkında ayrıca cevaplanması gereken bazı diğer noktalar da şunlar:

  • Veri paketi boyutu
  • Hata kontrolü
  • Şifreleme -Encryption-
  • Sıkıştırma -Compression-

Misal hata kontrolünü ele alacak olursak, herhangi bir ağ problemi veya başka bir nedenden ötürü paketin sunucuya ulaşmaması veya sunucudan client’a dönerken bütünlüğünü kaybetmesi, o an oyun içinde yapılan eylemin gerçekleşmemesine neden olacaktır, özellikle anlık lag yükselmelerinde oyunun donması, yapılan eylemin gerçekleştirilmemesi gibi sonuçlanan durumlar bir bağlamda buradaki hata mekanizmasına bağlıdır.

o4

Şifreleme konusuna da değinelim. Şayet global çapta veya o kadar büyük olmasa bile yine hatırı sayılı miktarda anlık oyuncuya sahip bir oyundan bahsediyorsak ve de envanter -inventory- oyundaki en önemli unsurlardan birisiyse, encryption uygulamak da bir zorunluluk haline gelebiliyor zira aksi bir durumda hile olasılığına davetiye çıkarmış oluyorsunuz.

Burada çok fazla detay var, zaten temel de olsa kriptografi bilginiz yoksa bu detayları okumak işkence gibi gelebilir. En azından şunu söyleyebiliriz, TCP ve UDP farkını ele alırken TCP’nin UDP’den daha güvenli olduğu söylenir ama bu kısmen hatalı bir çıkarımdır, çünkü TCP, UDP’den daha güvenli değil, daha güvenilirdir.

Türkçe biraz havada kalıyor galiba, şöyle diyelim: TCP is not more secure, it’s just more reliable than UDP.

Yani buradaki keywordler secure ve reliable, böyle daha anlaşılır oldu değil mi?

Sonuç itibariyle iki protokol için de şifreleme uygulanabilir.

Burada olay sadece hile değil, aynı zamanda DDoS saldırılarını da ilgilendirmektedir. Amplifikasyon saldırılarıyla bir maçın tamamen durmasına neden olunabilir. Koruma noktasında iş sadece protokollerin şifrelemesiyle bitmiyor, yine para - köfte ilişkisi burada da karşımıza çıkıyor.

Sıkıştırma konusuyla bağlantılı olan bir konudan kısa da olsa bahsetmekte fayda var: Rendering. Rendering konusu da Client side ve Server side olmak üzere ikiye ayrılıyor. Hani online oyunlarda bekleme ekranları olur, oyuna dair bilgiler verilir filan, işte tam olarak bu bekleme ekranı online oyunlarda Client side olarak gerçekleşir. Oyun bilgileri karşıdan client’a iletilir, oyun başladıktan sonra sunucu oyuncudan sadece input bilgilerini alır.

Bandwidth ve Tickrate

Bandwidth terimi de bir diğer önemli unsur. Burada bir limit olduğu için haliyle her ufak değişiklikte paket alışverişi yapılmıyor. Şuna benzetebiliriz; sunucu tarafında mevcut oyun durumunun bir snapshot’ı alınır ve aslında bu anlık durum bilgileri oyunculara iletilir. Az önce belirttiğimiz gibi veri alışverişi bize her ne kadar anlık yaşanan bir durum gibi gelse de, aslında somut olarak milisaniye bazında da olsa bir süre geçiyor. Buradaki trafiğin süresi elbette sadece oyun sunucusunun performansına bağlı değil ve kuantum fiziği buna ileride ışık tutar mı bilmiyorum ama veri paketi sunucuda ve client tarafında aynı anda bulunamayacağı için, aslında client’ın sunucunun her zaman biraz gerisinde olduğu sonucuna varıyoruz.

Burada yine framerate, tickrate gibi kavramlar da işin içine girebiliyor. Özellikle rekabetçi FPS oyunlarında oldukça önem arz eden bu konuya da biraz değinelim. Tickrate aslında üç aşamadan oluşan bir eylemler bütününü betimliyor ki biraz önce bahsetmiş olduğum iki veri tipinin hesaplanmasına benzetebilirsiniz.

  • Oyuncuların anlık durum verilerini toplama
  • Toplanan verileri hesaplama
  • Hesaplanan bilgileri geri gönderme

Bu üç aşamanın toplamı bir ‘tick’ işlemine tekabül ediyor. CS GO üzerinden örnek vermek gerekirse, Valve ağırlıklı olarak 64 tick rate’e sahip sunucuları kullanıyor. Bunun anlamı şu: bir oyuncu maç esnasında oyun sunucusundan saniyede 64 güncelleme alıyor. Haliyle ne kadar yüksek tick rate, o kadar pürüzsüz ve akıcı bir oyun deneyimi diyebiliriz.

Tabii söz konusu tickrate olduğunda işin içine monitörlerdeki hertz değerleri de giriyor zira 144 Hz’e sahip bir oyuncu monitörü her ne kadar oyuncuya saniyede 144 kare gönderebilecek kapasitede olsa da, 64 tickrate’e sahip bir sunucunun göndereceği maksimum kapasite bu olduğu için özellikle FPS oyunlarındaki meşhur “daha adamı göremeden öldüm amk” cümlesini ilgilendiren değişkenlerden birisi de budur. Trivia; majör CS GO turnuvalarında sunucular her zaman 128 tickrate’e sahiptir.

o6x

Tickrate konusu aslında arka planda ciddi mühendislik birikiminin olduğu bir olay. Tüm frame’lerin belirli bir süre içinde gönderilmesi gerekliliği, CPU tüketimi, network replikasyonu gibi ayrı başlıklara da sahip.

Tickrate haricinde yine bilinmesi gereken konulardan birisi de RTT.

RTT, kaynak ve hedef alıcı arasındaki veri alışverişinde geçen süreyi tanımlar. Ee, ping değil mi bu? dediğinizi duyar gibi oldum, aslında terminoloji olarak şöyle; RTT’yi ping aracı ile ölçüyoruz ama ping normalde ICMP paketleri üzerinden işlem yaptığı için RTT’nin kullandığı metriklerle birebir aynı zamanı işaret etmiyor.

Cloud dünyasındaki servisler

Cloud tarafına da kısacak değinmek gerekirse; şu an tüm majör cloud sağlayıcılarının online oyun konusunda kendilerine ait servisleri mevcut. Buradaki yapıyı frontend ve backend olarak ikiye ayırıyoruz. Mesela, kullanıcının bir online oyuna bağlandığında oyun girmeden önce kullandığı platform frontend olarak düşünülebilir. Sunucu seçimi, oyuncu bilgileri, sıralamalar, rakip bulma -matchmaking- vs. bu kümeye giriyor. Backend ise daha çok oyun bilgilerinin dinamik olarak tutulduğu veri tabanına işaret ediyor.

Devamlı gelişen cloud ve container teknolojileri sayesinde olay artık öyle bir noktaya geldi ki Agones gibi açık kaynak platformlarla oyun sunucuları AWS ya da GCP üzerindeki Kubernetes servisleri üzerinde ölçeklenebilir durumda. Hatta seneler önce GCP, Pokemon GO ile ilgili bir yazı yayınlamıştı, meraklıları için onu da bırakayım. Geçen sene ben de bizzat bir Türk indie oyun şirketinin sunucusunu GKE üzerinde deploy ettiğini görmüş ve görece niş bir proje olduğu için sevmiştim.

Oyuncu perspektifinde en önemli durumun düşük gecikme olduğunu kabul edersek, seçim yaparken özellikle coğrafya - bölge bazındaki olanaklara, networking yapısına bakmak önem arz edebilir.

İş elbette sadece düşük gecikmeyi sağlamakla bitmiyor, bütçe yönetimi söz konusu olduğunda oyuncu trafiğinin doğru şekilde ölçeklendirilmesi, operasyonel işlemlerin otomatize edilmesi de önemli noktalar. Mesela matchmaking konusunda açık kaynak projeler olduğu gibi, cloud tarafında sadece bu işlem için özelleştirilmiş çözümler de var; Amazon GameLift FlexMatch gibi. Güvenlik yine ayrıca değerlendirilmesi gereken bir diğer mühim konu. Yukarıda bahsettiğimiz DDoS haricinde oyun sunucusunun ve oyun içerisinde yaşanabilecek anomalilerin tespit edilmesi, monitoring gibi eylemler son derece önemli.

Hatta konu sadece infrastructure ortamına yönelik de değil; misal yüksek GPU gücü gerektiren hazır sunucular, görsel konularda yardımcı olabilecek stüdyo uygulamaları, oyun motorlarının entegre şekilde kullanılabilmesi gibi farklı tipte ihtiyaçlara yönelik çözümler de mevcut. Günümüzde Epic Games, Riot, Ubisoft gibi oyun devleri bu ihtiyaçlarına yönelik çeşitli AWS servislerini kullanıyor.

Sunucunun host edilmesi noktasında kullanılabilen AWS servisleri:

  • EC2
  • ECS ve EKS
  • GameLift

Backend servisleri olarak:

  • Cognito
  • Lambda
  • Aurora
  • DynamoDB

Analiz işlemleri için:

  • Athena
  • EMR
  • Kinesis

örnek olarak verilebilir.

Genel olarak bir cloud mimarisi üzerinde host edilen online bir oyunun mimarisini kabaca özetlemek gerekirse:

  • Oyuncunun login ve matchmaking eylemleri backend servislerinde işlenir.
  • Bu bilgiler veri tabanına gönderilir.
  • Oturum ve matchmaking bilgilerinin işlenmesi ara bir serviste yapılır.
  • Oturum bilgileri bunların cloud tarafında tutulduğu servise iletilir.
  • Oyuna bağlanma esnasında üçüncü adımda bahsi geçen servis, oturum bilgilerinin cevabını ana sunucuya iletir.
  • Oyun bitiminde mevcut bilgiler yeniden veri tabanına aktarılır.

Oyuncu sayısı artan bir oyunda yeni dünyalar açılması (KO diliyle Ares - Beramus vs.) veya bunun coğrafi düzeyde yapılması, anlık kullanıcı bağlı olarak sunucuların otomatik olarak ölçeklendirilmesi konularında cloud elimizi güçlendirmektedir.

Performans bazlı durumlar haricinde güvenliğin sağlanması, support ihtiyacı gibi durumlar da ilgili AWS servisleriyle çözülebilmektedir.

AWS’in bu konudaki çözümlerine dair daha fazla bilgi almak istiyorsanız tık

Son sözlere başlarken şunu söylemek isterim. Konuyla ilgili makaleler okurken Unity’de çalışan Fatih Mar isimli bir Türk mühendisin adına rastladım ki kendisi özellikle networking / development konularında son derece bilgili bir arkadaşımız, ilgilileri için onun reposunu da ekliyorum.

https://github.com/ThusWroteNomad/GameNetworkingResources

Bu yazıyla ilgili eklemek / düzeltmek istediğiniz bir şeyler olursa: denizparlak@protonmail.ch adresinden bana ulaşabilirsiniz.

o8x



Written by Deniz Parlak