缓存设计可谓老生常谈了,早些时候都是采用memcache,现在大家更多倾向使用redis,除了知晓常用的数据存储类型,结合业务场景有针对性选择,好像其他也没有什么大的难点。

工程中引入Redis Client二方包,初始化一个 Bean 实例RedisTemplate ,一切搞定,so easy。

如果是几十、几百并发的业务场景,缓存设计可能并不需要考虑那么多,但如果是亿级的系统呢?

首先,了解缓存知识图谱

早期的缓存用于加速 CPU 数据交换的 RAM。随着互联网的快速发展,缓存的应用更加宽泛,用于数据高速交换的存储介质都称之为缓存。

使用缓存时,我们要关注哪些指标?缓存有哪些应用模式?以及缓存设计时有哪些 Tip 技巧?一图胜千言,如下:

七大经典问题

缓存在使用过程不可避免会遇到一些问题,对于高频的问题我们大概归为了 7 类。具体内容下面我们一一道来。

1、缓存集中失效

当业务系统查询数据时,首先会查询缓存,如果缓存中数据不存在,然后查询 DB 再将数据预热到Cache中,并返回。缓存的性能比 DB 高 50~100 倍以上。

很多业务场景,如:秒杀商品、微博热搜排行、或者一些活动数据,都是通过跑任务方式,将 DB 数据批量、集中预热到缓存中,缓存数据有着近乎相同的过期时间

当这批数据过期时,会一起过期,此时,对这批数据的所有请求,都会出现缓存失效,从而将压力转嫁到 DB,DB 的请求量激增,压力变大,响应开始变慢。

那么有没有解呢?

当然有了。

我们可以从缓存的过期时间入口,将原来的固定过期时间,调整为过期时间=基础时间+随机时间,让缓存慢慢过期,避免瞬间全部过期,对 DB 产生过大压力。

2、缓存穿透

不是所有的请求都能查到数据,不论是从缓存中还是 DB 中。

假如黑客攻击了一个论坛,用了一堆肉鸡访问一个不存在的帖子id。按照常规思路,每次都会先查缓存,缓存中没有,接着又查 DB,同样也没有,此时不会预热到 Cache 中,导致每次查询,都会cache miss

由于 DB 的吞吐性能较差,会严重影响系统的性能,甚至影响正常用户的访问。

解决方案:

  • 方案一:查询 DB 时,如果数据不存在,预热一个特殊空值到缓存中。这样,后续查询都会命中缓存,但是要对特殊值,解析处理。
  • 方案二:构造一个BloomFilter过滤器,初始化全量数据,当接到请求时,在BloomFilter中判断这个 key 是否存在,如果不存在,直接返回即可,无需再查询缓存和 DB

3、缓存雪崩

缓存雪崩是指部分缓存节点不可用,进而导致整个缓存体系甚至服务系统不可用的情况。

分布式缓存设计一般选择一致性 Hash,当有部分节点异常时,采用 rehash 策略,即把异常节点请求平均分散到其他缓存节点。但是,当较大的流量洪峰到来时,如果大流量 key 比较集中,正好在某 1~2 个缓存节点,很容易将这些缓存节点的内存、网卡过载,缓存节点异常 Crash,然后这些异常节点下线,这些大流量 key 请求又被 rehash 到其他缓存节点,进而导致其他缓存节点也被过载 Crash,缓存异常持续扩散,最终导致整个缓存体系异常,无法对外提供服务。

解决方案:

  • 方案一:增加实时监控,及时预警。通过机器替换、各种故障自动转移策略,快速恢复缓存对外的服务能力。
  • 方案二:缓存增加多个副本,当缓存异常时,再读取其他缓存副本。为了保证副本的可用性,尽量将多个缓存副本部署在不同机架上,降低风险。

4、缓存热点

对于突发事件,大量用户同时去访问热点信息,这个突发热点信息所在的缓存节点就很容易出现过载和卡顿现象,甚至 Crash,我们称之为缓存热点。

这个在新浪微博经常遇到,某大 V 明星出轨、结婚、离婚,瞬间引发数百千万的吃瓜群众围观,访问同一个 key,流量集中打在一个缓存节点机器,很容易打爆网卡、带宽、CPU 的上限,最终导致缓存不可用。

