2011-12-28 11 views
8

के बारे में सुझाव की आवश्यकता है मैं एक टर्न-आधारित आरामदायक एमएमओआरपीजी गेम सर्वर विकसित करने में व्यस्त हूं।एमएमओआरपीजी डेटा मॉडल डिज़ाइन, डेटाबेस एक्सेस और स्टैकलेस पायथन

निम्न स्तर इंजन (नहीं हमारे द्वारा लिखित) जो नेटवर्किंग, बहु सूत्रण, टाइमर, इंटर-सर्वर संचार, मुख्य खेल पाश आदि, सी द्वारा लिखित था ++ संभाल। उच्च स्तर का खेल तर्क पायथन द्वारा लिखा गया था।

मेरा प्रश्न हमारे गेम में डेटा मॉडल डिज़ाइन के बारे में है।

सबसे पहले हम केवल रैम में एक खिलाड़ी के सभी डेटा और एक साझा डेटा कैश सर्वर जब क्लाइंट प्रवेश लोड और एक टाइमर डेटा कैश सर्वर और डेटा कैश सर्वर में समय-समय पर फ्लश डेटा अनुसूची डेटाबेस में डेटा बना रहेगा करने के लिए प्रयास करें।

लेकिन हम इस दृष्टिकोण पाया कुछ समस्याओं

1) कुछ डेटा ऐसी खोज प्रगति, स्तर ऊपर, आइटम & पैसा हासिल आदि

2) के अनुसार रूप में सहेजा जा करने के लिए या जाँच की तुरंत जरूरत है खेल तर्क के लिए, कभी-कभी हमें कुछ ऑफलाइन प्लेयर के डेटा से पूछताछ करने की आवश्यकता होती है।

3) कुछ वैश्विक गेम विश्व डेटा को अलग-अलग गेम उदाहरणों के बीच साझा करने की आवश्यकता है जो एक अलग मेजबान पर चल रहे हैं या उसी होस्ट पर एक अलग प्रक्रिया हो सकती है। यह डेटा कारण है कि हमें डेटा कैश सर्वर गेम तर्क सर्वर और डेटाबेस के बीच बैठता है।

4) प्लेयर को गेम के उदाहरणों के बीच स्वतंत्र रूप से स्विच की आवश्यकता है।

1) सभी डेटा का उपयोग आपरेशन नेटवर्क आई/ओ मुख्य खेल तर्क धागा अवरुद्ध से बचने के लिए asynchronized किया जाना चाहिए:

नीचे कठिनाई हमने अतीत में सामना करना पड़ा है। हमें डेटाबेस या कैश सर्वर पर संदेश भेजना है और फिर कॉलबैक फ़ंक्शन में डेटा उत्तर संदेश संभालना है और आगे बढ़ें गेम तर्क जारी रखें। यह कुछ मामूली जटिल गेम तर्क लिखने के लिए दर्दनाक हो जाता है जिसे डीबी के साथ कई बार बात करने की आवश्यकता होती है और गेम लॉजिक कई कॉलबैक फ़ंक्शंस में बिखरा हुआ है, इसे समझना मुश्किल हो जाता है और बनाए रखता है।

2) विज्ञापन-प्रसार डेटा कैश सर्वर चीजों को और अधिक जटिल बनाता है, हमें डेटा स्थिरता को प्रभावी ढंग से अद्यतन/लोड/रीफ्रेश डेटा बनाए रखना मुश्किल है।

3) इन-गेम डेटा क्वेरी अक्षम और बोझिल है, खेल तर्क ऐसी सूची, आइटम की जानकारी, अवतार राज्य आदि के रूप में कई जानकारी क्वेरी करने के लिए कुछ लेनदेन machanism भी जरूरत है उदाहरण के लिए, यदि एक कदम में विफल रहा है की जरूरत है पूरे ऑपरेशन रोलबैक होना चाहिए। हम रैम, में एक अच्छी डेटा मॉडल प्रणाली बनाने की कोशिश करते हैं, जिसमें कई सूचनाएं कम करने के लिए कई जटिल इंडेक्स तैयार किए जाते हैं, लेनदेन समर्थन इत्यादि जोड़ते हैं। जल्दी ही मुझे एहसास हुआ कि हम क्या बना रहे हैं एक मेमोरी डेटाबेस सिस्टम है, हम पुनर्विचार कर रहे हैं पहिया ...

