转: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. 【转】MySQL常见的运算符及使用

    转自:http://www.linuxidc.com/Linux/2016-03/129672.htm MySQL中有4类运算符,它们是: 算术运算符 比较运算符 逻辑运算符 位操作运算符 算术操作符 ...

  2. [译]curl_multi_perform

    http://curl.haxx.se/libcurl/c/curl_multi_perform.html curl_multi_perform.3 -- man page NAMEcurl_mult ...

  3. SQL数据库——静态成员

    静态: 1.普通成员普通成员都是属于对象的用对象调用 2.静态成员静态成员是属于类的用类名调用 stactic 静态关键字 静态方法里面不能包含普通成员普通方法里面可以包含静态成员 静态: 1.普通成 ...

  4. D1-mini esp8266的资料备份

    需要更新esp8266库 http://arduino.esp8266.com/stable/package_esp8266com_index.json 下载好即可.

  5. struts2之通配符映射

    系统有n多个请求时候,不可能以一个action对应一个映射.可以用通配符映射将成百上千请求简化成一个通用映射. 通配符映射规则:1.若找到多个匹配,没有通配符的将胜出. 2.若指定的动作不存在,str ...

  6. 10.4 缓冲流 BufferedReader & BufferedWriter & 缓冲流特殊功能readLine

    缓冲流和正常流的使用大致相同,缓冲流效率更高. package day10_io_fileWrite_Read.buffer_stream; import java.io.*; /* * Buffer ...

  7. Redis系列(四)--持久化

    持久化就是将数据的更新异步的保存到磁盘中 持久化方式: 1.快照:某个时间点数据的备份 MySQL dump.Redis RDB 2.写日志:MySQL BinLog.HBASE Hlog.Redis ...

  8. 19MVC设计模式

    MVC设计模式 MVC英文即Model-View-Controller, 即把一个应用的输入.处理.输出流程按照Model.View.Controller的方式进行分离,这样一个应用被分成三个层——模 ...

  9. Linux 下 Bash 脚本对拍

    背会... #!/bin/bash i= while true ;do ./maker > data.in ./a <data.in> data.out ./b <data.i ...

  10. 用python写了一个猜年龄小游戏

    写一个猜年龄游戏: 需要实现用户登录的功能 初始用户登录信息为 {'hades': '13579','nick': '123','ruixing': 'a1','fanping': 'b2'} 登录时 ...