文档章节

cache缓存失效高并发读数据库的问题

昨日今日明日
 昨日今日明日
发布于 2012/12/11 00:19
字数 911
阅读 443
收藏 9
点赞 0
评论 1

在网上看到有用其他语言实现的例子,这里用php写下,以加深理解。

用php具体代码实现

首先设计一个访问数据库的模型类

class model
{
    function getlist($catid)
    {
        
    }
}

方法一:

$cache = new cache(); //实例化一个已封装过的memcache类

function getnewlist($catid)
{
global $cache;

$key = "newslist-catid=".$catid; //设置一个cache key

$value = $cache->get($key); //获取key对应的cache

if($value == null) //key 对应的cache过期
{
    //按说过期的时候就应读取数据库 用getlist($catid)方法了。在小流量小并发时不会出现什么问题,当大并发时,可能会有几千个人同时访问到了cache失效,如果都去读取db的话,会造成db资源浪费甚至崩溃
   并发读取数据库势必会造成很慢的情况,如果还没有从数据库中读取出来并写入到cache中。这时候再有人访问过来,就又进入读取db的操作了。
    
    //因此增加锁
    $mutex_key = $key."-mutex"; //设置mutex key,用于支持本key的一个锁
    if($cache->add($mutex_key, 1) == true ) //对mutex_key 设置一个整数为1 的缓存,不计算马上存储。add方法就是第一次存储时返回true,如果已经存在返回false。这就相当于一个锁,避免了再次被执行
    {
$model = new model(); //实例化模型
          $value = $model->getlist($catid); //读取数据库获得catid的列表信息,数据库设置中应为catid建立索引
 $cache->set($key, $value);//刷新缓存
$cache->delete($mutex_key);//释放锁缓存
    }
    else//如果有并发访问过来,等待处理
    {
     sleep(2); //设置2秒的锁等待
                        getnewlist($catid);//尝试去读取结果
    }
}
         
        return $value;
}

方法二:

$cache = new cache(); //实例化一个memcache类

    function getnewlist($catid)
{
        global $cache;
        $expiretime = 360; //过期时间6分钟
        $key = 'newlist-catid='.$catid;
        $value = $cache->get($key);
        
        if($value == null) //缓存失效
        {
                //设置一个锁等待
                $mutex_key = $key.'-mutex';
                if($cache->add($mutex_key, 1) == true) //设置一个锁
                {
                        $model = new model(); //实例化模型
              $value = $model->getlist($catid); //读取数据库获得catid的列表信息,数据库设置中应为catid建立索引
    $cache->set($key, array('timeout' => time() + $expiretime, 'value' => $value), $expiretime*2);//刷新缓存,这步可以在cache类中封装

//这里有个问题,就是可能每个cache服务器会出现时间不一致,造成不是你预想的时间。对timeout赋值,如果只设置 $expiretime,如何获取时间节点问题。

    $cache->delete($mutex_key);//释放锁缓存
                }
                else
                {
                        sleep(2); //设置2秒的锁等待
                        getnewlist($catid);//尝试去读取结果
                }

        }
        else//如果还没有过期
{
//如果timeout已经过期,因为timeout设置的时间短,此时$key还没有到期,实际上是个伪过期时间点,timeout作为一个真正的到期时间点
if($value['timeout'] < time())
{
//设置锁
$mutex_key = $key.'-mutex';
if($cache->add($mutex_key, 1) == true)//首先捕获到并设置个锁
{
$value['timeout'] = time() +  $expiretime ; //马上延长过期时间
$cache->set($key, $value, $expiretime*2); //延长时间并保存,防止在高并发状态下,数据库读取时间长,而缓存已失效。


$model = new model(); //实例化模型
 $value = $model->getlist($catid); //读取数据库获得catid的列表信息,数据库设置中应为catid建立索引
 $cache->set($key, array('timeout' => time() + $expiretime, 'value' => $value), $expiretime*2);//刷新缓存,这步可以在cache类中封装


$cache->delete($mutex_key);//释放锁缓存

}
}
return $value['value'];
}
}

相比于方法一, 优点:避免cache失效时刻,大量请求无法执行add(key_mutex)而进入sleep锁定等待 缺点:代码复杂性增加,前台数据要求不那么严格时可以使用这里输入代码

© 著作权归作者所有

共有 人打赏支持
昨日今日明日
粉丝 3
博文 17
码字总数 7394
作品 0
程序员
加载中

评论(1)

kslr
kslr
$value = $$model->getlist($catid); 错误
缓存更新的套路

看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作,另一个是查询操作...

OSC一霸 ⋅ 2016/09/01 ⋅ 0

为什么要用NoSQL(一)

NoSQL被我们用得最多的当数key-value存储,当然还有其他的文档型的、列存储、图型数据库、xml数据库等。在NoSQL概念提出之前,这些数据库就被用于各种系统当中,但是却很少用于web互联网应用...

疯狂的兔子 ⋅ 2014/04/07 ⋅ 0

NoSQL开篇——为什么要使用NoSQL

【编者按】NoSQL在2010年风生水起,大大小小的Web站点在追求高性能高可靠性方面,不由自主都选择了NoSQL技术作为优先考虑的方面。今年伊始,InfoQ中文站有幸邀请到凤凰网的孙立先生,为大家分...

Mr&Cheng ⋅ 2013/01/20 ⋅ 0

架构知识整理

