MMORPG mobil oyunumuz için doğru mimari bu mu?


14

Bugünlerde şirketim için yeni bir MMORPG mobil oyun mimarisi tasarlamaya çalışıyorum. Bu oyun Mafya Savaşları, iMobsterler veya RİSK'e benzer. Temel fikir, rakiplerinizle (çevrimiçi kullanıcılar) savaşacak bir ordu hazırlamaktır.

Daha önce birden çok mobil uygulama üzerinde çalışmış olmama rağmen bu benim için yeni bir şey. Bir çok mücadeleden sonra, üst düzey bir akış şeması yardımıyla gösterilen bir mimari ortaya çıkardım:

Yüksek seviye akış diyagramı

İstemci-sunucu modeli ile gitmeye karar verdik. Sunucuda merkezi bir veritabanı olacaktır. Her istemcinin sunucuyla senkronize kalacak kendi yerel veritabanı olacaktır. Bu veritabanı, haritalar, ürünler, envanter vb. Gibi sık sık değişmeyen şeyleri saklamak için bir önbellek görevi görür.

Bu model yerinde olduğunda, aşağıdaki sorunların nasıl çözüleceğinden emin değilim:

  • Sunucu ve istemci veritabanlarını senkronize etmenin en iyi yolu nedir?
  • Bir olay sunucuya güncellenmeden önce yerel DB'ye kaydedilmeli mi? Uygulama, merkezi DB'deki değişiklikleri kaydetmeden önce herhangi bir nedenle sona ererse ne olur?
  • Basit HTTP istekleri senkronizasyon amacına hizmet eder mi?
  • Şu anda hangi kullanıcıların oturum açtığını nasıl öğrenebilirim? (Bunun bir yolu, istemcinin etkin olduğunu bildirmek için her x dakikada bir sunucuya istek göndermeye devam etmesini sağlamak olabilir. Aksi takdirde istemciyi devre dışı bırakın).
  • İstemci tarafı doğrulamaları yeterli mi? Değilse, sunucu bir şeyi doğrulamazsa bir eylem nasıl geri alınır?

Bunun etkili bir çözüm olup olmadığından ve nasıl ölçekleneceğinden emin değilim. Bu tür uygulamalarda zaten çalışmış olan kişilerin deneyimlerini paylaşıp paylaşamayacaklarını daha iyi bir şey bulmamı gerçekten takdir ediyorum. Şimdiden teşekkürler.

İlave bilgi:

İstemci tarafı marmelat adı verilen C ++ oyun motorunda uygulanmaktadır. Bu, uygulamanızı tüm büyük mobil işletim sistemlerinde çalıştırabileceğiniz bir çapraz platform oyun motorudur. Kesinlikle iplik geçirmeyi başarabiliriz ve bu da benim akış diyagramımda gösterilmiştir. Sunucu için MySQL ve istemci için SQLite kullanmayı planlıyorum.

Bu sıra tabanlı bir oyun değil, bu yüzden diğer oyuncularla çok fazla etkileşim yok. Sunucu çevrimiçi oyuncuların bir listesini sunacak ve savaş düğmesine tıklayarak onlarla savaşabilirsiniz ve bazı animasyonlardan sonra sonuç duyurulacaktır.

