转:http://api.crap.cn/index.do#/web/article/detail/web/ARTICLE/7754a002-6400-442d-8dc8-e76e72d948ac

目前高并发项目会在数据库之上引入数据缓存:

1. 缓存雪崩,什么是雪崩效应?

缓存雪崩可能是因为数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。

我的理解的雪崩效应是在分层服务调用的系统中,当一个较为基础的服务a因某种原因不可用,导致其调用服务b,c也不可用,而b的不可用又导致其调用服务e,f的不可用,不可用的服务就好像滚雪球一样越滚越大,最后导致系统出现严重故障。我们称之为雪崩效应。如图。

以此为例,当数据库主备都不可用时,将导致其调用服务的关联失效(红色组件)

2.基于redis数据过时失效的策略,在缓存过期的短时间内存在数据库短暂压力问题,如下:

为解决上述问题(主要是后者),可采用一下解决方案如下:

这里我们以两个键值对的缓存代替之前的一个,将缓存时间(key-time),和缓存数据(key-data)分离,这样

1.当缓存过期时,第一个线程发现key-time没有,则先更新key-time,

2.然后去查询数据库(或任何比较耗时的数据查询方式),并更新key-data的值,

3.当后续线程来获取数据时,虽然第一个还没有从数据库查完并更新缓存,但发现key-time存在,会获取旧的数据。

虽然按这种方式获取的数据中c类型的数据为旧数据,但可以做到:

在缓存过期时不至于在短时间内对数据库造成较高压力(解决第2个问题)。

在数据库不可用,同时缓存过期的时候,其调用服务皆不可用,造成连锁反应,而已该解决方式,则可以返回过期数据,为修复数据库赢得宝贵时间(缓解雪崩效应)

示例代码:

Redis 获取数据
public static String get(String key) {
      Jedis jedis = null;
      int redisIndex = RedisUtils.getRedisIndex(key);
      try {
         jedis = getRedis(redisIndex);
         jedis.select(1);
         // 缓存过期  && 获取锁成功
   // setnx:原子操作,如果不存在则设置值,并返回1。如果缓存存在,则返回0,设置缓存失败
         if(jedis.setnx("lock_"+key, System.currentTimeMillis()+"")==1){
            /**
             *  将锁的有效时间设为60s,在60s内如果查询数据库成功,则更新该锁的失效时间=缓存时间。
             *  如果60s内出现异常,则60s后第一个请求又会去访问数据库...
             *  返回null表示没有查询到数据库,外层代码会通过数据库获取数据
             */
            jedis.expire("lock_"+key, 60);
            return null;
         }
         // (缓存未过期) || (缓存过期,但是获取锁失败) then 返回旧的数据
         else{
            jedis.select(0);
            return jedis.get(key);
         }
      } catch (JedisException e) {
         if (jedis != null) {
            returnBrokenResource(jedis, redisIndex);
            // 避免在finally中再次关闭reids
            jedis = null;
         }
         throw e;
      } finally {
         if (jedis != null) {
            returnResource(jedis, redisIndex);
         }
      }
   }
 
Redis 缓存数据
public static boolean set(String key, String value, int seconds) {
      Jedis jedis = null;
      int redisIndex = RedisUtils.getRedisIndex(key);
      try {
         jedis = getRedis(redisIndex);
         if (seconds > 0){
            // 添加缓存,缓存有效时间=真实时间+1天
            jedis.setex(key, seconds + 60 * 60 *24 , value);
            jedis.select(1);
            // 添加缓存锁,有效时间 =真实时间
            jedis.setex("lock_" + key, seconds, System.currentTimeMillis()+"");
         }else{
            jedis.set(key, value);
            jedis.select(1);
            jedis.set("lock_" + key, System.currentTimeMillis()+"");
         }
         return true;
      } catch (JedisException e) {
         if (jedis != null) {
            returnBrokenResource(jedis, redisIndex);
            // 避免在finally中再次关闭reids
            jedis = null;
         }
         throw e;
      } finally {
         if (jedis != null) {
            returnResource(jedis, redisIndex);
         }
      }
   }

