[转至云风的博客]开发笔记 (2) :redis 数据库结构设计

接上回,按照我们一期项目的需求,昨天我简单设计了数据库里的数据格式。数据库采用的是 Redis ,我把它看成一个远端的数据结构保存设备。它提供基本的 Key-Value 储存功能,没有层级表。如果需要两层结构,可以在 Value 里保存一组 Hashes 。

这是我第一次实战使用 Redis ,没有什么经验。不过类似的设施几年前自己实现过,区别不大。经过这几年,有了 Redis 这个开源项目,就不需要重造轮子了。但其模式还是比较熟悉的。也就是说,是按我历史经验来使用 Redis 。

一期项目需要比较简单,不打算把数据拆分到不同的数据服务器上。但为日后的拆分需求做好设计准备。以后有需要,可以按 Key 的前缀把数据分到不同的位置。例如,account 信息是最可能独立出去的,因为它和具体游戏无关。

用户系统使用 email 来做用户名,但在数据库中的唯一标识是一个 uid 。用户应该允许修改登陆名(用户很可能更换 email)。用户的身份识别是用 id 来定位的。所以,在数据库中就应该有如下几组 Key :

  • account:count id
  • account:userlist set(id)
  • account:email:[email] id

这里,account:userlist 对应的 value 是一个 set ,里面存放了所有存在的 user id 。用于遍历所有的 user 。这个暂时可能用不上,而且当用户量相当大的时候可能有问题。不过暂时不用考虑这么多问题,等以后改进。

account:count 是一个计数器,可以用来生成唯一 id 。

account:email:[email] 用来标示每个注册的 account 的登陆名。[email] 指登陆用 email 地址。

这里,email 内可能也存在符号 ":" ,为了回避这个问题,许多对 email 进行编码。我的方案是,将字母数字 @ . _ 之外的字符编码为 %XX 的形式。用 lua 干这件事情非常简单:

local function _encode(str)
    return string.format("%%%02X",string.byte(str))
end

function emailEncode(str)
    return string.gsub(str,"([^%[email protected]])",_encode)
end

当然,解码回来也很简单

local function _decode(str)
    return string.char(tonumber(str,16))
end

function emailDecode(str)
    return string.gsub(str,"%%(%w%w)",_decode)
end

之后,就是 account 下每个 id 的数据:

  • account:[id]:version number
  • account:[id]:email string
  • account:[id]:password string // md5(password..salt)
  • account:[id]:nickname string
  • account:[id]:lastlogin hashes
    • ip string
    • time string
  • account:[id]:history list(string)
  • account:[id]:available enum(open/locked/delete)

其中,密码不想保存为明文。因为任何可能的数据泄露都会导致用户的损失,我也不想任何人看到用户的密码。所以采用 md5(password .. salt) 的风格。

md5 运算前,加一个 salt 后缀,是因为单纯的文本 md5 值也是有数据库可查的。

lastlogin 下保存了用户最后一次登陆的信息,使用了一张 hashes 表,因为这些信息在未来会进一步扩充。

history 保存了用户登陆的所有历史记录,用一个 string 链表记录。

用户删除自己的账户时,不想把数据从数据库删除,只想在 available 下做一个标记。

考虑到数据库内数据结构有可能发生变化,所以加了 version 域做版本标识。



我不想让各种服务可以直接读写这份数据,所以,会单独写一个认证服务器做处理。

认证服务器提供三项服务:

  1. 用户注册
  2. 用户名 密码 认证 (用于 ssl 连接上的 web 服务)
  3. 用户名 密码 挑战式认证 (用于 client 的认证服务)


下面是基本的场景服务用的数据:

  • 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]:data hashes
    • name string
    • figure string
  • world:scene hashes
    • [name] id
  • scene:count id
  • scene:[id]:name string
  • scene:[id]:available enum(open/close/delete)
  • scene:[id]:info hashes
    • time string
    • pc number
  • scene:[id]:pc hashes
    • [id] enum[online/offline]
  • scene:[id]:pc:[id] hashes
    • status string

