zoukankan      html  css  js  c++  java
  • memcached缓存批量更新解决方案探讨

    众所周知,Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。

    俺所在的公司经营的主要是基于web和wap两个平台的手机游戏门户网站,分布式缓存解决方法正好有用武之地,多平台共享使用memcache缓存数据 (php+mysql+memcache),确实很大程度的缓解访问量过大对数据库的压力。但是,在享受便利的同时,同样也遇到相信对大多数 memcache使用者都造成困扰的一个问题:大容量缓存数据的更新难题。

    说起缓存数据更新,可能有些兄弟会说,memcached本身有::delete()方法可以去更新指定key的数据,是的,对显式缓存key的数据我们 可以方便的进行更新,这个是没问题的。我这里指的是指那种复杂的隐式缓存key的数据列表缓存更新问题。因为获取列表时一般会有多个查询条件或排序方式, 加上要指定数据列表的分页,所以往往一个获取数据的方法会产生一组具有相似key的缓存,遇到这种情况该怎么办呢?

    可能有些人还不明白,举个例子吧,例如我需要写一个获取手机游戏列表的方法,因为获取时需要根据手机型号,游戏类型等条件进行查询,还要根据时间,下载数等方式排序。那么就有:
    class DataClass{
    ......
    /**
    * 获取游戏列表
    *
    * @param int
    $modelId 机型ID
    * @param int $gameType 游戏分类
    * @return array  游戏列表
    */

    function getGameList($modelId=null, $gameType = null, $orderKey = "id", $sort = "DESC", $page = 1, $pagePer = 10) {
    /**指定一个具有唯一性的缓存key,也许大家还有别的命名方式,其实都行,只要保证唯一性就行了**/
    $key = $this->memPrefix .
    "game_list_" . $modelId . "_" . $gameType . "_" . $orderKey . "_" . $sort . "_" . $pagePer . "_" . $page ;  
    ......
    }
    ......
    }

    当我更新或删除了一个游戏后,就要把通过这个方法产生的所有缓存都要更新,这里就有问题了。memcached为了性能着想,没有也不会提供对key检索 的功能,也就是你不可能知道通过这个方法已经存在了哪些key,故一个个key的去更新是不可能的。于是就想,要是能把这里所有的key都放到统一标识的 一个组里就好了,这样就能对这组key进行遍历一个个更新,但这个缓存key组怎么存放呢。存到本地缓存,多平台间数据更新不同步;存到memcache 里,大量频繁的对memcache的写入更新,会堵塞获取缓存的网络通道,这个是我通过测试才知道这种方式都多傻的,后果就是memcache一下子变得 奇慢...,看种思路看来不行了。

    去网上东找西找,终于找到另一种更新机制:由时间戳来决定是否更新。先贴写的代码:

    /**
    * 获取游戏列表
    *
    * @param int
    $modelId 机型ID
    * @param int $gameType 游戏分类
    * @return array  游戏列表
    */

    function getGameList($modelId=null, $gameType = null, $orderKey = "id", $sort = "DESC", $page = 1, $pagePer = 10) {
    /**指定一个具有唯一性的缓存key**/
    $key = $this->memPrefix .
    "game_list_" . $modelId . "_" . $gameType . "_" . $orderKey . "_" . $sort . "_" . $pagePer . "_" . $page ;  
    /**这个方法产生的所有的缓存共用一个update key**/
    $update_key = "game_list_update";
    $list = $this->memcache->get($key);
    /**获取要更新数据的时间**/
    $update_time = $this->memcache->get($update_key);
    /**数据为空或写入缓存的时间小于更新时间时则更新**/
    if(empty ($list) || $list['update'] < $update_time){
    /**查询数据库得到数据**/
    $game_list = ...;
    $list = array (
    'data' => $game_list,
    'update' => time(),                   
    );
    $this->memcache->set($key, $list, $this->policy);
    }
    return (!empty($list)) ? $list['data'] : null;
    }


    /**
    * 更新缓存数据
    *
    * @access public
    * @param string $update_key - 缓存更新key
    */

    function updateMemcache($update_key) {
    $update_key = $this->memPrefix . $update_key;
    $this->memcache->set($update_key, time(), array (
    'lifetime' => 0
    ));
    }


    更新缓存:
    $data_class = new DataClass;
    $data_class::updateMemcache("game_list_update");


    相信大家应该从中看出这个思路吧。就是给数据缓存时加一个时间戳,用来与更新时间来进行比较,如果更新时间大于缓存时间,那就说明要进行更新了,否则直接取缓存数据。总算解决了隐式缓存key的数据更新问题!


    转于:www.kissthink.com/archive/memcached-caching-solutions-of-batch-update.html

    http://blog.csdn.net/lxy2520/article/details/7734265

    http://kb.cnblogs.com/page/69074/

  • 相关阅读:
    怎么把创业的风险降到最低
    反思:创业一开始并不需要重量级的产品
    口头承诺不如白纸黑字 技术大牛曹政(前4399核心员工)期权被坑的那些事
    idea配置tomcat去启动web项目
    Closeable释放资源
    Spring的SchedulingConfigurer实现定时任务
    thymeleaf js绑定多个变量参数
    Mysql concat() group_concat()用法
    枚举
    lambda之美
  • 原文地址:https://www.cnblogs.com/Alight/p/3624686.html
Copyright © 2011-2022 走看看