专栏首页老男孩成长之路缓存并发神技,如何通过双 key 来解决缓存并发问题?

缓存并发神技,如何通过双 key 来解决缓存并发问题?

我们在使用缓存的时候,不管Redis或者是Memcached,基本上都会遇到以下3个问题:缓存穿透、缓存并发、缓存集中失效。这篇文章主要针对【缓存并发】问题展开讨论,并给出具体的解决方案。

1.什么是缓存并发?

在高并发的访问下,当某个缓存处于过期失效的时间点时,极有可能出现多个进程同时查询该缓存(该缓存是业务场景中非常 "热点" 的数据,比如首页的缓存数据)。因为查询DB并重新缓存需要一定的时间,而瞬时并发非常高,如果此时缓存失效了,这些并发请求都会直接访问DB,从而导致DB服务器的CPU或者内存负载过高,服务能力下降甚至宕机,此问题即缓存并发问题。

缓存并发问题在微服务架构下凸显更加严重,比如某个基础服务A因为上述问题出现不可用,进而导致依赖A服务的B、C服务也不可用,而B服务的不可用又导致服务E、F不可用,不可用的服务就像滚雪球一样越滚越大,最终导致系统出现严重故障,此现象我们称之为雪崩效应。

注意缓存并发和缓存集中失效的区别在于:缓存并发指的是某一个热点key的失效,而缓存集中失效则是一批key同时失效,两者都可能导致雪崩问题。

2.如何解决?

针对该问题,存在以下三种解决方案:

  1. 加锁:在缓存失效后,通过加锁的方式只允许一个线程查询数据和写缓存,其他线程如果发现有锁就等待,等解锁后再返回数据。该方案会造成部分请求等待。
  2. 二级缓存:A1为原始缓存,A2为拷贝缓存。A1失效时,可以访问A2,其中A1的缓存失效时间设置为短期(比如5min),A2的缓存失效时间设置为长期(比如1天)。如果缓存value很大,此方案的缓存空间利用率低。关注公众号互联网架构师,回复关键字2T,获取最新架构视频
  3. 双key:思路和方案2类似,不同的是双key分别缓存过期时间(key-time)和缓存数据(key-data),其中(key-time)的缓存失效时间设置为短期(比如5min),(key-data)的缓存失效时间设置为长期(比如1天)。当第一个线程发现 key-time 过期不存在时,则先更新key-time,然后去查询数据库并更新key-data 的值;当其他线程来获取数据时,虽然第一个线程还没有从数据库查询完毕并更新缓存,但发现key-time存在,会直接读取缓存的旧数据返回。和二级缓存的方案对比,该方案的缓存空间利用率高。

3.双key方案的示例代码