Veritabanı senkronizasyonu için iki çözüm var:

  1. Her kayıt için zaman damgasını saklayın. Ayrıca, yerel DB'nin en son ne zaman güncellendiğini de takip edin. Senkronize ederken, yalnızca daha büyük zaman damgası olan satırları seçin ve yerel DB'ye gönderin. Silinmiş satırlar için isDeleted bayrağını saklayın, böylece her silme işlemi bir güncelleme görevi görür. Ancak, tüm DB isteğini taramak ve güncellenmiş satırları aramak zorunda kalacağımız her senkronizasyon isteği için performans konusunda ciddi şüphelerim var.
  2. Başka bir teknik, bir kullanıcıya karşı gerçekleştirilen her ekleme veya güncellemenin günlüğünü tutmak olabilir. İstemci uygulaması senkronizasyon istediğinde, bu tabloya gidin ve hangi tablonun hangi satırların güncellendiğini veya eklendiğini öğrenin. Bu satırlar başarıyla istemciye aktarıldıktan sonra bu günlüğü kaldırın. Ama sonra bir kullanıcı başka bir cihaz kullanıyorsa ne olacağını düşünüyorum. Günlükler tablosuna göre, bu kullanıcı için tüm güncellemeler aktarıldı, ancak aslında başka bir cihazda yapıldı. Bu yüzden cihazı da takip etmek zorunda kalabiliriz. Bu tekniği uygulamak daha fazla zaman alır, ancak ilkinin uygulanıp uygulanmadığından emin değildir.

2
Ben MsSQL bir değerlendirme kapmak ve onunla keman - MySQL çoğaltma açısından ne sağlar emin değilim ama MsSQL 2008 R2 seçim için çoğaltma (5-6) teknikleri YÜKÜ verir. Sadece bir düşünce, MySQL veya başka bir şeyden nefret etmiyor, ancak Microsoft kümeleme konusunda gerçekten iyi.
Jonathan Dickinson

1
@Jonathan Dickinson: MySQL Kümesi Var: P
Coyote

1
Ayrıca PostgreSQL'e bakın - sürüm 9 çoğaltma teknolojisine sahiptir, PostgreSQL ağır yükleri gerçekten iyi idare etmek için mükemmel bir uzun soluklu itibara sahiptir, geliştiricilerin çoğu optimizasyon kuruyemiş gibi görünüyor ve en iyisi açık kaynak ve tüm kullanımlar için tamamen ücretsiz (ticari dahil).
Randolf Richardson

Mesele şu ki, aynı veritabanını istemci ve sunucu tarafında kullanamayız. Ben istemci için en uygun DB SQLite olacağını düşünüyorum böylece uygulama mobil cihazlarda çalışıyor gibi çok fazla kaynak tüketmez. Sunucu kısmında çalışan kişi sadece MySQL'i biliyor, bu yüzden onu seçtik. Ayrıca çoğu MMO oyununun MySQL veritabanını kullandığını duydum.
umair

