นี่เป็นสถาปัตยกรรมที่เหมาะสมสำหรับเกมบนมือถือ MMORPG ของเราหรือไม่


14

ทุกวันนี้ฉันพยายามออกแบบสถาปัตยกรรมของเกม MMORPG บนมือถือใหม่สำหรับ บริษัท ของฉัน เกมนี้คล้ายกับ Mafia Wars, iMobsters หรือ RISK แนวคิดพื้นฐานคือการเตรียมกองทัพให้พร้อมเพื่อต่อสู้กับคู่ต่อสู้ของคุณ (ผู้ใช้ออนไลน์)

แม้ว่าก่อนหน้านี้ฉันเคยทำงานกับแอพมือถือหลายตัว แต่นี่เป็นสิ่งใหม่สำหรับฉัน หลังจากการต่อสู้อย่างหนักฉันได้พบกับสถาปัตยกรรมที่แสดงด้วยความช่วยเหลือของแผนภาพการไหลระดับสูง:

แผนภาพการไหลระดับสูง

เราตัดสินใจที่จะไปกับรูปแบบไคลเอนต์ - เซิร์ฟเวอร์ จะมีฐานข้อมูลส่วนกลางบนเซิร์ฟเวอร์ ลูกค้าแต่ละรายจะมีฐานข้อมูลท้องถิ่นของตัวเองซึ่งจะยังคงซิงค์กับเซิร์ฟเวอร์ ฐานข้อมูลนี้ทำหน้าที่เป็นแคชสำหรับจัดเก็บสิ่งต่าง ๆ ที่ไม่เปลี่ยนแปลงบ่อยครั้งเช่นแผนที่ผลิตภัณฑ์สินค้าคงคลังเป็นต้น

ด้วยรุ่นนี้ฉันไม่แน่ใจว่าจะแก้ไขปัญหาต่อไปนี้ได้อย่างไร:

  • อะไรจะเป็นวิธีที่ดีที่สุดในการซิงโครไนซ์เซิร์ฟเวอร์และฐานข้อมูลลูกค้า
  • เหตุการณ์ควรถูกบันทึกลงในฐานข้อมูลท้องถิ่นก่อนที่จะอัปเดตไปยังเซิร์ฟเวอร์หรือไม่ ถ้าแอพยุติลงด้วยเหตุผลบางอย่างก่อนที่จะบันทึกการเปลี่ยนแปลงในฐานข้อมูลส่วนกลาง
  • คำร้องขอ HTTP แบบง่ายจะมีจุดประสงค์ในการซิงโครไนซ์หรือไม่
  • จะทราบได้อย่างไรว่าผู้ใช้คนใดที่เข้าสู่ระบบอยู่ในปัจจุบัน? (วิธีหนึ่งอาจให้ไคลเอนต์ส่งคำขอไปยังเซิร์ฟเวอร์หลังจากทุก ๆ x นาทีเพื่อแจ้งว่ามีการใช้งานอยู่มิฉะนั้นให้ถือว่าไคลเอ็นต์ไม่ทำงาน)
  • การตรวจสอบด้านลูกค้าเพียงพอหรือไม่ หากไม่มีวิธีการคืนค่าการกระทำหากเซิร์ฟเวอร์ไม่ได้ตรวจสอบบางอย่าง?

ฉันไม่แน่ใจว่านี่เป็นวิธีแก้ปัญหาที่มีประสิทธิภาพหรือไม่ ฉันจะขอบคุณมาก ๆ ถ้าคนที่ทำงานในแอพนั้นสามารถแบ่งปันประสบการณ์ซึ่งอาจช่วยให้ฉันได้เจอสิ่งที่ดีกว่า ขอบคุณล่วงหน้า.

ข้อมูลเพิ่มเติม:

ฝั่งไคลเอ็นต์ถูกนำไปใช้ในเอ็นจิ้นเกม C ++ ที่เรียกว่ามาร์มาเลด นี่คือเอ็นจิ้นเกมข้ามแพลตฟอร์มซึ่งหมายความว่าคุณสามารถเรียกใช้แอพของคุณในระบบปฏิบัติการมือถือที่สำคัญทั้งหมด เราสามารถบรรลุเธรดได้อย่างแน่นอนและยังแสดงให้เห็นในแผนภาพการไหลของฉัน ฉันวางแผนที่จะใช้ MySQL สำหรับเซิร์ฟเวอร์และ SQLite สำหรับลูกค้า

