I am developing a turn-based MMORPG game server.
A low-level engine (NOT written by us) that processes networks, multithreading, a timer, server-to-server communication, the main game loop, etc. written by C ++. The logic of the high-level game was written by Python.
My question is about the design of the data model in our game.
First, we simply try to load all the player’s data into RAM and the general data of the cache server when the client logs in and the timer is scheduled, periodically dump data into the data cache server and the data cache server will be stored in the database.
But we found that this approach has some problems
1) Some data must be immediately saved or checked, for example, completing a quest, level up, goods and money, etc.
2) In accordance with the logic of the game, sometimes we need to request data from some players of an offline player.
3) Some global world data must be shared between different games, instances that can run on another host or another process on the same host. This is the main reason why we need a data cache server, which is located between the game logical server and the database.
4) The player must freely switch between game instances.
Below we encountered difficulties in the past:
1) All data access operations should be asynchronized to avoid network I / O operations blocking the main logical flow of the game. We need to send a message to the database or cache server, and then process the data response message in the callback function and continue the game. It quickly becomes painful to write some moderate complex game logic, which must speak with db several times and the game logic is scattered in many callback functions, making it difficult to understand and maintain.
2) The ad-hoc data cache server makes things more complex, it is difficult for us to maintain data consistency and efficient data update / upload / update.
3) Requesting data in the game is inefficient and cumbersome, logical logic requires a lot of information, such as inventory, product information, avatar status, etc. Some transactional machinism is also necessary, for example, if one step fails the whole operation should be a rollback. We are trying to create a good data model model in RAM, creating many complex indexes to facilitate a large information query, adding transaction support, etc. I quickly realized that we are building, this is the memory of a database system, we are reinventing the wheel ...
Finally, I move on to seamless python, we removed the cache server. All data is stored in the database. The game logical server directly queries the database. With no stacking python micro tasklet and channel, we can write game logic in a synchronized way. It is much easier to write and understand and significantly improve productivity.
In fact, basic access to the database is also asynchronous: one client talisman to issue a request to another separate DB I / O workflow, and is blocked through the channel, but all the main logic of the game is not blocked, other client talisman is planned and will be executed freely. When the database data respond, the blocked talisman will wake up and continue to work on the “break” point “(continued?).
With the above design, I have a few questions:
1) Access to the database will be more frequent than the previous cached solution. Can a DB support frequent query / update execution? Any mature cache solution, such as redis, memcached, is needed in the near future?
2) Are there any serious problems in my design? Can you guys give me a little better suggestions, especially for the data management template in the game.
Any suggestion would be appreciated, thanks.