zoukankan      html  css  js  c++  java
  • 手游server之数据IO进化

    这里数据IO是指游戏数据存盘和读取。


    假设IO处理不好。server在IO时会导致。游戏卡顿较长的时间,严重影响游戏体验。


    近期服务端刚好对IO这一块做了优化,把优化过程记录一下。



    一 原始版

    刚開始立项的时候,仅仅是做了一个Demo,加上也刚開始做服务端,仅仅是做了一个仅仅可以測试用的server。


    当时是在每一个场景对象area中加入了一个users对象,通过uid来保存每一个玩家的数据。
    当玩家登录的时候,将玩家的数据读入。退出的时候将玩家的数据写回。

    var users = {};
    
    
    function onLogin(uid){
        var user = DBMgr.read(uid);
        users[uid] = user;
    }
    
    
    function onLogout(uid){
        var user = users[uid];
        DBMgr.write(user);
        delete users[uid];
    }
    

    为了防止server宕机数据丢失,再添加了一个定时存盘。
    function onTick(){
        for (var uid in users) {
            var user = users[uid];
            DBMgr.write(user);
        }
    }
    

    这样做有两个非常明显的问题:
    1 假设一个玩家下线之后马上又一次登录,就会又一次IO的过程;
    2 每次都须要将所有玩家的数据写入。玩家多了之后会卡非常长时间。



    二 进阶版

    为了解决如上问题,添加了一个cache。


    玩家离线后。先将其数据移到cache中,每隔一段时间,将cache中的玩家写入存储介质中。


    登录的时候先在cache中查找玩家的数据,假设找不到。再去读数据。


    然后结构就变成了这样:

    var users = {};
    var cache = {};
    
    
    function onLogin(uid){
        if (!!cache[uid]) {
            users[uid] = cache[uid];
            delete cache[uid];
        } else {
            users[uid] = DBMgr.read(uid);
        }
    }
    
    
    function onLogout(uid){
        var user = users[uid];
        cache[uid] = user;
        delete users[uid];
    }
    
    
    function onTick(){
        for (var uid in cache) {
            var user = cache[uid];
            DBMgr.write(user);
            delete cache[uid];
        }
    }

    然而,前面两个问题并没有彻底地解决掉。


    1 假设玩家下线之后。刚好onTick时间到,这样数据就被写回了,下次登录就得又一次读一次;
    2 若是在onTick这个周期内下线的玩家太多。onTick之中还是会有非常多玩具须要写入。

    三 终极版

    为了优化前面的两点,不再玩家的数据移到cache,而是在cache中保存玩家的下次存盘时间。
    每次登录直接在users中找数据,假设找不到,就读数据库。


    假设玩家下线。就将其下次存盘时间在变为对应的负数,来标记玩家已经下线。


    在onTick中,先将到存盘时间的玩家存盘,然后已下线的玩家从users和cache中同一时候移除。

    var users = {};
    var cache = {};
    
    
    function onLogin(uid){
        var user = users[uid];
        if (!user) {
            user = DBMgr.read(uid);
            users[uid] = user;
            cache[uid] = curTime + WRITE_GAP;// WRITE_GAP为存盘间隔时间
        }
    }
    
    
    function onLogout(uid){
        cache[uid] = 0 - (curTime + WRITE_GAP);
    }
    
    
    function onTick() {
        for (var uid in cache) {
            var time = cache[uid];
            if (curTime < Math.abs(time)) {
                continue;
            }
            DBMgr.write(users[uid]);
    
    
            if (time < 0) { // 离线玩家
                delete users[uid];
                delete cache[uid];
            } else { // 在线玩家
                cache[uid] = curTime + WRITE_GAP;
            }
        }
    };


    这种结构定时存盘一批玩家数据,即使玩家离线也能够在内存中保存一段时间。

    眼下我们的服务端存盘机制就是这种,假设以后有优化再补充。

  • 相关阅读:
    前端的UI设计与交互之布局篇
    前端的UI设计与交互之文案篇
    前端的UI设计与交互之字体篇
    前端的UI设计与交互之图标篇
    前端的UI设计与交互之色彩篇
    Linux学习(一)
    PHP正则表达式基本语法
    PHP正则表达式函数学习
    PHP发送HTTP请求的几种方式
    PHP实现队列
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/6940512.html
Copyright © 2011-2022 走看看