Redis的应用(一)

185 阅读6分钟

1.开篇

学习一门技术,目的肯定是为了在业务中使用它。那么,Redis到底能干些什么?最常用的当属拿Redis做缓存。今天就来学习Redis的作用之一--做缓存。学完此篇,你将掌握:

  • Redis做缓存的工作原理;
  • 缓存的替换策略;
  • 缓存异常的原因以及应对方法;
  • 缓存与数据库一致性保证的方法;

1.1 Redis缓存的工作原理

  • 缓存的本质:
    • 使用更快的介质/系统加速慢速介质/系统的访问
    • 快速介质/系统的容量通常更小
  • 缓存类型
    • 只读缓存,redis做只读缓存多一些;
    • 读写缓存
  • 缓存的应用场景:加速数据库的访问
  • 缓存的请求处理流程:
    • 首先查询缓存,如果缓存中有请求的数据,则缓存命中,从缓存中读取数据;相反,如果缓存中没有请求的数据,则缓存缺失,从后端数据库当中读取数据,此外还要做一个操作--把这个缺失的数据写入缓存。
  • 缓存满了怎么办?缓存容量毕竟是有限的。如果缓存存满数据后,再有新数据要写入缓存,此时会有相关的操作:
    • 哪些数据将从缓存中替换出,即一个进,对应一个出。这叫替换策略;
    • 替换出的数据如何处理?这涉及到数据如何写回。这叫写回策略,只在读写缓存中存在数据写回这个操作。有两种:
      • Write-through策略:写缓存的同时写数据库,优点是可靠性高,有可能快
      • Write-back策略:先写缓存后写数据库,优先是性能快

1.2 Redis缓存的替换策略,也叫淘汰策略

  • 按照候选数据集区分:
    • volatile-xxx;具体来说,就是给某些数据设置过期时间,淘汰数据时,从已设置过期时间的key中淘汰数据,没设置的数据将永久驻留。热点数据经常使用这个策略;
    • allkeys-xxx。缓存的全部数据都可淘汰。
  • 按策略区分:ttl,random,LRU(Least Recently Used),LFU(Least Frequently Used)

1.3 Redis缓存异常

实战问题1:缓存中大量热数据同时失效会有什么问题么?关键词:大量数据,同时;导致:缓存雪崩

  • 场景:Redis作为MySQL的前端缓存,针对同一时刻加载到Redis中的数据,采用了volatile-ttl淘汰策略,并设置相同的过期时间,到期后同时失效。
  • 现象:MySQL的QPS一下飙到6k OPS(正常是3k OPS),数据库系统资源占用急剧上升,系统报警。
  • 分析:
    • Redis中大量数据同时失效,导致发生大量缓存缺失。数据请求转发到数据库,导致DB压力剧增。导致缓存雪崩现象;
    • 缺失的数据再更新到Redis,导致Redis压力增加。
  • 应对方法:
    • 给数据设置不同TTL值;
    • Redis实例异常,也会导致雪崩发生,通过主从集群增加缓存可靠性。

实战问题2:缓存中某一热点数据失效会有什么问题么?导致:缓存击穿

  • 场景:Redis作为MySQL的前端缓存,某一热点数据过期失效。
  • 现象:MySQL数据库QPS增加,数据库系统资源占用增加。
  • 分析:不同于雪崩,仅少量热点数据失效;缓存击穿现象。
  • 应对方法:热点数据不设置过期时间。

实战问题3:数据库误删数据会对缓存有影响么?导致:缓存穿透

  • 场景:Redis作为MySQL的前端缓存,采用volatile-ttl替换策略。业务部门误删了某些数据。
  • 现象:过段时间后,Redis的QPS突然增加,MySQL数据库的QPS也相应增加。
  • 分析:
    • 被误删除的数据再Redis的过期时间到达后,数据失效,被淘汰出缓存了;
    • 有请求需要读取这部分数据,在Redis和MySQL都找不到这些数据;
    • 如果并发请求很多,那么将导致Redis和MySQL的压力都会增加;
    • 这叫缓存穿透现象。
  • 应对方法:
    • 缓存缺失后,DB中查询不到的数据,在Redis中设置为NULL;
    • 使用布隆过滤器(Bloom Filter),让Redis快速返回;
    • Redis和MySQL压力超过报警阈值,触发前端限流。

思考题:前端限流对缓存雪崩,击穿,穿透都有用么?如果是恶意访问不存在的key,前端限流是个好方案吗?

  • 参考回答:
    • 前端下流作为一个成熟的系统级方案,一般建议进行部署;
    • 雪崩,击穿,穿透都会对数据库造成压力,前端限流会有帮助;
    • 前端限流是一个有损方案,对于恶意访问,建议在网关处进行请求校验。

1.4 缓存数据一致性如何保证?

  • 场景:Redis作为MySQL的前端缓存,业务应用需要对某一数据进行更新。

  • 问题:现有两种设计方案,该如何选择?我们上面说过,Redis做缓存更多时候做的是只读的,这里就不考虑更新缓存了,只考虑删除缓存。

    • 方案一:先删缓存,再更新数据库;
    • 方案二:先更新数据库,再删除缓存。
  • 方案一分析:

    • 先删除缓存,数据库尚未更新->此时有并发请求访问缓存—>缓存已删除,导致缓存缺失->从数据库读取旧值
    • 先删除缓存,更新数据库失败->重试更新数据库还是失败->有并发请求访问缓存->缓存缺失->从数据库读取旧值
    • 如果重试更新数据库成功了,是否就没问题了呢?
      • 分析:先删除缓存,更新数据库失败->重试更新数据库成功->有并发请求访问缓存->缓存缺失->数据库已经更新,从数据库读取新值
  • 方案二分析:

    • 先更新数据库,删除缓存失败->此时有并发请求访问缓存->缓存还没成功删除,缓存命中->从缓存读取旧值
    • 如果删除缓存这个操作也是可以重试的,那么在删除了缓存后,通过缓存缺失,读取到新值,这时两个方案没什么差别。
  • 如何选择方案,还是具体情况具体分析。

总结:

  • Redis缓存以只读缓存应用为主,常用的缓存淘汰策略包括基于过期时间、LRU、LFU;
  • Redis缓存异常包括雪崩,击穿,穿透。雪崩和击穿都是指有数据在缓存中缺失,压力传导至DB。而穿透则是指缓存和DB都要承受大压力;
  • Redis缓存和数据库一致性保证时,先删缓存再更新数据库,或者先更新数据库再删除缓存是两种不同的方案。
  • 今天的学习就先到这里,《蒋德钧的Redis集训班》Day three