解决方案:

  • 首先找到这个热 key来,比如通过Spark实时流分析,及时发现新的热点 key。
  • 将集中化流量打散,避免一个缓存节点过载。由于只有一个 key,我们可以在 key 的后面拼上有序编号,比如key#01key#02。。。key#10多个副本,这些加工后的 key 位于多个缓存节点上。
  • 每次请求时,客户端随机访问一个即可。

可以设计一个缓存服务治理管理后台,实时监控缓存的 SLA,并打通分布式配置中心,对于一些hot key可以快速、动态扩容。

5、缓存大 Key

当访问缓存时,如果 key 对应的 value 过大,读写、加载很容易超时,容易引发网络拥堵。另外缓存的字段较多时,每个字段的变更都会引发缓存数据的变更,频繁的读写,导致慢查询。如果大 key 过期被缓存淘汰失效,预热数据要花费较多的时间,也会导致慢查询。

所以我们在设计缓存的时候,要注意缓存的粒度,既不能过大,如果过大很容易导致网络拥堵;也不能过小,如果太小,查询频率会很高,每次请求都要查询多次。

解决方案:

  • 方案一:设置一个阈值,当 value 的长度超过阈值时,对内容启动压缩,降低 kv 的大小。
  • 方案二:评估大 key所占的比例,由于很多框架采用池化技术,如:Memcache,可以预先分配大对象空间。真正业务请求时,直接拿来即用。
  • 方案三:颗粒划分,将大 key 拆分为多个小 key,独立维护,成本会降低不少。
  • 方案四:大 key 要设置合理的过期时间,尽量不淘汰那些大 key。

6、缓存数据一致性

缓存是用来加速的,一般不会持久化储存。所以,一份数据通常会存在DB缓存中,由此会带来一个问题,如何保证这两者的数据一致性。另外,缓存热点问题会引入多个副本备份,也可能会发生不一致现象。

解决方案:

  • 方案一:当缓存更新失败后,进行重试,如果重试失败,将失败的 key 写入 MQ 消息队列,通过异步任务补偿缓存,保证数据的一致性。
  • 方案二:设置一个较短的过期时间,通过自修复的方式,在缓存过期后,缓存重新加载最新的数据。

7、数据并发竞争预热

互联网系统典型的特点就是流量大,一旦缓存中的数据过期、或因某些原因被删除等,导致缓存中的数据为空,大量的并发线程请求(查询同一个 key)就会一起并发查询数据库,数据库的压力陡然增加。

如果请求量非常大,全部压在数据库,可能把数据库压垮,进而导致整个系统的服务不可用。

解决方案:

  • 方案一:引入一把全局锁,当缓存未命中时,先尝试获取全局锁,如果拿到锁,才有资格去查询DB,并将数据预热到缓存中。虽然,client 端发起的请求非常多,但是由于拿不到锁,只能处于等待状态,当缓存中的数据预热成功后,再从缓存中获取。

为了便于理解,简单画了个流程图。这里面特别注意一个点,由于有一个并发时间差,所以会有一个二次 check 缓存是否有值的校验,防止缓存预热重复覆盖。

  • 方案二:缓存数据创建多个备份,当一个过期失效后,可以访问其他备份。

写在最后

缓存设计时,有很多技巧,优化手段也是千变万化,但是我们要抓住核心要素。那就是,让访问尽量命中缓存,同时保持数据的一致性。

