MMO database consistency

Started by
5 comments, last by Rycross 14 years, 6 months ago
I'm wondering how MMO game servers should update the database (e.g. MySQL) such that the database is supposed to be consistent. Since a large amount of actions involve updating multiple entites (e.g. trading, fighting), if the game server sends update of individual entites to database, crashing will make the database having an inconsistent state. Is taking 'snapshots' of the whole memory the only solution? Say, the game server takes snapshot of all entites that has flagged 'updated' for every 5 minutes, and send updates to database as one single atomic transaction. But the problem is, during the "snapshot", the game server cannot process normally, so there's a halt period for every 5 minutes. Regarding the snapshot approach, I've another question: suppose I've a database server storing common data, e.g. guilds, which is shared by all game servers (members of a guild can login different game servers). The guild struct contains shared cash or items pool which any guild members can take away. So, when the game server receives player A's request on taking an item from guild pool, it sends the request to database server, and the database server marks the guild struct as 'updated', and send back reply to the game server. Then player B, C, etc, from different game servers, sends similar requests to the database server. So, when the update interval comes, how do the database server updates the database such that the guild struct is consistent with all guild members (who have modifed the pool)? Does it need to wait for ALL snapshots from all game servers, add its own snapshot, and update the database as a huge transaction?
Advertisement
You use Transactions to keep it consistent.

Each transaction should be a single action, for example a trade between two players is done as one transaction.
Quote:Original post by Adam_42
Each transaction should be a single action, for example a trade between two players is done as one transaction.


So you're sending updates to database for every action (e.g. A hits B 10 times => send "A.stamina decrease 1, B.hp decreases 1" x 10 times), rather than grouping all actions in a short period of time (send "A.stamina decrease 10, B.hp decrease 10" once)?
No, instead of sending 2 separate updates you send one transaction (containing 2 updates). The transaction provides a guarantee that the whole of it will complete or none of it.

You'll need to check the mysql docs to see if their supported and to what level. I'm not familiar with it, so can't say. It might be that they still won't be atomic if the server fails hard. At that point your best bet is probably to rollback state a minute or two until you're at a point where you can reasonably assure consistency.
Quote:But the problem is, during the "snapshot", the game server cannot process normally, so there's a halt period for every 5 minutes.

You could use Replication. Then you can query from a replicated DB while your master DB is busy processing big transactions.
It isn't necessary to do a database update for every single trivial change of state. You decide which actions are important and do those updates right away, minor updates can be delayed to the next snapshot.

Important actions would be stuff like trades (player-player or in your example player-guild), death, leveling, zoning, etc. Trades in particular should be done under a transaction to ensure consistency. A good rule of thumb for whether or not it's important is to consider how loudly players will bitch if the action gets lost.

Hp/mana/whatever changes, in-zone location changes, basically anything that happens every tick you just accumulate in-memory. Periodically you update the db with a snapshot of the current in-memory state. You can smooth things out by sending out your snapshot updates in batches a few entities at time continuously instead of all in one huge batch. e.g. the first tick you might snapshot entity 1,11,21,..., the second 2,12,22,..., etc.
-Mike
Quote:Original post by gamelife
Is taking 'snapshots' of the whole memory the only solution? Say, the game server takes snapshot of all entites that has flagged 'updated' for every 5 minutes, and send updates to database as one single atomic transaction. But the problem is, during the "snapshot", the game server cannot process normally, so there's a halt period for every 5 minutes.


In addition to suggestions that you should split up transactions between "important" and "non-important," any snapshot (low priority) updates should happen asyncronously, or on a separate thread. This way, the game can continue updating normally while you're syncing your data.

If you choose to use a separate thread, you can generate save commands for the data that you want to save, add it to a queue, and then have a background thread continually working to process that queue.

You may want to do your important saves syncronously though. Of course, I'm not an expert on designing an MMO in particular.

This topic is closed to new replies.

Advertisement