Game Development Community

MMO Backends - Database Hell

by Flybynight Studios · 07/18/2007 (12:12 pm) · 8 comments

Preface:
It's been a while since I posted any updates on what I've been up to so I thought I'd share some MMO DB thoughts and considerations. Keeping in mind I've been on a 6 month hiatus due to RL work complications I'm just getting back in the drivers seat now and thought going over some of the changes and database implementations I've been working with would be a great refresher. Please note that I am not a guru at any of this and it's taken the efforts of a lot of people to get my project where it is today. Some extra special thanks goes out to Vince Gee, Harold Brown and Stephen Zepp for all of their assistance over the years.
-preface off

What is an MMO really? Everyone has their own ways of viewing it but I always revert back to that scene in the matrix 1 where at the end of the show everything turns into streams of binary.. THAT is an MMO. Datastreams, Datahandling, Datamanagement... It's all about the data. Until you can deal with the data handling properly, all of the 3D resources in the world mean nothing.

I've been working on Aakrana for years. It's a hobby project (so I keep telling myself) until someone offers me $100k to finish it and I've made tons of mistakes, gone through many "engines" and had to scrap months of manhours worth of work on more than one occasion and do a ground up rewrite on the major subsystems. I don't regret making mistakes, I can honestly say that the mistakes were honest ones, mostly due to lack of experience, and that every time I make a major mistake I learn from it and the entire project gets better.

One of the biggest mistakes I made was worrying about the graphics and artwork. It's not about graphics.. Who cares about your beautiful 3D world if you can't do anything with it? It took me a long time but I finally think I got the message and sometime last year I really focused hard core on the datastructuring and database handling. Best thing I ever did :) (Next to buying Torque of course.)

Do you know what your datastream footprint will be in an MMO? Any guesses? Well you should. Designing a database without having any idea what kind of traffic or what shape of traffic streams you are going to be dealing with is like trying to design a sports complex without knowing what sport will be played there. Designs will change of course and that's part of the whole experience thing but at least laying some ground rules is so important when you are getting started. How many stats will your players have? How many variables in a player object, how will you handle unique appearances, skills, training, equipment, all these things are a critical part of your player datastream and more specifically your database footprint.

What happens when a player attacks something? 'Interacts' with something? Changes his equipment? Has his faction adjusted? Everyone of those things causes a ripple effect that shoots out to every other player object within his sphere of influence. (In an unmodified TNL setup this would basically be every other player in the current mission area) So would it be OK to just call on the database everytime there is something happening and wait for a response? Sure you could do that. It would work.. But what happens as the number of players scale up? 20 players? It would be OK, a bit of lag for sure depending on how many of them are doing dataupdates to the DB, but what about 50 players? 100 players? In my case I set my 'acceptable load' tolerance goals for 100 players in a close area all interacting and needed to design a database setup that worked for that.

In the early days of my development (back when I was truely clueless) I was using a flatfile to store data. No offence to folks using flatfiles, they work and that's fine. Fact is though they are not scaleable, not flexible (at all) and very unforgiving to errors and structure changes. Certainly not capable of handling the demands of an MMO datastream. Consulting with many ( and I mean MANY) DB gurus on many websites and forums I settled on MySQL. (MSSQL is a perfectly viable option, I just felt I could push MySQL farther performance wise and didn't want to be shackled by the licensing issues of Microsoft products) MySQL could handle the RPS (requests per second) of an MMO and has been used by multiple triple A MMO companies in the past. So What does MySQL give you over a flatfile? Flexibility, expandability, accuracy and stability.

So where are we at now? The client logs in, his character data is requested by the server, tossed into a massive array of variables on the server and streamed out to the client where it is again tossed into a massive array of variables on the client and streamed out to anyone as needed. Sounds fine right? Nope. How do you decide when to save datachanges back to the database from the variables? What happens if the mission area crashes? What happens if someone is doing a transaction with another player object and crashes? Nightmares that's what happens :)

