Last time, according to the requirements of our project, I designed the data format in the database yesterday. The database uses Redis, and I think of it as a remote data structure storage device. It provides basic key-value storage functions, no hierarchy tables. If you need a two-tier structure, you can save a set of hashes in Value.
This is the first time I have used Redis in real life, and I have no experience. But similar facilities have been implemented by themselves a few years ago, with little difference. Over the years, with the open source project of Redis, there is no need to re-create the wheels. But its model is still relatively familiar. In other words, I use Redis according to my historical experience.
The first phase of the project needs to be relatively simple and does not intend to split the data onto different data servers. But for the future of the demand for the separation of design preparation. In the future, the data can be divided into different locations by the Key prefix. For example, the account information is most likely to go out independently because it has nothing to do with a specific game.
The user system uses email to do the user name, but the unique identifier in the database is a UID. Users should be allowed to modify the login name (users are likely to change email). The identity of the user is identified by ID. Therefore, you should have the following set of keys in the database:
- Account:count ID
- Account:userlist Set (ID)
- Account:email:[email] Id
Here, the value of account:userlist corresponds to a set, which holds all the existing user IDs. Used to traverse all the user. This may not be available for the time being, and may be problematic when the user volume is quite large. But for the time being not to consider so many problems, and so on later improvement.
Account:count is a counter that can be used to generate a unique ID.
Account:email:[email] is used to indicate the login name of each registered account. [email] means the login email address.
Here, there may also be a sign in the email ":", in order to avoid this problem, many of the email encoding. My plan is to put the alpha-numeric @. The character encoding outside _ is in the form of%XX. Doing this with Lua is simple:
local function _encode(str)
return string.format("%%%02X",string.byte(str))
end
function emailEncode(str)
return string.gsub(str,"([^%[email protected]])",_encode)
end
Of course, it's easy to decode it back.
local function _decode(str)
return string.char(tonumber(str,16))
end
function emailDecode(str)
return string.gsub(str,"%%(%w%w)",_decode)
end
After that, it is the data for each ID under account:
- Account:[id]:version number
- Account:[id]:email string
- Account:[id]:p Assword string//MD5 (password.. Salt
- Account:[id]:nickname string
- Account:[id]:lastlogin Hashes
- Account:[id]:history List (String)
- account:[id]:available enum (Open/locked/delete)
Where the password does not want to be saved as plaintext. I don't want anyone to see the user's password because any possible data leaks can result in a loss to the user. So adopt the style of MD5 (password. Salt).
MD5 before the operation, add a salt suffix, because the simple text MD5 value is also a database can be checked.
Lastlogin saved the user's last login information, using a hashes table, as this information will be further expanded in the future.
History holds all the historical records of the user's login and records it with a string list.
When users delete their account, they do not want to delete the data from the database, just want to make a mark under available.
Given that the data structures within the database are likely to change, the version domain is added to the build identity.
I do not want to let the various services can read and write this data directly, so, will write a separate authentication server to do processing.
The authentication server provides three services:
-
User Registration
-
User name password authentication (for Web services on SSL connections)
-
User Name Password challenge authentication (for Client Authentication service)
Here is the data for the basic scenario service:
- Account:[id]:avatars Set (ID)
- Avatar:count ID
- Avatar:[id]:version number
- Avatar:[id]:account ID
- Avatar:[id]:scene string
- avatar:[id]:available enum (Open/delete)
- Avatar:[id]:d ATA hashes
- Name string
- Figure string
- World:scene Hashes
- Scene:count ID
- Scene:[id]:name string
- scene:[id]:available enum (Open/close/delete)
- Scene:[id]:info Hashes
- Scene:[id]:p c hashes
- [ID] enum[online/offline]
- Scene:[id]:p C:[id] Hashes
There are many game characters under the user account, and the list is under Account:[id]:avatars.
Each role also has a unique ID. This ID is an independent system in principle and the account ID, but for the human good, Avatar:count's starting point and Account:count are different.
The scene in which the character is located records the scene name of a string avatar:[id]:scene, and the other data of the character is placed in a hashes.
All the scene indexes are under World:scene. If there are more than one world later, you can use World:[id]:scene. But there is no need to consider.
The online status of all PCs under scene is placed in Scene:[id]:p C hashes, and the PC is offline with its ID recorded, only the PC transfer scene is removed.
The location status information for each PC is recorded in Scene:[id]:p C:[id], the first ID is the ID of the scene, and the second is the Avatar ID of the PC.
Btw. This is a draft, though poorly thought out, but sufficient to meet the needs of the project phase one. Of course, many of the areas under consideration are not to be considered, but to be as simple as possible to meet the needs of a given period. The cost of this change is not very big.
Finally, spit out the Windows version of Redis. The Office Linux Server is not installed yet, I am temporarily doing development under Windows. Took a copy of the Windows version of the unofficial Redis that Google searched for. To facilitate the diagram, the Luajit ffi is used to call the Hiredis DLL. I can't get it out of the beginning. The socket connection cannot be established, and the error code cannot be taken.
Compared to the source code, found that the modified version of the C struct structure changed, the front added several domains, and I hiredis the official standard to define the interface.
After the change, you can correctly remove the error code. Discover the evil Windows Socks API needs to call WSAStartup to use. And Hiredis's Windows modified version actually did not go to call. Let me a lot of trouble to change the good, back and forth tossing for one hours.
And then spit it out. Hiredis API design, actually relies on C Struct layout. Good C library interface design won't do that. Like Lua, like ZMQ. Alas, it's a little uncomfortable with this stuff. But it's much better than the C + + library.
[Go to Cloud Blog] Development notes (2): REDIS database structure Design