I have in mind a traditional MMORPG like World of Warcraft.
Save after every command from each player and autonomous thing (e.g. NPC)
- Constant backup. The server could go down at any moment, and the state of the game is saved up to that moment (or as recent as possible, anyway).
- Impact to server performance; even if it's non-blocking (i.e. on another thread), even if the database is on another server, it is processing that you would otherwise not do. If it is non-blocking like you say, then another thread has to handle it, and that's a thread that could be occupied with something else.
- Increased disk I/O, thus increasing risk/rate of failure. This is especially a concern if you are using SSDs for storage, given their lower life.
- If you offload the database to another server, then increased bandwidth; this might be a concern if you are paying for bandwidth, and if it's not on a separate network card then it's taking up resources that could be better put to use handling player traffic.
- What happens if the server gets further and further behind in saving the state of these commands? I.e. if more commands come in than can be saved, so they pile up in a queue? Does this queue overflow and cause an error? Do you stop everything so the queue can catch up?
- It seems to me that this approach, while it sounds simple, would need to be carefully planned. For example, consecutive commands that rely on each other will need to be saved together; otherwise a failure could occur in the middle of the commands, and only one will be saved but not the other. Consider if two players execute a trade and two commands are saved to disk: "add 1 of the item to recipient" and "subtract 1 of the item from sender". If a failure happens after the first command but before the second command is saved, you have an item duplication. (if the order is reversed, then you have a lost item)
Save everything periodically
- In case of a failure, the server will be somewhat out of date. Hopefully you use something like a journaled approach, so the most recent snapshot will at least be whole and consistent, and all the active players are set back by the same amount of time.
- Whatever database system you use might have an optimization for batch updating, which is more efficient (less overhead) than updating one at a time.
- If you opt instead for a binary file system, this method is dead simple. Make a new file, dump memory into it, throw a marker on the end which signals that the backup was fully completed. Once one backup completes, delete the previous backup (or don't).
- The backup process may also need to account for things mentioned in the last bullet point of the other section, such as saving in the middle of consecutive commands that should not be broken up. You might opt to lock the entire set of data, dump it to disk, and unlock it, but depending on how much time that takes, it could result in a pretty hefty pause or slowdown in the game.
Save a character on logout (don't save anything else)
- The most important thing to a player is their character, which includes the items they have, the skills they've earned, their friends list, and so on. If they kill a monster and the loot is on the ground in front of them and then the server fails, they're going to be a little heartbroken at not having the chance to pick up their loot, but they'll get over it. So just save the important stuff, and don't sweat the small stuff. Don't save the positions of NPCs, for example; if the server goes down, when it comes back up, they'll spawn in the general area that they should be in. The exception, of course, is for any "smart" NPCs that for some reason need to remain in the place they were when the server went down.
- Furthermore, a player shouldn't be logged in for too many hours at a time (note that here I'm considering "going back to a lobby" as logging out). They will eventually need to take a bathroom break or get food or get interrupted by their parent/friend/whatever or sleep. So they really shouldn't realistically be logged on nonstop more than, say, 8 hours for even the most hardcore gamer. If a "player" is logged on for a really long period of time, there's a good chance that it's either multiple people or a bot, and neither one is desirable or normal.
- Also, your logout process should already be checking for things like the above-mentioned consecutive commands. It should essentially already be packing up the character, so it's obviously a prime time to dump it to disk.
- Clearly I'm in favor of the last approach, but I tried to be unbiased about all three.
- It's difficult to say which of the first two methods is more wasteful. With the first method, if the character sends several move commands, these will each be saved to disk and overwritten, when clearly they could be packaged up into one. But with the second method, if you have half of your population standing around, their positions are being saved to disk even if they're the exact same since the last backup operation. In the third case, it is very possible that someone could log on and immediately log off, but most often, many things about the player will have changed so the wastefulness seems like it would be minimal.
- Keep in mind that this is entirely for backup in case of failure, and a failure should be absolutely minimized. It's good to handle this exception case, but in the end, if the server fails, some data is going to be lost and some players are going to be upset. So just implement whatever method you can, whatever you think is simplest or best, and continue on.
- Don't rely on this as the default save; put in a nice shutdown button on your server application, which gracefully closes connections and writes everything to the database. Use that on a normal basis.
Lastly, don't take this advice as absolute truth. I haven't written a multiplayer backup system. I am working on an online "game", which is why I have thought of this and wrote out my thoughts above, but I haven't gotten to the stage of implementing this yet. So this is written without actual experience, but after lots of reading and collecting knowledge about the topic.