文档章节

游戏服务器-批量读写

l
 leekay
发布于 2016/06/24 15:07
字数 1146
阅读 14
收藏 0

一、为什么要批量读写

    在业务开发中,我们经常需要更新玩家多处数据,如果每条数据都单独更新的话,效率非常低,分别存储的话还需要处理异常回滚,非常麻烦。

二、数据存储类型

    为此我建议在数据存储时尽量使用string存储也就是key-value形式,这一可以利用Redis的Mget和Mset进行批量读写操作,来提高性能。当然例如排名和消息队列这些不适用string的也不用勉强。

三、Module层父类

    该父类封装了玩家和逻辑两个数据库的Mget和Mset方法,用于在夸模块时string的批量数据操作。

class Modules{
    protected $_app;
    protected $_redis;

    /**
     * 创建Redis的连接
     */
    public function __construct(){
        global $app;
        $this->_app   = $app;
        $this->_redis = new MyRedis();
    }

    /**
     * 公共数据库批量读
     *
     * @param $arr
     *
     * @return array
     */
    public function CommonMget($arr){
        return $this->_redis->getCommonRedis()->mget($arr);
    }

    /**
     * 公共数据库批量写
     *
     * @param $arr
     *
     * @return bool
     */
    public function CommonMset($arr){
        if(empty($arr)){
            return null;
        }
        foreach($arr as $index => $val){
            $arr[$index] = setRedis($val);
        }
        return $this->_redis->getCommonRedis()->mset($arr);
    }

    /**
     * 玩家数据库批量读
     *
     * @param $puid
     * @param $arr
     *
     * @return array
     */
    public function Mget($puid, $arr){
        if(empty($arr)){
            return true;
        }
        return $this->_redis->getUserRedis($puid)->mget($arr);
    }

    /**
     * 批量写
     *
     * @param $puid
     * @param $arr
     *
     * @return bool
     */
    public function Mset($puid, $arr){
        if(empty($arr)){
            return true;
        }
        foreach($arr as $index => $val){
            $arr[$index] = setRedis($val);
        }
        return $this->_redis->getUserRedis($puid)->mset($arr);
    }
}

四、获取数据

    当Domain层需要一条数据时,通常调用Module层的查询方法即可。

$hero_pack = $this->hero_module->getHeroPackByPuid($puid);

    而当需要查询多个模块的数据时,如果英雄、装备、道具背包和角色信息时,使用常规方法就会是这样

$hero_pack = $hero_module->getHeroPackByPuid($puid);
$equip_pack = $equip_module->getEquipPackByPuid($puid);
$item_pack = $item_module->getItemPackByPuid($puid);
$role_info = $role_module->getRoleInfoByPuid($puid);

而如果使用Mget则只需一次查询即可

//以Role模块的Domain层为例
$keys = array(
    Redis_Pfx_RoleInfo . $puid,
    Redis_Pfx_HeroPack . $puid,
    Redis_Pfx_EquipPack . $puid,
    Redis_Pfx_ItemPack . $puid,
);

//Role模块调用自己Module层里父类的Mget方法
$data = $this->role_module->Mget($puid, $keys);

//将批量获取的数据分配到变量,千万不要直接拿$data[0]去用,维护起来糟糕
$role_info_data       = $data[0];
$hero_pack_data       = $data[1];
$equip_pack_data      = $data[2];
$item_pack_data       = $data[3];

//调用数据所属模块的数据格式化方法
$role_info = $role_class->getRoleInfoByData($role_info_data);//角色信息
$hero_pack = $hero_class->getHeroPackByData($hero_pack_data);//英雄背包
$equip_pack = $equip_class->getEquipPackByData($equip_pack_data);//装备背包
$item_pack = $item_class->getItemPackByData($item_pack_data);//道具背包

四、批量存储

    批量存储与批量读也是类似的,但需要多一步数据转换的操作,我会将数组转换为Json再存入数据库,为什么选择Json而不是序列化,后面细讲。批量存储还有一个好处就是,在业务操作时中断对数据库中的数据都没有任何影响,不需要处理太多的数据回滚,只有所有业务都跑通之后统一进行数据库修改。类似于事务(也可以直接用Multi开发事务),当然跨库操作需要手动回滚数据。这样不但写库效率高,而且数据操作的安全性也得到保障。

//以Role模块的Domain层为例
$sets = array(
    Redis_Pfx_RoleInfo . $puid => $role_info,
    Redis_Pfx_HeroPack . $puid => $hero_pack,
    Redis_Pfx_EquipPack . $puid => $equip_pack,
    Redis_Pfx_ItemPack . $puid => $item_pack,
);

//Role模块调用自己Module层里父类的Mset方法
$result = $this->role_module->Mset($puid, $sets);