Here the solutions can vary quite a bit depending on the actual traffic patterns between your mission servers and your DB server. In my case, for Aakrana, we came up with a hybrid system using SQLlite as a mission server localized caching system for the actual MySQL transactions. Working with database queries is a science. Any amateur like myself can make DB queries work but it takes a professional to make them work well. In my case I was fortunate enough to have met some incredibly talented DB people in the process of making the game. (A couple years back I was working with 2 DB admins who worked at NASA.. yeah I'm serious. That rocked) The current implementation of the Aakrana DB was the brainchild of Vince Gee, an exceptionally skilled coder and DB analyst here in the Torque community. Vince tossed all of the DB calls from Torque script into C++ (Massive performance improvements) and then developed a tiered system of 'critical' and 'non-critical' data. The critical data being data that is manipulated almost constantly (health, stamina, cash, inventory, transfer location data) where the non critical data being things like quest variables, factions, names, etc were all variables that were not changed or called nearly as frequently. By doing this Vince was able to write code to update the MySQL tables when "critical" data adjustments were made without having to dump massive amounts of data back to the DB as a "save" every 60 seconds to maintain persistence. by maintaining a local SQLlite caching of all of the critical and non-critical data (which would write back to the MySQL DB on a random timer) we always had a local backup of the player data snapshot at any given time incase of a mission server failure.

At this point (and yes I am almost done here for today) we have a very powerful, persistent and redundant datastream that scales up well into the 100 players per mission. Great, but lets make it better :) Optimization. Generally you don't even touch optimization until your codebase and scripts are at least beta quality or near release as optimizations will change depending on changes you make. In my case I'm a bit of a performance analyst and I saw some obvious gaping holes that screamed to be fixed immediately so I made some adjustments pre-emptively to improve performance down the road. By default you would hammer down streams of variables as servercmds to your client either onmissionstart or during the mission. Vince took all of the critical mission vars and moved them into the C++ datastream to optimize them there and I setup SQLlite on the client side for all of the static game data. Quest tables, item tables, NPC tables, basically anything static in the world that might end up being sent as a variable could now be sent as simply an item# by the server and that item number is cross-refd at the client on it's local SQLlite DBs. The datastream savings here are tremendous if you scale them by player. A person could get carried away with this, but here is just an example:

Race table:
1- Human
2- Ithchykabutchis
3- Hairyscaries
4- Killalottalittathings

I think its pretty easy to see that if you have hundreds of players interacting and each one needs to know the others race (as a varaible) it is much cheaper bitstream wise to send a simple '4' than to send down 'Killalottalittathings'. Same with inventory.. Way easier to send down a '65373' than 'Vorpal sword of etheral Vanquishing'.

That's it for now guys. I hope this long winded blathering was of some use to someone. It helped me refresh my own memory as to where I'm at. Aakrana is coming along. I'm still nailing down some GUI issues but I hope to truly be starting some serious world building.. 'soon'(tm) ;)

None of this would be possible without the hard work of a lot of people who have helped me in either a consulting capacity or hands on coding/DB capacity (Thanks Vince you are a champion). Most importantly I want to thank the community here at GG as one of the greatest indie development resources out there. Some outstanding people here and I'll never forget all the help they've given.

#1
07/18/2007 (12:38 pm)
Vince is indeed a champion!
One of the other design tools you can use is to do blind DB writes on a separate thread for updating information. Doesn't hurt performance at all, as it's not waiting on anything.
#2
07/19/2007 (3:11 am)
One thing I've been seeing in some MMO architectures is to have a client proxy at the server cluster end. This client proxy basically sits between a group of clients and the server backend. The advantage of this, is that you can aggregate update information at the client proxy such that it cache's common data and thus doesnt require a lot of server updating to keep things working.