转:Redis 缓存策略的更多相关文章

  1. redis 缓存策略

    redis 缓存策略配置项:maxmemory <bytes>maxmemory-policy noeviction 触发时机:每次执行命令(processCommand)的时候会检测 w ...

  2. Redis缓存策略设计及常见问题

    Redis缓存设计及常见问题 缓存能够有效地加速应用的读写速度,同时也可以降低后端负载,对日常应用的开发至关重要.下面会介绍缓存使用技巧和设计方案,包含如下内容:缓存的收益和成本分析.缓存更新策略的选 ...

  3. mysql+redis缓存策略常见的错误

    什么时候应该更新缓存 应该是从数据库读取数据后,再更新缓存,从缓存读取到数据,就不需要再重新写缓存了,一个常见的错误是,每次访问接口都更新缓存,这样的话,如果接口一直有流量,那么db中的数据,就一直没 ...

  4. Redis缓存策略

    常用策略有“求留余数法”和“一致性HASH算法” redis存储的是key,value键值对 一.求留余数法 使用HASH表数据长度对HASHCODE求余数,余数作为索引,使用该余数,直接设置或访问缓 ...

  5. 在Window系统中使用Redis缓存策略

    Redis是一个用的比较广泛的Key/Value的内存数据库,新浪微博.Github.StackOverflow 等大型应用中都用其作为缓存,Redis的官网为http://redis.io/. 最近 ...

  6. Redis的缓存策略和主键失效机制

    作为缓存系统都要定期清理无效数据,就需要一个主键失效和淘汰策略. >>EXPIRE主键失效机制 在Redis当中,有生存期的key被称为volatile,在创建缓存时,要为给定的key设置 ...

  7. 浅谈一下缓存策略以及memcached 、redis区别

    缓存策略三要素:缓存命中率   缓存更新策略  最大缓存容量.衡量一个缓存方案的好坏标准是:缓存命中率.缓存命中率越高,缓存方法设计的越好. 三者之间的关系为:当缓存到达最大的缓存容量时,会触发缓存更 ...

  8. redis 缓存用户账单策略

    最近项目要求分页展示用户账单列表,为提高响应使用redis做缓存,用到的缓存策略和大家分享一下. 需求描述:展示用户账单基本信息以时间倒序排序,筛选条件账单类型(所有,订单收入.提现.充值...). ...

  9. 缓存策略:redis缓存之springCache

    最近通过同学,突然知道服务器的缓存有很多猫腻,这里通过网上查询其他人的资料,进行记录: 缓存策略 比较简单的缓存策略: 1.失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放 ...

随机推荐

  1. c/c++导出lua绑定

    [转载]https://note.youdao.com/share/?id=0f4132271151c4b62f9afb712e8304d9&type=note#/ 1.在纯C环境下,把C函数 ...

  2. [转]ASP.NET MVC的帮助类HtmlHelper和UrlHelper

    本文转自:http://www.cnblogs.com/greatandforever/archive/2010/04/20/1715914.html?login=1 在ASP.NET MVC框架中没 ...

  3. SCRIPT70: 没有权限

    主要原因:iframe安全而引发的问题,浏览器中js是没有垮域访问的权限的.如果用到iframe首先确保不垮域,或者不用iframe以绕开这个问题. 另外在jquery的早期版本中如:jquery-1 ...

  4. 为什么我的对象被 IntelliJ IDEA 悄悄的修改了?

    背景     最近,在复习JUC的时候调试了一把ConcurrentLinkedQueue的offer方法,意外的发现Idea在debug模式下竟然会 "自动修改" 已经创建的Ja ...

  5. windows系统下的redis启动教程

    下载解压后配置redis.conf文件配置端口号和密码,打开poweshell命令,进入redis解压目录,使用.\redis-server.exe redis.conf 命令启动redis服务,再打 ...

  6. (转)版本管理工具介绍——SVN篇(二)

    http://blog.csdn.net/yerenyuan_pku/article/details/72620498 上一篇文章我介绍了一下SVN,以及SVN服务器的安装,相信大家都安装了,接下来我 ...

  7. 前端零基础快速入门JavaScript

    JavaScript代码可以直接嵌在网页的任何地方,不过通常我们都把JavaScript代码放到<head>中: <html><head> <script&g ...

  8. vue组件---动态组件之多标签页面

    首先看下效果图 代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> & ...

  9. 用Docker构建MySQL镜像

    构建MySQL镜像 本文目的不仅仅是创建一个MySQL的镜像,而是在其基础上再实现启动过程中自动导入数据及数据库用户的权限设置,并且在新创建出来的容器里自动启动MySQL服务接受外部连接,主要是通过D ...

  10. Manjaro安装配置美化字体模糊发虚解决记录

    Manjaro安装记录 前言: ​ 记录自己Manjaro18安装的一些坑,避免下次满互联网找解决方法.在此之前试过Manjaro.Ubuntu.Fedora.linux Mint系统的pac.yum ...