五、函数支持

    处于对批量查询的支持,我们应该在Domain层提供一个格式化数据的函数,它的主要用处有两点:
    1. 初始化数据,例如获取玩家的英雄背包,新注册的玩家该数据是空的,而使用Redis的话不会像Mysql哪有有表结构,所以需要返回一个数据结构如: 

   /**
     * 初始化英雄背包(包含英雄和契约石-也就是碎片)
     *
     * @param      $data
     * @param null $config
     *
     * @return array
     */
    public function getHeroPackByData($data){
        $hero_pack = dataToArray($data);//自定义函数:如果数据是Json则转换为数组
        if(empty($hero_pack['Hero'])){//如果英雄列表不存在
            $hero_pack['Hero'] = array();//初始化
        }
        if(empty($hero_pack['Contract'])){//如果契约石不存在
            $hero_pack['Contract'] = array();//初始化
        }
        return $hero_pack;
    }

   /**
     * 获取英雄背包
     *
     * @param $puid
     *
     * @return array
     */
    public function getHeroPackByPuid($puid){
        $hero_data = $this->hero_module->getHeroPackByPuid($puid);
        return $this->getHeroPackByData($hero_data);
    }

    2. 数据的统一业务处理

        例如,每次获取角色信息时,我们应该根据上次体力的恢复时间和恢复间隔为玩家恢复体力,更新玩家的活跃时间,只需要写在初始化数据函数中即可。

无论是单次查询还是批量查询都用格式化函数处理一下原始数据再使用,形成这样的约束。

 

© 著作权归作者所有

共有 人打赏支持
下一篇: 项目建议
l
粉丝 1
博文 17
码字总数 6436
作品 0
虹口
程序员
私信 提问
腾讯云推高IO版云数据库,满足游戏等IO密集型行业需求

近日,腾讯云宣布正式推出高IO版云数据库(CDB),经过多年积累,多个迭代的优化,高IO版CDB在性能上提升高达10倍,QPS(每秒查询率)高达37000,领先业界,可以很好地满足游戏、移动应用等I...

现在的曾经
2015/06/30
519
1
Redis 通讯协议分析

简介 Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。Redis的性能非常出色,每秒...

IamOkay
2018/01/15
5
0
自己独立开发的一套运维管理平台

很久没有写博客了,今天突然来了兴致就上来看看,把自己花了2个月写的一个运维管理平台展示一下,各位大牛不要笑话写的简陋哦,想交流运维开发的朋友可以加群:455247653,共同学习共同进步。 ...

wiliiwin
2016/10/24
0
0
国内唯独一家卖带GPU显卡云服务器的资源商,支持安卓模拟器

可以用安卓模拟器玩游戏的服务器、安卓模拟器玩游戏的服务器、安卓模拟器玩游戏的服务器。雷电模拟器, 1、E5-2690至尊CPU,极大的提高机器性能。 2、高端显卡NVIDIA grid m60-1q显卡,4G显存...

李百不喝酒
2018/07/20
0
0
关于阿里云,除了首台半价,你还应该知道点什么

这几天,圈里都在讲阿里云服务器企业首台半价的事情。 --------------------啊?你不知道?暂停!先补课!----------------- 活动地址快戳: http://click.aliyun.com/m/1709/ -------------...

阿里云官方博客
2015/08/20
1K
2

没有更多内容

加载失败,请刷新页面

加载更多

Windows同步对象Event和Linux的条件变量

最近在看一些同步对象模拟的东东,特别对在Windows下如何模拟条件变量折腾了很久。 1 Windows同步对象Event 微软有一个很有意思的同步对象,某种程度上和Linux的条件变量很相似。但秉承微软一...

shzwork
11分钟前
0
0
从上往下打印出二叉树的每个节点,同层节点从左至右打印。

//第一种做法 public class Solution { public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) { ArrayList <Integer> li=new ArrayList<Integer>(); ArrayList <TreeN......

南桥北木
21分钟前
0
0
linux 服务管理 Crontba、Ntpdate、Logrotate、Supervisor

crond linux 系统则是由 cron (crond) 这个系统服务来控制的。Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的。 另外, 由于使用者自己也可以设置计划任务,所以,...

狼王黄师傅
51分钟前
3
0
Sobel算子和Scharr滤波器

Sobel算子在数学上的本质是微分,对离散信号,是求邻域内的增量。 基本原理:在图像上,对图像信号在某点进行微分,表示图像的某个特征(如,强度、色调或者饱和度)在该点的变换程度。以强度...

yepanl
今天
2
0
Jenkins API 使用

Jenkins 是一款流行的开源持续集成工具,可以用来做一些软件开发的自动化工作,如打包,测试,自动部署等。 Jenkins 中有 view 和 job 的概念, view 相当于组, job 则是具体的任务。 view...

YanWen
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部