เกมนี้ไม่ใช่เกมเทิร์นเบสดังนั้นจึงไม่มีการโต้ตอบกับผู้เล่นคนอื่นมากนัก เซิร์ฟเวอร์จะให้รายชื่อผู้เล่นออนไลน์และคุณสามารถต่อสู้กับพวกเขาได้โดยคลิกที่ปุ่มการต่อสู้และหลังจากภาพเคลื่อนไหวบางอย่างจะมีการประกาศผล

สำหรับการซิงโครไนซ์ฐานข้อมูลฉันมีสองวิธีในใจ:

  1. จัดเก็บเวลาประทับสำหรับแต่ละระเบียน ติดตามเมื่อฐานข้อมูลท้องถิ่นได้รับการปรับปรุงล่าสุด เมื่อทำการซิงโครไนซ์ให้เลือกแถวเหล่านั้นที่มีการประทับเวลามากขึ้นและส่งไปยังฐานข้อมูลท้องถิ่น เก็บค่าสถานะ isDeleted สำหรับแถวที่ถูกลบดังนั้นการลบทุกครั้งจะทำหน้าที่เป็นการอัปเดต แต่ฉันมีข้อสงสัยอย่างมากเกี่ยวกับประสิทธิภาพการทำงานสำหรับคำขอซิงค์ทุกครั้งที่เราต้องสแกนฐานข้อมูลที่สมบูรณ์และค้นหาแถวที่อัปเดต
  2. อีกเทคนิคหนึ่งอาจจะเก็บบันทึกการแทรกหรือการอัพเดตแต่ละครั้งที่เกิดขึ้นกับผู้ใช้ เมื่อแอปไคลเอ็นต์ขอซิงค์ให้ไปที่ตารางนี้และดูว่าแถวใดของตารางที่ได้รับการปรับปรุงหรือแทรก เมื่อแถวเหล่านี้ถูกถ่ายโอนไปยังไคลเอ็นต์เรียบร้อยแล้วให้ลบบันทึกนี้ แต่ฉันคิดว่าจะเกิดอะไรขึ้นหากผู้ใช้ใช้อุปกรณ์อื่น ตามตารางบันทึกการอัปเดตทั้งหมดได้รับการถ่ายโอนสำหรับผู้ใช้รายนั้น แต่จริง ๆ แล้วที่ทำบนอุปกรณ์อื่น ดังนั้นเราอาจต้องติดตามอุปกรณ์ด้วย การใช้เทคนิคนี้ใช้เวลานานกว่า แต่ไม่แน่ใจว่ามันใช้งานได้ดีหรือไม่

2
ฉันจะคว้าการประเมินผลของ MsSQL และซอกับมัน - ฉันไม่แน่ใจว่าสิ่งที่ MySQL ให้ในแง่ของการจำลองแบบ แต่ MsSQL 2008 R2 มอบเทคนิคการจำลองแบบ (5-6) ให้คุณเลือกมากมาย แค่คิดไม่เกลียด MySQL หรืออะไร แต่ Microsoft เก่งในการทำคลัสเตอร์
Jonathan Dickinson

1
@ Jonathan Dickinson: มีกลุ่ม MySQL: P
Coyote

1
ดูที่ PostgreSQL - เวอร์ชัน 9 มีเทคโนโลยีการจำลองข้อมูล PostgreSQL มีชื่อเสียงอันยาวนานในการจัดการกับภาระงานหนักมากนักพัฒนาหลายคนดูเหมือนจะเป็นถั่วเพิ่มประสิทธิภาพ (รวมถึงการค้า)
Randolf Richardson

สิ่งคือเราไม่สามารถใช้ฐานข้อมูลเดียวกันที่ฝั่งไคลเอ็นต์และเซิร์ฟเวอร์ ฉันคิดว่าฐานข้อมูลที่เหมาะสมที่สุดสำหรับลูกค้าจะเป็น SQLite เพื่อที่จะไม่ใช้ทรัพยากรจำนวนมากเนื่องจากแอปจะทำงานบนอุปกรณ์มือถือ ในขณะที่คนที่ทำงานในส่วนของเซิร์ฟเวอร์รู้เพียง MySQL ดังนั้นเราจึงเลือกใช้ ฉันเคยได้ยินว่าเกม MMO ส่วนใหญ่ใช้ฐานข้อมูล MySQL
umair

1
@umair: ฝั่งไคลเอ็นต์สามารถเป็น SQLite (บน iPhone เช่นมีอยู่แล้ว) แต่คุณสามารถเลือกที่จะเก็บเพียงแค่ข้อมูลที่เกี่ยวข้องที่คุณต้องการในไฟล์ (สิ่งที่ SQLite ทำอยู่แล้ว) และไม่รบกวน DB ฝั่งไคลเอ็นต์ในทุกประเภทที่คุณต้องการด้วยแอป Javascript
โคโยตี้