An example would be that instead of each connection asking the server for updates on object positions, the object positions are requested by the proxy and cached for the number of clients its handling. This means that the server deals with N/M clients, with N being number of player clients and M being number of proxies (assuming lets say a ration of 150 clients per proxy) rather than N clients. It means that internally to your server cluster you are organising less data.
#3
07/21/2007 (1:00 pm)
Sounds pretty cool. One thing I'm interested in is how you're verifying the integrity of the local SQLite cache? If you're storing things there that could possibly alter the game's interaction with the player (aside from the obvious things like health, inventory, money, stats etc. you might have issues with things like faction ratings, quest completion flags or the like...) you'll probably want some sort of check to ensure dodgy players don't alter the SQLite DB before it's sent out. Player exploits to the game world can have a very serious effect on the integrity of the game's economy, or just be hugely annoying (e.g. people being able to arbitrary teleport around a zone in Everquest).
#4
07/21/2007 (5:29 pm)
Good point to touch on Ross. I totally missed mentioning that. All of the client side data is for the client info only. Any action or activity that is attempted clientside is just a trigger event that the server then checks the validity of.

Example:
Client adjusts some memlocks to change 'a rusty dagger' to Vorpal sword of arse whoopage... Thats fine.. on the client side the client may show he has equiped the said legendary sword of pwnage.. then when he goes to attack the client sends the command to the server to initiate combat.. No problem says the server. The server then looks at it's local info for the client and sees that it is attacking "FieryDemon129" with "a rusty dager" and processes combat rounds accordingly..

Example2:
Client adjusts his Dexterity to be 5293 instead of 12.. Client attacks "RobinRedBreast" and sits back. The server sees clientXYZ initiating combat. Server checks the serverside target variable for ClientXYZ, checks the server side stat variables for clientXYZ and sees his dex is 12.. Server processes all functions .. The server is in charge at all times.. Nothing that is edited on teh client has ANY bearing on the server. The client is simply a window into the datastream that the server is maintaining for the clients game.

Example3:
Client hacks Item123 that is normally a chestpiece and makes it into an earing. (simple variable adjustment of the item) The client then shows on his end that the item in question can be dropped in teh ear slot. Client attempts to move said item to the ear slot and this is what the server sees.. "ClientXYZ is attempting to drop invitem.bag2.item543 into client.slots.slot2". The server then does a quick check server side and notices that the item in the clients inventory at loc bag2/item543s a chestpiece and is not allowed in the ear slot and gives the "You can not equip that item here."

It's good that you are paying attention to that kind of stuff Ross. Alot of people dont. They just close their eyes and pray to God that when the poo hits the fan they are miles away. Designing a good solid transaction structure is essential to evening begginging to dream about making an MMO. Untill someone has got their head around that kind of stuff they have no business even pretending to work on an MMO :)

In my case, the entire client is, as I said before, merely an interpreter of the datastream for what is taking place on the server. The client can never push absolutes back to the server or manipulate items specifically. All the client can do is tell the server it wants to use itemXYZ from slot123 and the server does the appropriate checks and balances.. It's hack proof. The only thing the hackers can do is actually hack your server and THEN really screw with you :)

Good point though. Glad you mentioned it.

Just for clarities sake: In the end I dont give a damn if the end user wants to make his client show him having a million HP and dual wielding Holy archangel staffs of the apocalypse while wearing a legendary chest piece on his head as a hell. In the end the only data that matters is what the server sees. And since the data on teh server is never pushed from teh client the server KNOWS what the client has and can do with those items. Hope this is clear :)
#5
07/21/2007 (7:28 pm)
More clarification since I got an email on this. All your client side SQLite should be doing is assisting in reducing your datastream. It is only meant as a fast/felixble way to access datatables and convert ID#s from the server into viewable object information.

You would (almost)never want to run any kind of process using the local info. You simply use the local info to stop your client from having to call the server and request every little piece of info about every little item/quest object/race/statistic/skill in the entire virtual world :)

I probably should have left the SQlite thing out so as to simplify this but it's just common sense to use ID#s from a server cmd and resolve those IDs client side using a flatfile/SQlite table.

Example:
Character loots a "vorpal flaming sword of redemption".. The server COULD send down the pipe to the client that he has just looted a "vorpal flaming sword of redemption" with +200 to STR, +200 to CON, +200 to INT, +200 well I think you get it.. But thats not all!! If you call in the next 30 seconds I'm also goign to instruct the sword to give you my famed "WordofDeath" skill that can be called every 5 minutes and will smite your foes with the curse of the gods instantly causing them to cease to exist...

Or....

I could simply have the server tell the client they recieved obj5326. End of story.