1
@umair: İstemci tarafı SQLite olabilir (örneğin iPhone'da zaten mevcuttur). Ancak, sadece ihtiyacınız olan ilgili verileri bir dosyada (SQLite zaten ne yapar) depolamayı seçebilir ve bir Javascript uygulamasıyla yapacağınız gibi istemci tarafı DB ile uğraşmayabilirsiniz.
Coyote

Yanıtlar:


15

Oyuncuların bir oyun sahnesinde başka bir oyuncunun eylemlerinin hemen sonucunu görmeleri gerekmediği anlamında bir "gerçek zamanlı" oyun değilse, HTTP istekleri konusunda iyi olmalısınız. Ancak HTTP yükünü de unutmayın.

HTTP kullanmanın, iletişim protokolünüzü dikkatli bir şekilde tasarlamanıza engel olmayacağını söyler. Ancak hem sunucunun hem de istemci tarafının başındaysanız, protokolü ihtiyacınız olduğunda ayarlayabileceğiniz için şanslısınız.

Ana DB ile İstemci DB arasında senkronize etmek için, erişiminiz olan HTTP, veya başka herhangi bir aktarım protokolünü kullanabilirsiniz. Önemli olan, senkronizasyonun arkasındaki mantıklardır. Basit bir yaklaşım için, istemci DB'sindeki son zaman damgasından bu yana istemci tarafından ihtiyaç duyulan en son değişikliklerin tümünü sunucudan havuzlayın. İstemci DB'sine uygulayın ve bununla devam edin. İstemci tarafında daha fazla değişiklik varsa, hala alakalı ise yükleyin, aksi takdirde atın.

Bazı oyunlar yerel bir DB bile kullanmaz, gerektiğinde sunucudan ilgili bilgileri bir araya getirerek durumu izler.

Yerel etkinlikleri kaybetmek kabul edilebilir değilse, evet, yerel depolama alanınız olmalı ve bu depolamaya mümkün olduğunca sık kaydetmelisiniz. Her ağ göndermeden önce bunu deneyebilirsiniz.

Başarılı bir oyunda her 20 saniyede bir HTTP ile ping işlemi yapmak için kullandığımız aktif kullanıcıları kontrol etmek için ... Bu değer, sunucular aşırı yüklendikçe hemen yükseldi :( Sunucu ekibi başarı hakkında düşünmedi. iletişim protokolünüzde, istemcilerinizi yeniden yapılandırmanıza olanak tanıyan bir mesaj veya bir tür özel başlık (ping frekansı yük dengelemesi ve diğer iletişim ile ilgili değerler için).

Oyunlara saldıran dolandırıcılara, bilgisayar korsanlarına ve diğer otomatik komut dosyalarına aldırmazsanız istemci tarafı doğrulamaları yeterlidir. Sunucu, işleminizi reddedebilir ve bazı ayrıntılarla bir hata mesajı gönderebilir. Bu hata iletisini, yerel değişiklikleri geri alarak veya sunucunun değişiklikleri gerçekten kaydetmek için yanıt vermesini bekleyebiliyorsanız, yerel depolama alanınıza uygulamayarak işlersiniz.

Oyunumuzdaki komut desenini, başarısız veya geçersiz kullanıcı işlemlerinin basit ve verimli bir şekilde geri alınmasına izin vermek için kullandık. Komutlar, yerel olarak eşlere gönderilir veya sunucu iletisine çevrilir ve daha sonra eşlere uygulanır veya sunucuda kontrol edilir, bir sorun olması durumunda komutların oynatılmaması ve oyun sahnesi bir bildirim ile ilk durumuna geri döndü.

HTTP'yi kullanmak kötü bir fikir değildir, daha sonra Flash veya HTML5 istemcileriyle çok kolay bir şekilde tümleştirmenize izin verir, esnektir, herhangi bir sunucu komut dosyası dili kullanabilir ve temel yük dengeleme teknikleri ile daha sonra çok çaba harcamadan daha fazla sunucu ekleyebilir arka ucunuzu ölçeklendirmek için.

Yapacak çok işin var ama eğlenceli bir iş ... Öyleyse tadını çıkar!


3
'HTML muhtemelen yeterince iyi' için +1, çünkü muhtemelen :).
Jonathan Dickinson

1
@Coyote: Zaman ayırdığınız ve bu kadar ayrıntılı bir cevap verdiğiniz için teşekkürler. Diğer istemcilere destek sağlamak için HTTP fikriniz gibi.
umair

1
Güç seninle olsun :)
Coyote

5

Sunucu ve istemci veritabanlarını senkronize etmenin en iyi yolu nedir?

En kolay yol, veritabanını aktarabileceğiniz tek bir dosya olarak uygulamaktır. Veritabanları arasındaki farkları karşılaştırmaya çalışırsanız, bu bir acı dünyasıdır ve deneyimlerden söz ediyorum.

Sunucunuzun, istemcinin değiştirebileceği için istemcinin bu yerel veritabanına dayalı olarak aldığı kararlara güvenmemesi gerektiğini unutmayın. Sadece sunum detayı için var olmalıdır.

Bir olay sunucuya güncellenmeden önce yerel DB'ye kaydedilmeli mi?

Hayır. Sunucu etkinliğin hiç gerçekleşmediğine karar verirse ne olur? İstemci zaten olaylar hakkında karar vermemelidir, çünkü müşteriye güvenilemez.