架构概念 一套系统的软件架构就是这个系统所需的结构体的集合,包括:软件元素,软件元素之间的关系,以及二者的属性。 从视角不同一般分为: 逻辑架构 关注于各个组件之间的关系,如:用户界...

古城痴人 ⋅ 2015/08/19 ⋅ 0

大型分布式网站架构:缓存在分布式系统中的应用

缓存是分布式系统中的重要组件,主要解决高并发,大数据场景下,热点数据访问的性能问题。提供高性能的数据快速访问。 一、缓存概述 缓存是分布式系统中的重要组件,主要解决高并发,大数据场...

烂猪皮 ⋅ 04/26 ⋅ 0

Infinispan分布式缓存分析

1. Infinispan是什么? 下述截自官方描述: Infinispan是基于Apache 2.0协议的分布式键值存储系统,可以以普通java lib或者独立服务的方式提供服务,支持各种协议(Hot Rod, REST, Memcached...

随安居士 ⋅ 2017/09/06 ⋅ 0

分布式数据库与缓存双写一致性方案解疑

作者介绍 孤独烟,中国平安研发工程师,目前负责规则云平台架构设计以及需求研发工作。毕业后一直从事Java开发工作,在Web开发、架构设计上有多年的实战经验。在MySQL性能优化、JVM调优、分布...

孤独烟 ⋅ 06/01 ⋅ 0

淘宝大秒系统设计详解

大家还记得2013年的小米秒杀吗?三款小米手机各11万台开卖,走的都是大秒系统,3分钟后成为双十一第一家也是最快破亿的旗舰店。经过日志统计,前端系统双11峰值有效请求约60w以上的QPS ,而后...

陶邦仁 ⋅ 2016/03/14 ⋅ 1

分布式之数据库和缓存双写一致性方案解析

原文出处:孤独烟 引言 为什么写这篇文章? 首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用。在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作。 但是在更新...

孤独烟 ⋅ 05/17 ⋅ 0

构建高并发高可用的系统平台架构实践

一、设计理念 1.空间换时间 1.1多级缓存,静态化 客户端页面缓存(http header中包含Expires/Cache of Control,last modified(304,server不返回body,客户端可以继续用cache,减少流量),E...

郭恩洲_OSC博客 ⋅ 2016/05/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

用SQL命令查看Mysql数据库大小

要想知道每个数据库的大小的话,步骤如下: 1、进入information_schema 数据库(存放了其他的数据库的信息) use information_schema; 2、查询所有数据的大小: select concat(round(sum(da...

源哥L ⋅ 18分钟前 ⋅ 0

两个小实验简单介绍@Scope("prototype")

实验一 首先有如下代码(其中@RestController的作用相当于@Controller+@Responsebody,可忽略) @RestController//@Scope("prototype")public class TestController { @RequestMap...

kalnkaya ⋅ 23分钟前 ⋅ 0

php-fpm的pool&php-fpm慢执行日志&open_basedir&php-fpm进程管理

12.21 php-fpm的pool pool是PHP-fpm的资源池,如果多个站点共用一个pool,则可能造成资源池中的资源耗尽,最终访问网站时出现502。 为了解决上述问题,我们可以配置多个pool,不同的站点使用...

影夜Linux ⋅ 33分钟前 ⋅ 0

微服务 WildFly Swarm 管理

Expose Application Metrics and Information 要公开关于我们的微服务的有用信息,我们需要做的就是将监视器模块添加到我们的pom.xml中: 这将使在管理和监视功能得到实现。从监控角度来看,...

woshixin ⋅ 33分钟前 ⋅ 0

java连接 mongo伪集群部署遇到的坑

部署mongo伪集群 #创建mongo数据存放文件地址mkdir -p /usr/local/config1/datamkdir -p /usr/local/config2/data mkdir -p /usr/local/config3/data mkdir -p /usr/local/config1/l......

努力爬坑人 ⋅ 34分钟前 ⋅ 0

React Native & Weex 区别

JS引擎 Weex使用V8, React native使用JSCore JS开发框架 ( Js Framework ) Weex基于vue.js(2W+ star)。小巧轻量的前端开发框架,组件化,数据绑定,2.0引入virtual dom。 ReactNative使用...

东东笔记 ⋅ 42分钟前 ⋅ 1

UIkit 分页组件动态加载简单实现

1. 问题描述 使用过UIkit分页组件的都清楚,UIkit的分页不能动态刷新数据,也就是不能在点击下一页的时候,动态从后台加载数据,并且刷新页数以及该页数上的数据,下面是一个简单实现,没有做...

影狼 ⋅ 43分钟前 ⋅ 0

Mobx入门之三:Provider && inject

上一节中<App/>组件传递状态temperatures给children -- <TemperatureInput />,如果组建是一个tree, 那么属性的传递则会非常繁琐。redux使用Provider给子组件提供store, connect将子组件和s...

pengqinmm ⋅ 45分钟前 ⋅ 0

魔兽世界 7.0版本 S23/S24/S25全职业普通+精锐套

  死亡骑士   (联盟)   (部落)   (精锐)   恶魔猎手   (联盟)   (部落)   (精锐)   德鲁伊   (联盟)   (部落)   (精锐)   猎人   (联盟) ...

wangchen1999 ⋅ 52分钟前 ⋅ 0

maven顶级pom和子pom的版本号批量修改

当一个版本发布,新起一个版本时,我们只需要手动修改一下项目中pom.xml的版本号就可以了。但是如果这个maven项目有很多的子模块项目,那么一个个手动的去改就显得费时费力又繁琐了。还好,m...

ArlenXu ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部