अंततः मैं स्टैकलेस पायथन पर जाता हूं, हमने कैश सर्वर को हटा दिया। सभी डेटा डेटाबेस में सहेजे गए हैं। खेल तर्क सर्वर सीधे डेटाबेस क्वेरी।स्टैकलेस पायथन के माइक्रो टास्कलेट और चैनल के साथ, हम गेम तर्क को एक सिंक्रनाइज़ तरीके से लिख सकते हैं। यह लिखना और समझना और उत्पादकता बहुत अधिक आसान है में सुधार हुआ।

वास्तव में, अंतर्निहित डीबी पहुँच भी asynchronized है: एक और करने के लिए एक ग्राहक tasklet मुद्दा अनुरोध डीबी आई/ओ कार्यकर्ता धागा समर्पित और tasklet एक चैनल पर अवरुद्ध है, लेकिन पूरे मुख्य खेल तर्क अवरुद्ध नहीं कर रहा है, अन्य ग्राहक का कार्यपत्र निर्धारित और स्वतंत्र रूप से चलाया जाएगा। जब डीबी डेटा अवरुद्ध टास्कलेट को जागृत कर दिया जाएगा और 'ब्रेक बिंदु' (निरंतरता?) पर चलना जारी रखेगा। पिछले कैश्ड समाधान की तुलना में अक्सर

1) डीबी पहुँच हो जाएगा करता डीबी उच्च लगातार जानकारी/अद्यतन आपरेशन का समर्थन कर सकते हैं:

ऊपर डिजाइन के साथ

, मैं कुछ प्रश्न हैं? क्या कुछ परिपक्व कैश समाधान जैसे रेडिस, निकट भविष्य में memcached की आवश्यकता है?

2) क्या मेरे डिजाइन में कोई गंभीर समस्या है? क्या आप लोग मुझे कुछ बेहतर सुझाव दे सकते हैं, खासकर इन-गेम डेटा प्रबंधन पैटर्न पर।

किसी भी सुझाव की सराहना की जाएगी, धन्यवाद।

उत्तर

6

मैंने एक एमएमओ इंजन के साथ काम किया है जो कुछ हद तक समान फैशन में संचालित होता है। यह जावा में लिखा गया था, हालांकि, पायथन नहीं।

के साथ अंक के अपने पहले सेट के संबंध

:

1) async db पहुँच हम वास्तव में अन्य मार्ग चला गया, और एक होने बचा सभी खेल तर्क कार्यों "मुख्य खेल तर्क धागा।" नए धागे के रूप में पैदा हुए थे। थ्रेड सृजन और विनाश का ऊपरी भाग आई/ओ की तुलना में शोर तल में पूरी तरह से खो गया था। इसने कॉलबैक की गड़बड़ी श्रृंखला के बजाय प्रत्येक "कार्य" को उचित रूप से सरल विधि के रूप में संरक्षित किया, जो कि अन्यथा समाप्त होता है (हालांकि इसमें अभी भी मामले थे।) इसका मतलब यह भी था कि सभी गेम कोड था समवर्ती होने के लिए, और हम टाइमस्टैम्प के साथ अपरिवर्तनीय डेटा ऑब्जेक्ट्स पर तेजी से निर्भर हुए।