1. 写缓存的示例代码
 1public static boolean set(String key, String value, int seconds) {
 2    Jedis jedis = null;
 3    try {
 4        jedis = jedisPool.getResource();
 5        if (seconds > 0){
 6            // 添加数据缓存,缓存有效时间 = 真实时间 + 1 天
 7            jedis.set(key, seconds + 60 * 60 * 24, value);
 8
 9            // 添加过期时间缓存,缓存有效时间 = 真实时间
10            jedis.set("lock_" + key, seconds, System.currentTimeMillis() + "");
11        } else {
12            jedis.set(key, value);
13            jedis.set("lock_" + key, System.currentTimeMillis() + "");
14         }
15
16         return true;
17    } catch (JedisException e) {
18         if (jedis != null) {
19             returnBrokenResource(jedis);
20             jedis = null;
21         }
22         throw e;
23    } finally {
24         if (jedis != null) {
25             returnResource(jedis);
26         }
27    }
28}
2. 读缓存的示例代码
 1public static String get(String key) {
 2    Jedis jedis = null;
 3    try {
 4        jedis = jedisPool.getResource();
 5
 6        // 缓存过期 && 获取锁成功,setnx:原子操作
 7        if (jedis.setnx("lock_" + key, System.currentTimeMillis() + "") == 1) {
 8            /**
 9             * 将锁的失效时间设为60s,在60s内若查询数据库成功,则更新锁的失效时间=缓存时间
10             * 如果60s内出现异常,则60s后第一个请求又会去访问数据库
11             * 返回null表示没有查询到数据库,外层代码会通过数据库获取数据并设置缓存
12             */
13            jedis.expire("lock_" + key, 60);
14            return null;
15        } else{
16            // 缓存未过期或者缓存过期但获取锁失败, 则返回旧数据
17            return jedis.get(key);
18        }
19    } catch (JedisException e) {
20        if (jedis != null) {
21            returnBrokenResource(jedis);
22            jedis = null;
23        } 
24        throw e;
25    } finally {
26        if (jedis != null) {
27            returnResource(jedis);
28        }
29    }
30}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 高并发架构技术|缓存失效、缓存穿透问题 PHP 代码解决

    缓存失效:   引起这个原因的主要因素是高并发下,我们一般设定一个缓存的过期时间时,可能有一些会设置5分钟啊,10分钟这些;并发很高时可能会出在某一个时间同时...

    猿哥
  • 什么是布隆过滤器?如何解决高并发缓存穿透问题?

    日常开发中,大家经常使用缓存,但是你知道大型的互联网公司面对高并发流量,要注意缓存穿透问题吗!!! 本文会介绍布隆过滤器,空间换时间,以较低的内存空间、高...

    用户7676729
  • 高并发下缓存失效问题及解决方案

    当查询一个不存在的数据,此时缓存是不命中的,就会去查询 db,这将导致每次查询这个不存在的数据都要去访问 db,缓存就没有意义了。如果不怀好意的人利用不存在的数...

    java乐园
  • 面试官:什么是布隆过滤器?如何解决高并发缓存穿透问题?

    日常开发中,大家经常使用缓存,但是你知道大型的互联网公司面对高并发流量,要注意缓存穿透问题吗!!! 本文会介绍布隆过滤器,空间换时间,以较低的内存空间、高...

    一个优秀的废人
  • 高并发场景下缓存+数据库双写不一致问题分析与解决方案设计

    Redis是企业级系统高并发、高可用架构中非常重要的一个环节。Redis主要解决了关系型数据库并发量低的问题,有助于缓解关系型数据库在高并发场景下的压力,提高系...

    编程大道
  • 高并发场景下的缓存+数据库双写不一致问题分析与解决方案设计

    库存可能会修改,每次修改都要去更新这个缓存数据; 每次库存的数据,在缓存中一旦过期,或者是被清理掉了,前端的nginx服务都会发送请求给库存服务,去获取相应的数...

    HUC思梦
  • 【高并发】面试官:讲讲什么是缓存穿透?击穿?雪崩?如何解决?

    作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了...

    冰河
  • 带上问题来学redis,看到不吃亏(什么是redis?缓存问题、数据一致性、redis配置文件汉化版)

    redis 是一个NOSQL类型数据库, 是一个高性能的key-value数据库, 是为了解决高并发、高可用、大数据存储等一系列的问题而产生的数据库解决方...

    看、未来
  • 面对缓存,出现这些问题你要如何思考!

    缓存可以说是无处不在,比如 PC 电脑中的内存、CPU 中的二级缓存、HTTP 协议中的缓存控制、CDN 加速技术都是使用了缓存的思想来解决性能问题。 Java...

    Java架构
  • Redis专题(1):构建知识图谱

    思考:很明显,小明同学在面试过程中关于Redis的表现和回答肯定是比较失败的。Redis是我们工作中每天都会使用到的东西,为什么一到面试却变成了丢分项呢?

    宜信技术学院
  • 神奇的闪电缓存,带系统飞

    缓存,在高并发的应用中,用的那是相当多。为什么?就因为I/O实在是慢!为了解决不同组件之间的速度差,大家都寄希望于加入一个中间层,期待产生一些魔幻的事。

    xjjdog
  • 如何发现 Redis 热点 Key ,解决方案有哪些?

    1.1 用户消费的数据远大于生产的数据(热卖商品、热点新闻、热点评论、明星直播)。

    Java技术栈
  • 58同城数据库架构设计思路(下)

    《58同城数据库架构设计思路》(下) WOT(World Of Tech)2015,互联网运维与开发者大会将在北京举行,会上58同城分享了《大数据量下,58同城...

    架构师之路
  • 缓存穿透、缓存并发、缓存雪崩、缓存抖动、热点缓存、缓存双写一致性等问题

    对于高并发的业务场景,常用的技术手段包括黑白名单、限流防刷、熔断降级、兜底、线程隔离、多级缓存(客户端、CDN、NGINX、内存缓存、分布式缓存)等等。这些手段...

    码农编程进阶笔记
  • 志玲姐姐宣布结婚的一刹那,对一个单身程序员的冲击究竟有多大。

    2019年6月6日 下午6:06分 全民女神林志玲宣布结婚,这是一条爆炸新闻,究竟有多炸??,一会儿我再给你分析,看到这条消息的这一刻,我的心里也一阵悲叹,为什...

    王炸
  • 缓存穿透、缓存并发、缓存失效之思路变迁

    来源:https://www.jianshu.com/p/d96906140199

    芋道源码
  • 缓存穿透、缓存并发、缓存失效之思路变迁

    我们在用缓存的时候,不管是Redis或者Memcached,基本上会通用遇到以下三个问题:

    小程故事多
  • 缓存穿透、缓存并发、缓存失效之思路变迁

    我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回。这个时候如果我们查询的某一个数据在...

    Java_老男孩
  • 58同城数据库架构设计思路

    (1)可用性设计 解决思路:复制+冗余 副作用:复制+冗余一定会引发一致性问题 保证“读”高可用的方法:复制从库,冗余数据,如下图 ? 带来的问题:主从不一致 ...

    用户1263954

扫码关注云+社区

领取腾讯云代金券