คำตอบ:


15

หากไม่ใช่เกม "เรียลไทม์" ในแง่ที่ว่าผู้เล่นไม่จำเป็นต้องเห็นผลลัพธ์ของการกระทำของผู้เล่นคนอื่นในฉากเกมคุณควรปรับใช้กับคำขอ HTTP แต่อย่าลืมค่าใช้จ่ายของ HTTP

ที่กล่าวว่าการใช้ HTTP จะไม่ช่วยให้คุณประหยัดจากการออกแบบโปรโตคอลการสื่อสารอย่างระมัดระวัง แต่ถ้าคุณรับผิดชอบทั้งเซิร์ฟเวอร์และฝั่งไคลเอ็นต์คุณโชคดีที่คุณสามารถปรับเปลี่ยนโปรโตคอลเมื่อคุณต้องการ

ในการซิงโครไนซ์ระหว่างฐานข้อมูลหลักและฐานข้อมูลลูกค้าคุณสามารถใช้โปรโตคอลการขนส่งที่คุณสามารถเข้าถึงได้ HTTP หรืออื่น ๆ ส่วนที่สำคัญคือการเข้าสู่ระบบหลังการซิงค์ สำหรับแนวทางที่ตรงไปตรงมาให้รวบรวมพูลจากเซิร์ฟเวอร์การเปลี่ยนแปลงล่าสุดทั้งหมดที่ลูกค้าต้องการตั้งแต่การประทับเวลาครั้งสุดท้ายในฐานข้อมูลลูกค้า ใช้กับฐานข้อมูลลูกค้าและไปกับสิ่งนั้น หากคุณมีการเปลี่ยนแปลงเพิ่มเติมเกี่ยวกับฝั่งไคลเอ็นต์ให้อัปโหลดถ้ามันยังมีความเกี่ยวข้องมิฉะนั้นให้ละทิ้ง

เกมบางเกมไม่ใช้ฐานข้อมูลท้องถิ่นพวกเขาเพียงแค่ติดตามสถานะโดยการรวมข้อมูลที่เกี่ยวข้องจากเซิร์ฟเวอร์เมื่อจำเป็น

หากไม่สามารถยอมรับกิจกรรมในท้องถิ่นที่สูญหายได้คุณควรมีที่จัดเก็บในตัวเครื่องและบันทึกลงในที่จัดเก็บบ่อยที่สุดเท่าที่จะทำได้ คุณสามารถลองทำก่อนที่แต่ละเครือข่ายจะส่ง

เพื่อตรวจสอบผู้ใช้ที่ใช้งานอยู่เราเคย ping กับ HTTP ทุก ๆ 20 วินาทีในเกมที่ประสบความสำเร็จ ... ค่านี้สูงขึ้นทันทีเนื่องจากเซิร์ฟเวอร์โอเวอร์โหลดแล้ว :( ทีมเซิร์ฟเวอร์ไม่ได้คิดถึงความสำเร็จดังนั้นฉันจะบอกให้คุณเพิ่ม ข้อความหรือส่วนหัวพิเศษบางอย่างในโปรโตคอลการสื่อสารของคุณซึ่งจะช่วยให้คุณกำหนดค่าไคลเอนต์ของคุณใหม่ (สำหรับการปรับสมดุลภาระโหลดความถี่และค่าที่เกี่ยวข้องกับการสื่อสารอื่น ๆ )

การตรวจสอบด้านไคลเอนต์นั้นเพียงพอหากคุณไม่คำนึงถึงคนขี้โกงแฮกเกอร์และสคริปต์อัตโนมัติอื่น ๆ ที่โจมตีเกมของคุณ เซิร์ฟเวอร์สามารถปฏิเสธการกระทำของคุณและส่งข้อความแสดงข้อผิดพลาดพร้อมรายละเอียดบางอย่าง คุณจัดการกับข้อความแสดงข้อผิดพลาดนั้นโดยการย้อนกลับการเปลี่ยนแปลงภายในเครื่องหรือโดยไม่นำไปใช้กับที่จัดเก็บในตัวเครื่องของคุณหากคุณสามารถรอจนกว่าเซิร์ฟเวอร์ตอบกลับเพื่อบันทึกการเปลี่ยนแปลงจริง

เราใช้รูปแบบคำสั่งในเกมของเราเพื่ออนุญาตการย้อนกลับที่ง่ายและมีประสิทธิภาพของการกระทำของผู้ใช้ที่ล้มเหลวหรือไม่ถูกต้อง คำสั่งถูกเล่นแบบโลคัลส่งไปยังเพียร์หรือแปลไปยังข้อความเซิร์ฟเวอร์จากนั้นนำไปใช้กับเพียร์หรือตรวจสอบบนเซิร์ฟเวอร์ในกรณีที่มีปัญหาคำสั่งไม่ได้เล่นและฉากเกมกลับสู่สถานะเริ่มต้นด้วยการแจ้งเตือน

การใช้ HTTP ไม่ใช่ความคิดที่ไม่ดีเนื่องจากในภายหลังจะช่วยให้คุณสามารถรวมกับไคลเอนต์ Flash หรือ HTML5 ได้อย่างยืดหยุ่นและยืดหยุ่นคุณสามารถใช้ภาษาสคริปต์เซิร์ฟเวอร์ชนิดใดก็ได้และด้วยเทคนิคการสร้างสมดุลภาระพื้นฐานเพิ่มเซิร์ฟเวอร์เพิ่มเติมในภายหลังโดยไม่ต้องใช้ความพยายามมาก เพื่อขยายแบ็กเอนด์ของคุณ

คุณมีหลายอย่างที่ต้องทำ แต่มันเป็นงานที่สนุก ... สนุกมาก!


3
+1 สำหรับ 'HTML น่าจะดีพอ' เพราะอาจเป็น :)
Jonathan Dickinson

