在工作中,经常会遇到高并发的时候,众所周知我们可以用Redis来做缓存,缓解数据库压力。这里的高并发指的是多个请求同时请求数据库,导致数据库压力过大,造成崩溃。

缓存原则

使用Reids做缓存要遵从的原则有:

  1. 热点数据缓存,即对于访问频繁的数据可以加上缓存,一般数据遵从二八原则,即80%的流量在20%的热点数据之上
  2. 静态数据缓存,对于部分数据长时间不会变动的可以做缓存,比如系统设置、奖品设置等

如何做缓存

一般而言,缓存分为服务器端缓存,和客户端缓存。

服务器端缓存即服务端将数据存入Redis,可以在访问DB之后,将数据缓存,或者在回包时将回包内容以请求参数为Key缓存。

本文主要讨论服务端缓存,客户端缓存需要具体情况具体分析故不再讨论范围内。

缓存的几种模式

旁路由模式

读操作

当请求到达服务端时,会先从Redis检索是否存在数据,如果存在则直接返回,否则将

写操作

当请求到达服务端时,会先更新数据库数据,然后删除Redis缓存内容

image-20231023160907544

为什么写操作要删除缓存而不是更新缓存

因为为了保证数据的一致性,若更新缓存可能会出现以下情况:

A请求更新数据库 -> B请求更新数据库 -> B请求更新缓存 -> A请求更新缓存

这样会导致数据库与缓存中的数据不一致的问题

缓存异常场景

缓存穿透

缓存穿透是某种特定的攻击,当没有命中缓存就会查询数据库,但是数据库中并没有该数据,会导致多次请求该数据都会进行查库,这使得我们的缓存设了个寂寞,没有达到想要的效果。

解决方案

  1. 增加接口校验,过滤不合法的数据,如id=-1,这样直接在接口层就能拦截数据
  2. 当数据库查询不到数据时,在缓存中设置一个value-None的键值对,并设置过期时间,如30秒(设置太长会导致正常情况也没法使用)。这样多次查询就不会直接打到数据库。
  3. 使用布隆过滤器

缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

解决方案

1.热点数据支持续期,持续访问的数据可以不断续期,避免因为过期失效而被击穿

2.发现缓存失效,重建缓存加互斥锁,当线程查询缓存发现缓存不存在就会尝试加锁,线程争抢锁,拿到锁的线程就会进行查询数据库,然后重建缓存,争抢锁失败的线程,你可以加一个睡眠然后循环重试

缓存雪崩

缓存雪崩顾名思义,是指大量的应用请求因为异常无法在Redis缓存中进行处理,像雪崩一样,直接打到数据库。这里异常的原因,也可以说雪崩的原因,主要是:

缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至宕机

解决方案

  1. 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  2. 重建缓存加互斥锁,当线程拿到缓存发现缓存不存在就会尝试加锁,线程争抢锁,拿到锁的线程就会进行查询数据库,然后重建缓存,争抢锁失败的线程,你可以加一个睡眠然后循环重试