高并发Redis缓存如何设计相关推荐

  1. 猿创征文 | 微服务 Spring Boot 整合Redis 实战开发解决高并发数据缓存

    文章目录 一.什么是 缓存? ⛅为什么用缓存? ⚡如何使用缓存 二.实现一个商家缓存 ⌛环境搭建 ♨️核心源码 ✅测试接口 三.采用 微服务 Spring Boot 注解开启缓存 ✂️@CacheEn ...

  2. 高并发大型互联网站架构设计

    每年进入3-4月所有的高等院校开始了一年一度的毕业生答辩准备阶段,现如今毕业论文或者毕业设计也更加的贴近了互联发展的趋势,很多学校开始做最热话题云计算openstack架构的实现以及云计算环境搭建,先 ...

  3. 互联网大厂高并发抢购系统架构设计

    背景 大家好,这篇文章给大家介绍一个非常经典的去大厂面试经常被问的一个问题,就是瞬时 高并发抢购问题,通常来说,大厂开发的系统经常会遇到一些类似电商秒杀抢购.景点门票高并发抢购.特殊商品(比如口罩)高 ...

  4. 高并发redis实现秒杀商品

    高并发redis实现秒杀 ps:直接在redis读取插入操作 只是插入的时候要加锁 怎么加锁 http://newmiracle.cn/?p=488 public function miaoshate ...

  5. 史上最强大型分布式架构详解:高并发+数据库+缓存+分布式+微服务+秒杀

    分布式架构设计是成长为架构师的必备技能,涵盖的内容很广,今天一次打包分享,文末有:最全分布式架构设计资料获取方式~ 负载均衡 负载均衡的原理和分类 负载均衡架构和应用场景 分布式缓存 常见分布式缓存比 ...

  6. Redis系列教程(一):Redis缓存的设计、性能、应用与数据集群同步

    Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库.Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行 ...

  7. 架构系列---一套高并发IM通信系统完整设计和实现

    先行参考:架构秘境系列3---微信.陌陌.WNS著名IM软件设计架构详解 1. 服务器端设计 1.1 总体架构 总体架构包括5个层级,具体内容如下图. 1.1.1 用户端 移动端重点是移动端,支持IO ...

  8. 高并发秒杀系统如何设计?

    前言 秒杀大家都不陌生.自2011年首次出现以来,无论是双十一购物还是 12306 抢票,秒杀场景已随处可见.简单来说,秒杀就是在同一时刻大量请求争抢购买同一商品并完成交易的过程. 从架构视角来看,秒 ...

  9. 【Netty源码解析】Netty核心源码和高并发、高性能架构设计精髓

    Netty线程模型图 Netty线程模型源码剖析图 图链接:https://www.processon.com/view/link/5dee0943e4b079080a26c2ac Netty高并发高 ...

最新文章

  1. 北大韦神透露现状:自己课讲得不太好,中期学生退课后就剩下5、6个人...
  2. 抢鲜!华硕240MIMOWL-566gM
  3. html 表格点击修改全部替换成文本_excel表格计算一个数据在总值中的占比
  4. python图片识别-python图像识别
  5. 请教怎么查询ORACLE的历史操作记录!
  6. HDU1213How Many Tables
  7. 《梦断代码》读后感2
  8. 【ZOJ 4070】Function and Function
  9. IDC:2016年上半年宏杉科技同比增长47.3% 中国TOP10数据存储厂商增速第一
  10. oppo9s刷机教程_OPPOR9SPlus官方固件刷机教程_线刷|救砖教程图解
  11. 如何在阿里云注册域名-阿里云域名注册与域名解析完整教程
  12. mysql XA 分布式事务、DTM TCC事务(多语言支持)
  13. Python中sep是函数吗?该怎么使用?
  14. WTL 自绘控件库 (CQsCheckBox)
  15. 寒假集训难题(四)QWQ和神奇的传送器nefu1608
  16. Redis基本应用及Java代码实现
  17. 线性代数学习笔记4-1:线性方程组的数学和几何意义、零空间/解空间/核
  18. !=EOF的含义和原理
  19. CMWAP 和 CMNET 的主要区别与适用范围
  20. python 文件锁 portalocker

热门文章

  1. “绿色高效 模块智能”金融业数据中心系列规范发布会将于12月7日召开
  2. 数字图像处理,图像锐化算法的C++实现
  3. java-什么是实例初始化块?
  4. 修改同一张表的同一个字段的两个不同的值。
  5. GROUP BY,WHERE,HAVING之间的差别和使用方法
  6. CSS three column layout
  7. 车道线识别/Opencv/传统方法
  8. Jquery根据JSON生成Table
  9. asp.net 递归删除文件夹及其子文件夹和所有文件[转]
  10. 程维谈智慧交通:我们赶上好时代 走出了自己路