Yerel DB hakkında iki şekilde konuştuğunuzu fark ettim: biri, "sık sık değişmeyen şeyler" ve iki tanesi de etkinlikler için. Bunlar, yukarıdaki nedenlerden dolayı gerçekten aynı veritabanında olmamalıdır - veritabanlarındaki tek tek veri satırlarını birleştirmeye veya ayırmaya çalışmak istemezsiniz. Örneğin, istemcinin sunucudan kaldırmaya karar verdiğiniz bir öğeye başvurusu olduğunda başvuru bütünlüğü bir sorun haline gelir. Veya istemci bir satırı değiştirirse ve sunucu bir satırı değiştirirse, hangi değişiklik önceliklidir ve neden?

Basit HTTP istekleri senkronizasyon amacına hizmet eder mi?

Evet, oldukça seyrek veya küçük olmaları şartıyla. HTTP bant genişliği açısından verimli değildir, bu nedenle bunu aklınızda bulundurun.

Şu anda hangi kullanıcıların oturum açtığını nasıl öğrenebilirim? (Bunun bir yolu, istemcinin etkin olduğunu bildirmek için her x dakikada bir sunucuya istek göndermeye devam etmesini sağlamak olabilir. Aksi takdirde istemciyi devre dışı bırakın).

HTTP gibi geçici bir protokol kullanıyorsanız, bu makul bir fikirdir. Sunucu bir istemciden mesaj aldığında, o istemcinin 'son görülme' zamanını güncelleyebilirsiniz.

İstemci tarafı doğrulamaları yeterli mi? Değilse, sunucu bir şeyi doğrulamazsa bir eylem nasıl geri alınır?

Hayır, hiç de değil. Müşteri düşmanın elinde. Bir eylemin nasıl geri alınacağı tamamen bir eylemin ne olduğunu düşündüğünüze ve bunun ne gibi etkileri olabileceğine bağlıdır. En kolay yol, sunucu izin vermek için yanıt verene kadar eylemi uygulamamaktır. Biraz daha karmaşık bir yol, her eylemin eylemi geri almak için geri alma özelliğine sahip olmasını sağlamak ve istemcideki tüm onaylanmamış eylemleri önbelleğe almaktır. Sunucu bunları onayladığında, önbellekten silin. Bir eylem reddedilirse, her eylemi reddedilene kadar ters sırayla geri alın.


1
Başardın. DB'leri senkronize etme konusunda haklısınız +1 İstemci DB'yi asla tek başına değiştirmemelidir ... Sadece sunucuda çalışan işlevleri arayın ve oyunun mantıklarını kullanarak DB'yi güncelleyin, ardından sonuçları alın.
Coyote

@Kylotan: Modelimdeki akışları işaret ettiğiniz için teşekkürler
umair

@Kylotan: "En kolay yol, veritabanını aktarabileceğiniz tek bir dosya olarak uygulamaktır. Eğer veritabanları arasındaki farkları karşılaştırmaya çalışırsanız, bu bir acı dünyasıdır ve deneyimden söz ediyorum." bu, uygulama her başlatıldığında tüm verilerin indirildiği anlamına gelir. Çok sık değişmeyecek şeyler vardır ve bu yüzden bunları her seferinde indirmek kabul edilemeyebilir. Bu, uygulamanın başlatma süresini de önemli ölçüde artıracaktır. Düşüncesi olan var mı?
umair

Veriler küçükse sorun ortadan kalkar. Merkezi statik veri tabanınız çok büyük olsaydı şaşırırdım. Her neyse, statik verileri daha küçük parçalara böldüğünüzde, yalnızca son zamandan bu yana değişen verileri göndermeniz gerekir. Elbette, her satırda bir değişiklik zamanı tutmaya istekliyseniz bunu satır başına yapabilirsiniz. Genellikle ilişkisel DB'nin dışında, üzerine kolayca yazmamı sağlamak için statik veriler olmasını tercih ederim.
Kylotan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.