1
@ หมาป่า: ขอบคุณที่สละเวลาและให้คำตอบอย่างละเอียด ชอบแนวคิด HTTP ของคุณที่ให้การสนับสนุนลูกค้ารายอื่น
umair

1
แรงอาจมีคุณ :)
โคโยตี้

5

อะไรจะเป็นวิธีที่ดีที่สุดในการซิงโครไนซ์เซิร์ฟเวอร์และฐานข้อมูลลูกค้า

วิธีที่ง่ายที่สุดคือการใช้ฐานข้อมูลเป็นไฟล์เดียวที่คุณสามารถถ่ายโอน หากคุณพยายามเปรียบเทียบความแตกต่างระหว่างฐานข้อมูลนั่นคือโลกแห่งความเจ็บปวดและฉันพูดจากประสบการณ์

โปรดทราบว่าเซิร์ฟเวอร์ของคุณจะต้องไม่เชื่อถือการตัดสินใจที่ลูกค้าทำตามฐานข้อมูลท้องถิ่นนั้นเพราะลูกค้าสามารถเปลี่ยนได้ มันจะต้องมีอยู่อย่างหมดจดเพื่อนำเสนอรายละเอียด

เหตุการณ์ควรถูกบันทึกลงในฐานข้อมูลท้องถิ่นก่อนที่จะอัปเดตไปยังเซิร์ฟเวอร์หรือไม่

ไม่เกิดอะไรขึ้นถ้าเซิร์ฟเวอร์ตัดสินใจว่าเหตุการณ์ไม่เคยเกิดขึ้น? ลูกค้าไม่ควรตัดสินใจเกี่ยวกับเหตุการณ์อยู่ดีเพราะลูกค้าไม่สามารถเชื่อถือได้

ฉันสังเกตเห็นว่าคุณกำลังพูดถึงฐานข้อมูลท้องถิ่นด้วยสองวิธี: หนึ่งสำหรับ "สิ่งที่ไม่เปลี่ยนแปลงบ่อย" และสองรายการสำหรับเหตุการณ์ สิ่งเหล่านี้ไม่ควรอยู่ในฐานข้อมูลเดียวกันด้วยเหตุผลข้างต้น - คุณไม่ต้องการเริ่มพยายามผสานหรือกระจายแถวข้อมูลแต่ละแถวในฐานข้อมูล ตัวอย่างเช่น Referential Integrity กลายเป็นปัญหาเมื่อลูกค้ามีการอ้างอิงไปยังรายการที่คุณตัดสินใจที่จะลบออกจากเซิร์ฟเวอร์ หรือถ้าลูกค้าเปลี่ยนแถวและเซิร์ฟเวอร์เปลี่ยนแถวซึ่งการเปลี่ยนแปลงจะมีความสำคัญกว่าและทำไม?

คำร้องขอ HTTP แบบง่ายจะมีจุดประสงค์ในการซิงโครไนซ์หรือไม่

ใช่การจัดหาไม่บ่อยนักหรือเล็ก HTTP ไม่มีแบนด์วิดท์ที่มีประสิทธิภาพดังนั้นโปรดจำไว้ว่า