用户账号下可以有许多游戏角色,列表放在 account:[id]:avatars 下。

每个角色也拥有一个唯一 id 。这个 id 原则上和 account id 是独立体系,但是为了人类好区格,avatar:count 的起点和 account:count 不同。

角色所在场景记录一个字符串的场景名 avatar:[id]:scene ,角色的其它各种数据放在一个 hashes 里。

所有的场景索引方在 world:scene 下。如果日后有多个世界,可以采用 world:[id]:scene 。但目前不必考虑。

scene 下面的所有 pc 的在线状态放在 scene:[id]:pc hashes 中,pc 离线也把它的 id 记录在内,只有 pc 转移场景才移除。

每个 PC 的位置状态信息记录在 scene:[id]:pc:[id] 中,第一个 id 是 scene 的 id ,第二个则是 PC 的 avatar id 。

btw. 这是一份草稿,虽然思考不周,但足够满足项目一期的需求。当然许多欠考虑的地方也并非是考虑不到,而是希望尽量简单,以满足一期需求为目的。这个日后修改的代价并不大。



最后吐槽一下 Redis 的 Windows 版。办公室的 Linux 服务器还没有装好,我暂时在 Windows 下做开发。取了一份 google 搜到的 非官方 Redis 的 Windows 版 。为了图方便,使用的是 luajit ffi 去调用 hiredis 的 dll 。一开始怎么都搞不定。建立不了 socket 连接,出错码也取不到。

对比了源代码,发现修改版把 C Struct 结构改了,前面增加了几个域,而我以 hiredis 官方标准来定义的接口。

改好后,能够正确取出出错码了。发现万恶的 Windows socks api 需要调用 WSAStartup 才可以用。而 hiredis 的 Windows 修改版居然没有去调用。让我大费周折才改好,前后折腾了一个多小时。

再吐槽一下 hiredis 的 API 设计,居然依赖 C Struct 的布局。良好的 C 库的接口设计不会这么干的吧。比如 lua ,又比如 zmq 。唉,用这种东西有点小不爽。不过比 C++ 库还是好太多了。

时间: 2024-11-09 06:00:59

[转至云风的博客]开发笔记 (2) :redis 数据库结构设计的相关文章

[转至云风的博客]谈谈陌陌争霸在数据库方面踩过的坑( Redis 篇)

« 谈谈陌陌争霸在数据库方面踩过的坑(芒果篇) | 返回首页 | linode 广告时间 » 谈谈陌陌争霸在数据库方面踩过的坑( Redis 篇) 注:陌陌争霸的数据库部分我没有参与具体设计,只是参与了一些讨论和提出一些意见.在出现问题的时候,也都是由肥龙.晓靖.Aply 同学判断研究解决的.所以我对 Redis 的判断大多也从他们的讨论中听来,加上自己的一些猜测,并没有去仔细阅读 Redis 文档和阅读 Redis 代码.虽然我们最终都解决了问题,但本文中说描述的技术细节还是很有可能与事实相悖

Django博客开发-数据建模与样式设定

开发流程介绍 之前Django的学习过程当中已经把基本Django开发学完了,现在以Django 的博客项目完成一遍课程的回顾和总结.同时来一次完整开发的Django体验. 一个产品从研究到编码我们要经历以下的过程: 博客开发需求分析与建模 需求分析 本次项目完成的是一个博客的项目,博客主要目的是为了分享个人的技术,进行技术积累. 主要是发布文章日志.但是也需要有评论和互动.需要完成以下功能点: 1.文章的发布.展示.修改.删除. 2.文章评论 3.读者互动 4.图片管理 概要设计 我们对上面的

博客开发系列(一)