2) तदर्थ कैश हम WeakReference वस्तुओं का एक बहुत (मेरा मानना ​​है कि अजगर एक समान अवधारणा है?) कार्यरत हैं, और भी डेटा वस्तुओं, उदा के बीच एक विभाजन का इस्तेमाल किया "प्लेयर", और "लोडर" (वास्तव में डेटाबेस पहुंच विधियां) उदा। "प्लेयर एसक्यूएल लोडर;" उदाहरणों ने अपने लोडर को पॉइंटर रखा, और लोडर्स को वैश्विक "फैक्ट्री" क्लास द्वारा बुलाया गया था जो कैश लुकअप बनाम नेटवर्क या एसक्यूएल लोड को संभालेगा। एक डेटा कक्षा में हर "सेटर" विधि विधि changed, जिसके लिए myLoader.changed (this);

आदेश अन्य सक्रिय सर्वर से लोड हो रहा है वस्तुओं को संभालने के लिए, हम "प्रॉक्सी" वस्तुओं है कि एक ही डेटा वर्ग इस्तेमाल किया कार्यरत में एक विरासत बॉयलरप्लेट था कहेंगे (दोबारा कहें, "प्लेयर,") लेकिन हमारे द्वारा खरीदा गया लोडर क्लास एक नेटवर्क प्रॉक्सी था जो (सिंक्रनाइज़, लेकिन गीगाबिट स्थानीय नेटवर्क पर) किसी अन्य सर्वर पर उस ऑब्जेक्ट की "मास्टर" प्रति अपडेट करेगा; बदले में, "मास्टर" प्रति changed स्वयं कॉल करेगी।

हमारे एसक्यूएल UPDATE तर्क में टाइमर था। यदि बैकएंड डेटाबेस को पिछले ($ n) सेकंड के भीतर ऑब्जेक्ट का UPDATE प्राप्त हुआ था (हम आम तौर पर इसे लगभग 5 रखते थे), तो यह ऑब्जेक्ट को "गंदे सूची" में जोड़ देगा। पृष्ठभूमि टाइमर कार्य समय-समय पर जागृत होगा और प्रयास करेगा डाटाबेस बैकएंड को असीमित रूप से "गंदी सूची" पर अभी भी किसी ऑब्जेक्ट को फ्लश करने के लिए।

चूंकि वैश्विक कारखाने ने सभी मूल वस्तुओं के लिए वीक संदर्भों को बनाए रखा है, और किसी भी लाइव सर्वर पर दिए गए गेम ऑब्जेक्ट की एक त्वरित तत्काल प्रतिलिपि की तलाश करेंगे, हम कभी भी एक गेम ऑब्जेक्ट की दूसरी प्रति को तत्काल करने का प्रयास नहीं करेंगे एक एकल डीबी रिकॉर्ड, इसलिए तथ्य यह है कि गेम की इन-रैम स्थिति एक समय में 5 या 10 सेकंड तक की SQL छवि से भिन्न हो सकती है।

हमारा पूरा SQL सिस्टम रैम में चला गया (हाँ, बहुत रैम) एक अन्य सर्वर के दर्पण के रूप में जो डिस्क पर लिखने के लिए बहादुरी से प्रयास करता था। (उस खराब मशीन ने "बूढ़ा युग" के कारण हर 3-4 महीनों में एक बार औसतन RAID ड्राइव को जला दिया।)

विशेष रूप से, कैश से हटाए जाने पर वस्तुओं को डेटाबेस में फ़्लश करना पड़ता था, उदा। कैश रैम भत्ता से अधिक होने के कारण।

3) इन-मेमोरी डेटाबेस ... मैं इस सटीक स्थिति में नहीं चला था। हमारे पास "लेनदेन की तरह" तर्क था, लेकिन यह सब जावा गेटर्स/सेटर्स के स्तर पर हुआ।

और, में अपने बाद के अंक के संबंध:

1) हाँ, PostgreSQL और MySQL में अच्छी तरह से इस के साथ विशेष रूप से सौदा, में विशेष रूप से आप वास्तविक HDD टूट-फूट को कम करने के प्रयास करने के लिए डेटाबेस के एक रैमडिस्क दर्पण का उपयोग करते हैं । मेरे अनुभव में, एमएमओ के हथौड़ा डेटाबेस को कड़ाई से जरूरी है, हालांकि अधिक है। हमारा "5 सेकंड नियम" * विशेष रूप से समस्या को हल करने से बचने के लिए बनाया गया था। "हमारे प्रत्येक सेटर्स changed पर कॉल करेंगे। हमारे उपयोग पैटर्न में, हमने पाया कि एक ऑब्जेक्ट में आम तौर पर 1 फ़ील्ड बदल गया था, और फिर कुछ समय के लिए कोई गतिविधि नहीं थी, या फिर अपडेट का "तूफान" होता था, जहां कई फ़ील्ड एक पंक्ति में बदलते थे। उचित लेन-देन का निर्माण करना या (जैसे ऑब्जेक्ट को सूचित करना कि यह कई लिखने के बारे में था, और डीबी में खुद को बचाने से पहले एक पल के लिए इंतजार करना चाहिए) में सिस्टम की अधिक योजना, तर्क और प्रमुख पुनर्लेख शामिल होंगे; इसलिए, इसके बजाय, हमने स्थिति को छोड़ दिया।

2) ठीक है, वहाँ :-) ऊपर मेरी डिजाइन

असल में, MMO के इंजन मैं इस समय पर काम कर रहा हूँ भी अधिक निर्भरता पर इन-रैम SQL डेटाबेस का उपयोग करता है, और (मुझे आशा है) थोड़ा बेहतर कर रहे होंगे। हालांकि, उस प्रणाली को ऊपर वर्णित ओओपी मॉडल की बजाय एक इकाई-घटक-सिस्टम मॉडल का उपयोग करके बनाया जा रहा है।

यदि आप पहले से ही ओओपी मॉडल पर आधारित हैं, तो ईसीएस में स्थानांतरित करना एक बहुत ही महत्वपूर्ण बदलाव है और यदि आप अपने उद्देश्यों के लिए ओओपी काम कर सकते हैं, तो शायद आपकी टीम जो पहले से जानता है उसके साथ रहना बेहतर होगा।

* - "5 सेकंड नियम" एक बोलचाल यूएस "लोक विश्वास" है कि फर्श पर भोजन छोड़ने के बाद, यदि आप इसे 5 सेकंड के भीतर उठाते हैं तो इसे अभी भी ठीक है।

2

सॉफ़्टवेयर की अधिक समझ के बिना पूरे डिज़ाइन/डेटामैडल पर टिप्पणी करना मुश्किल है, लेकिन ऐसा लगता है कि आपके एप्लिकेशन को इन-मेमोरी डेटाबेस से लाभ हो सकता है। * डिस्क पर ऐसे डेटाबेस का बैक अप लेना (अपेक्षाकृत बोलना) एक सस्ता है ऑपरेशन। मैंने पाया है कि यह आमतौर पर तेज़ है:

ए) एक मेमोरी डेटाबेस बनाएं, एक टेबल बनाएं, दी गई तालिका में एक लाख ** पंक्तियां डालें, और फिर पूरे डेटाबेस को डिस्क

पर बैक-अप करें

से

बी) एक डिस्क बाध्य डेटाबेस में एक तालिका में एक लाख ** पंक्तियां सम्मिलित करें।

जाहिर है, एकल रिकॉर्ड प्रविष्टियां/अपडेट/हटाना भी तेजी से स्मृति में चलाता है। मुझे जावा-डी/अपाचे डर्बी का उपयोग इन-मेमोरी डेटाबेस के लिए सफलता मिली है।

* ध्यान दें कि डेटाबेस को आपके गेम सर्वर में एम्बेड नहीं किया जाना चाहिए। ** इस उदाहरण के लिए एक मिलियन आदर्श आकार नहीं हो सकता है।

संबंधित मुद्दे