Now server side, the server checked the loot table when the client opened the treasure chest and spawned the object.. Instead of sending all that rediculous ammount of data down to the client the server just had to say "show client obj#5326". When the client picked it up, they didnt get to tell the server they wanted obj5326... All they got to tell the server is that they wanted to pick up item 1 in the current loot window. The server checked its vars and sees that item 1 is obj5326, afore mentioned vorpal sword of etc etc. The server pops the item into the clients next open inventory slot server side and THEN sends the client the command "you just looted Obj5326 and put it in slot bag2.slot45.

I think it should be pretty clear how this works guys. Not sure how much more I can clarify this. If you dont understand the concept you should write it all down on paper till it makes sense :)

Good luck in your work.
#6
07/21/2007 (8:35 pm)
Ah yeah, that all makes sense. It was just unstated in the original post whether the SQLite database would be used to push values back to the server, which obviously would be bad. Sounds like you've got a solid system going.

I would hesitate to deem any game "hack proof" without having anyone there to exploit it. For instance, the warping exploit I mentioned above was created by disassembling Everquest's binary and finding the function used to move the player to a safe location if they'd fallen through the world or become stuck. After that, a simple matter of getting the location of the function in memory and passing it arbitrary x,y,z values.

A similar exploit is possible with the resurrect spell in EQ (among other spells, but resurrect is "secure" in that there's no way for the logs to show a discrepancy, since anyone can be resurrected from any zone to another, where teleport spells, the "gate" (return to home zone) spell, etc. would show one going to the "wrong" zone, and if your character doesn't have that spell, big red flag), which allows one to zone to any zone (including the GM zones hehe).

Now, none of this becomes a real problem if it's extremely difficult to pull off (most people can't disasm and get anything fruitful out of it) since the community of people that are skilled and do such things do it for fun rather than to ruin the game's economy or make the experience suck for others (that is to say, most aren't gold farmers).
#7
07/21/2007 (9:15 pm)
No you are right on Ross. Nothing is really "hack proof". A good solid concept that is thought through (liek you obviously have) is your best defense though.

EQs problem (And yes I am very familiar with it :) ) was that they had code on the client that code be activated.. If your game doesnt have the code on the client to be hacke dout of it.. nothing much at risk. The real risk of a Torque based game (or one of the bigger risks at least) is simply the datastream. All MMOs have this risk and although there ARE some ways to combat it it's generally never worth the effort you put into it as hackers always will find a way to beat your datastream. Hell SoE gave up trying to stop the ShowEQ guys years ago. Their DS was a dogs breakfast anyways but it was kinda sad that you could sit there playing on one PC and have the entire zone and every object in it (including their current loot tables) up on another screen showign you were to hunt :/

I'm an ex-hack. Probably why I spent so much time designing my dataflow :) I worry abotu what peopel will do with my game when they get it but I dont lose sleep over it. I've done the best I can and I'll let the chips fall where they may :)

Thanks or pointing out the issue with localized variable storage. I was very negligant to not clarify that in the OP.

Cheers
#8
07/21/2007 (9:41 pm)
Yeah, that is definitely EQ's problem. Most newer games have everything server side (much like your own design), so are much less exploitable. As you note, the only other thing is the data between client<->server, which can possibly be exploited, but there's little to be done there except possibly having the server perform integrity checks against previous values or the like. And besides, anyone willing to go through the trouble that has the appropriate know how will likely get something in any case. As long as there isn't anything glaringly bad such as being able to alter things related to the economy, things are usually okay.

I used to do a bit of EQ exploiting for fun (after getting fed up with all the EQ clones, and its terrible gameplay, there was little left else to do), which was far more fun than the game itself. It's quite eye opening learning how to do that stuff, in terms of what needs to be done to ensure a basic level of security for these types of games. Really though, the exploiter community sort of ensures a basic level of security through their own methods. Most of it is underground to the extent where people that would abuse it are excluded, since that also usually means the people that found such exploits will lose them due to the developer noticing the newbs using it and patch.

I think my favorite EQ hack was flipping the "swimming" bit while on land, so you could "fly" around. Good times.