博客开发系列(一) 数据库表的创建 两张表: 文章类型 文章 #一篇博客一种分类 # 一篇博客多种分类 from django.db import models from django.contrib.auth.models import User # Create your models here. class BlogType(models.Model): type_name=models.CharField(max_length=15,verbose_name="博客类型") d

腾讯云搭建hexo博客

腾讯云搭建hexo博客 hexo腾讯云 1. 腾讯云 学生认证购买 重置密码和网络备案 2. hexo博客搭建 2.1 Node.js环境准备 2.2安装git 2.3安装hexo 切换淘宝源 安装hexo 新建一个博客文件夹并初始化 启动 2.4 nginx部署 2.4域名DNS配置 3. 本地搭建hexo,git推送到腾讯云自动部署 4. 小结 1. 腾讯云 学生认证购买 在阿里云和华为云购买失败的前提下,最终找到了腾讯云的购买,学生认证后价格只要10块一月,域名16一年,价格真香,我选择

博客、笔记里用“标签”有啥用?

在博客或笔记里我们可以根据类别把文章分类,比如前端来说,可以分"html"."css"."js","工程化"等等,但是有的文章内容涉及多方面的,觉得它既有很多js的干货,也有不少css的干货,还有些工程化思维,那分在哪个类下呢? 这时就可以使用"标签",可以给它打很多个标签,表示它的类型,而不像传统的分类那样只能归在一个类别下.以后再查资料时再根据这些"标签"来找,比如搜索时加上&quo

django 简易博客开发 1 安装、创建、配置、admin使用(转)

Django 自称是“最适合开发有限期的完美WEB框架”.本文参考<Django web开发指南>,快速搭建一个blog 出来,在中间涉及诸多知识点,这里不会详细说明,如果你是第一次接触Django ,本文会让你在感性上对Django有个认识,完成本文操作后会让你有兴趣阅读的相关书籍和文档. 废话少说,come on!! 本操作的环境: =================== Windows 7/10 python 2.7 Django 1.8.2 =================== 创建

博客开发流程

博客成品:邹振忠的博客 步骤: 1:列出博客大纲:用来干什么:为什么要做:怎么做: 2:列出博客的需求点 3:根据需求点整理出对应的技术文档 4:用workbench画出数据字典 5:开发好后列出我的博客测试文档,逐个测试. 6:上线. 7:复函: A:这次开发花了两个月的闲暇时间,其中60%以上花在了前端上. A.1:自己的前端功力还有待提高. A.1.1:这后面将会输出点击事件:普通点击,未来事件,iframe点击专题文章. A.1.2:输出jquery bootstrap源码解读文章. A

杨泽业:wordpress博客开发技巧之添加快递查询功能

前几天,我说到了给你的博客添加<汉字转拼音>和<二维码在线生成>的功能,这两个功能都是额外增加的,而且是可以增加在任何的网站里面,今天讲的是wordpress博客功能开发,是在wordpress博客模版的基础上添加新功能,调用博客主题的页眉和页脚,侧边栏等. 今天我们就以增加快递查询的功能为例,讲解知更鸟主题,新建一个独立页面应用的方法,并列出详细的步骤,方便小白用户实践操作: 1.下载自己主题里面的默认文章页面,比如我的是page.php,位置在/wp-content/theme

阿里云MVP携手博客园,寻找下一个MVP!专属服务、大咖交流、企业游学等你来!申请就送100元代金券!

"传递技术力量,传承布道精神."阿里云MVP(最有价值专家)第七期全球招募开启,与博客园携手,寻找热爱技术.乐于分享.关注个人成长的你! 戳链接,通过[博客园绿色通道]一键直达: https://mvp.aliyun.com/mvp/apply?recommendType=2&recommendId=qxJWelDeU8KrQWUUyLKtYw== 前20名申请即提供100元代金券,认证成功还送阿里云T-shirt. 如果你是资深开发者,想第一时间接触最新云技术,实现个人能力跃