Metin2 Game Core ve DB Core Arasındaki P2P Socket İletişim Optimizasyonu
Metin2 geliştiriciliğinin en derin ve performans açısından en kritik konularından biri Game Core (Oyun Motoru) ile DB Core (Veritabanı Önbelleği) arasındaki iletişimdir. Oyuncuların "Lag var", "Geri atıyor" veya "Itemim kayboldu" şikayetlerinin arka planında genellikle bu iki process arasındaki Socket (P2P) iletişiminin tıkanması yatar.
Bu iletişim, sunucunun "omuriliği" gibidir. Eğer burada veri akışı yavaşlarsa veya paketler (packet) kuyrukta beklerse, oyuncunun interneti ne kadar hızlı olursa olsun oyun takılır.
İşte Game ve DB Core arasındaki iletişimi optimize etmek, darboğazları (bottleneck) aşmak ve yüksek oyunculu sunucularda stabilite sağlamak için teknik rehber.
Metin2 sunucu mimarisinde Game dosyası doğrudan MySQL ile konuşmaz. Arada DB (Database Cache) adı verilen bir aracı vardır. Game, bir isteği (örneğin "Kılıcı +9 bas") DB'ye socket yoluyla iletir, DB bunu veritabanına işler ve sonucu geri döner. Bu işlem saniyede on binlerce kez gerçekleşir.
Yüksek online sayısına ulaşıldığında (2k+), standart socket ayarları yetersiz kalır ve "Packet Delay" (Paket Gecikmesi) başlar. Bu durumu optimize etmek için Source (C++) tarafında ve Config ayarlarında yapılması gerekenler şunlardır:
1. Nagle Algoritmasını Devre Dışı Bırakmak (TCP_NODELAY)
TCP protokolü varsayılan olarak "Nagle Algoritması"nı kullanır. Bu algoritma, küçük paketleri biriktirip tek seferde göndererek bant genişliğinden tasarruf etmeye çalışır. Ancak Metin2 gibi "Real-Time" (Gerçek Zamanlı) oyunlarda bu bir felakettir. Biz paketin birikmesini değil, oluştuğu an karşı tarafa gitmesini isteriz.
Çözüm: Game ve DB source dosyalarında socket açılışlarına TCP_NODELAY flag'ini eklemelisiniz.
Uygulanacak Dosyalar: libthecore/src/socket.c veya db/src/Main.cpp (Dosya yapısına göre değişebilir).
// Socket oluşturulduktan hemen sonra:
int flag = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
Bu kod, işletim sistemine "Bu socket üzerindeki veriyi bekletme, anında gönder" emrini verir. Bu, Game-DB arasındaki milisaniyelik gecikmeleri (micro-lag) ortadan kaldırır.
2. Socket Tampon (Buffer) Boyutlarını Artırmak
Standart Metin2 kaynak kodlarında socket buffer boyutları eski donanımlara göre ayarlanmıştır (Genellikle 16KB veya 64KB). Günümüz sunucularında binlerce oyuncunun verisi (Login paketleri, Item yüklemeleri) bu bufferları anında doldurur.
Buffer dolduğunda (OUTPUT_BUFFER_FULL), sistem paketi göndermeyi durdurur ve yer açılmasını bekler. Bu, oyunculara devasa bir lag spike (donma) olarak yansır.
Optimizasyon:
Source tarafında input_buffer ve output_buffer boyutlarını artırın.
Örnek Düzenleme (Config.cpp veya benzeri):
// Eski Değer: 64 * 1024 (64KB)
// Yeni Değer: 1024 * 1024 * 2 (2MB) veya daha yüksek
sys_log(0, "SYSTEM: P2P Socket Buffer Size increased to 2MB");
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, sizeof(buffer_size));
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, sizeof(buffer_size));
Bu değişiklik, özellikle "Lonca Savaşı" veya "Ox Yarışması" gibi toplu veri akışının olduğu anlarda sunucunun nefes almasını sağlar.
3. KeepAlive Mekanizması ve Timeout Ayarları
Game Core, DB Core'un hala hayatta olup olmadığını anlamak için "KeepAlive" sinyalleri gönderir. Eğer ağda bir kopukluk olursa ve bu ayar doğru yapılandırılmamışsa, Game Core DB'nin düştüğünü fark etmez ve verileri "boşluğa" göndermeye devam eder. Sonuç: Veri kaybı ve Item kaybı.
Önerilen Ayar: Socket opt ayarlarına KeepAlive süresini kısaltan parametreler ekleyin. Böylece bağlantı koptuğu an Game Core bunu fark eder ve kendini güvenli moda (shutdown) alır veya yeniden bağlanmayı dener.
4. Localhost (Loopback) Optimizasyonu
Çoğu sunucu sahibi, Game ve DB aynı makinede olmasına rağmen config dosyalarında Public IP (Dış IP) kullanır. Bu büyük bir hatadır.
Yanlış:
BIND_IP: 192.168.1.5(Veya sunucu dış IP'si)Doğru:
BIND_IP: 127.0.0.1
Neden?
Dış IP kullanıldığında veriler ağ kartına (NIC) gider, router'dan döner ve tekrar içeri girer (bazı durumlarda). 127.0.0.1 kullanıldığında ise veri asla ağ kartına uğramaz, işletim sisteminin RAM'i üzerinden doğrudan (Loopback Interface) iletilir. Bu, P2P iletişiminde %20'ye varan hız artışı ve "0" paket kaybı demektir.
5. Packet Aggregation (Paket Birleştirme) Mantığı
Game Core, DB'ye her saniye binlerce küçük sorgu gönderir (Örn: "Oyuncunun parasını güncelle"). Bu sorguları tek tek göndermek yerine, mantıksal bir döngüde birleştirip göndermek CPU yükünü azaltır.
Bunun için source tarafında "Flush" mekanizmasının doğru yerde kullanılması gerekir. Her Send() komutundan sonra socketi flushlamak yerine, oyun döngüsünün (Main Loop) sonunda toplu flush yapmak, context switch maliyetini düşürür.
Sık Karşılaşılan Hatalar ve Belirtileri
Syserr: SEQUENCE MISMATCH
Sebep: Game ve DB arasındaki paket sırası karışmıştır. Genellikle buffer taşması veya ağ kopukluğu yüzünden olur.
Çözüm: Buffer boyutlarını artırmak ve TCP_NODELAY kullanmak.
Syserr: SYSTEM: header not enough
Sebep: Gelen veri paketi yarım kalmıştır.
Çözüm: P2P iletişiminde verinin parçalı gelebileceğini (fragmentation) hesaba katan bir paket okuma algoritması kullanmak.
Core Crash (Segmentation Fault)
Sebep: DB'ye gönderilen bir paketin boyutu, tanımlanan struct boyutundan büyüktür.
Çözüm:
tables.h(Game) vetables.h(DB) dosyalarının birebir aynı olduğundan emin olun.
Sonuç
Metin2 sunucularında Game ve DB Core arasındaki iletişim, sunucunun performans limitini belirleyen ana faktördür. Donanımınız ne kadar güçlü olursa olsun, socket iletişiminizde TCP_NODELAY yoksa ve bufferlarınız darsa, yüksek oyunculu bir açılışta sunucunuz "lagdan oynanmaz" hale gelir.
Yukarıdaki C++ düzenlemelerini ve Config yapılandırmalarını uygulayarak, veri akışını otobandan geçen bir Ferrari hızına ve akıcılığına ulaştırabilirsiniz.