จะทราบได้อย่างไรว่าผู้ใช้คนใดที่เข้าสู่ระบบอยู่ในปัจจุบัน? (วิธีหนึ่งอาจให้ไคลเอนต์ส่งคำขอไปยังเซิร์ฟเวอร์หลังจากทุก ๆ x นาทีเพื่อแจ้งว่ามีการใช้งานอยู่มิฉะนั้นให้ถือว่าไคลเอ็นต์ไม่ทำงาน)

หากคุณใช้โปรโตคอลชั่วคราวเช่น HTTP นั่นเป็นแนวคิดที่สมเหตุสมผล เมื่อเซิร์ฟเวอร์ได้รับข้อความจากลูกค้าคุณสามารถอัปเดตเวลา 'ดูล่าสุด' สำหรับไคลเอ็นต์นั้น

การตรวจสอบด้านลูกค้าเพียงพอหรือไม่ หากไม่มีวิธีการคืนค่าการกระทำหากเซิร์ฟเวอร์ไม่ได้ตรวจสอบบางอย่าง?

ไม่เลย. ลูกค้าอยู่ในมือของศัตรู วิธีเปลี่ยนกลับการดำเนินการขึ้นอยู่กับสิ่งที่คุณพิจารณาว่าเป็นการกระทำและผลกระทบที่อาจเกิดขึ้น เส้นทางที่ง่ายที่สุดคือการไม่ใช้การกระทำเลยจนกว่าเซิร์ฟเวอร์จะตอบสนองต่อการอนุญาต เส้นทางที่มีเล่ห์เหลี่ยมเล็กน้อยคือเพื่อให้แน่ใจว่าทุกการกระทำมีความสามารถในการย้อนกลับเพื่อเลิกทำการกระทำและแคชการกระทำที่ไม่ได้รับการยอมรับทั้งหมดบนไคลเอนต์ เมื่อเซิร์ฟเวอร์ตอบรับให้ลบออกจากแคช หากการกระทำถูกปฏิเสธให้ย้อนกลับการกระทำแต่ละอย่างในลำดับย้อนกลับรวมถึงการปฏิเสธ


1
คุณตอกมัน คุณมีความถูกต้องเกี่ยวกับการซิงค์ฐานข้อมูล +1 ลูกค้าไม่ควรเปลี่ยนฐานข้อมูลด้วยตนเอง ... เพียงแค่เรียกใช้ฟังก์ชันที่ทำงานบนเซิร์ฟเวอร์และอัปเดตฐานข้อมูลโดยใช้ logics ของเกมจากนั้นดึงผลลัพธ์
โคโยตี้

@ Kylotan: ขอบคุณที่ชี้ให้เห็นกระแสในแบบจำลองของฉัน
umair

@Kylotan: "วิธีที่ง่ายที่สุดคือการใช้ฐานข้อมูลเป็นไฟล์เดียวที่คุณสามารถถ่ายโอนหากคุณพยายามเปรียบเทียบความแตกต่างระหว่างฐานข้อมูลนั่นเป็นโลกแห่งความเจ็บปวดและฉันพูดจากประสบการณ์" นี่หมายความว่าข้อมูลทั้งหมดจะถูกดาวน์โหลดทุกครั้งที่มีการเปิดตัวแอปพลิเคชัน มีสิ่งต่าง ๆ ที่ไม่เปลี่ยนแปลงบ่อยนักดังนั้นจึงอาจไม่สามารถดาวน์โหลดได้ทุกครั้ง สิ่งนี้จะเพิ่มเวลาในการเปิดตัวแอพอย่างมาก ความคิดใด ๆ
umair

หากข้อมูลมีขนาดเล็กแสดงว่าปัญหาหายไป ฉันจะแปลกใจถ้าฐานข้อมูลส่วนกลางของคุณของข้อมูลคงที่มีขนาดใหญ่มาก แต่อย่างไรก็ตามหากคุณแยกข้อมูลคงที่ออกเป็นส่วนเล็ก ๆ คุณจะต้องส่งข้อมูลที่เปลี่ยนแปลงตั้งแต่ครั้งที่แล้ว แน่นอนว่าคุณสามารถทำเช่นนี้ต่อแถวหากคุณยินดีที่จะให้เวลาในการแก้ไขในแต่ละแถว โดยทั่วไปฉันต้องการมีข้อมูลคงที่นอกฐานข้อมูลเชิงสัมพันธ์เพื่อให้ฉันเขียนทับได้อย่างง่ายดาย
Kylotan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.