千家信息网

redis缓存常见的问题有哪些

发表于:2024-11-21 作者:千家信息网编辑
千家信息网最后更新 2024年11月21日,这篇文章主要讲解了"redis缓存常见的问题有哪些",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"redis缓存常见的问题有哪些"吧!1、什么是缓存?缓
千家信息网最后更新 2024年11月21日redis缓存常见的问题有哪些

这篇文章主要讲解了"redis缓存常见的问题有哪些",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"redis缓存常见的问题有哪些"吧!

1、什么是缓存?

缓存,就是数据交换的缓冲区,针对服务对象的不同(CPU、内存、磁盘等)都可以构建缓存。

目的是,把读写速度慢的介质中的数据保存在读写速度快的介质中,提升效率。

例如:

· CPU高速缓存

· 内存缓存

将磁盘中常用的数据保存在内存中。

日常业务中,我们使用比较多的数据库是Mysql,缓存是Redis。Redis的性能比Mysql要快得多,因此我们将Mysql中的热点数据,缓存到Redis中,提升读取性能,减少数据库压力。

读数据时,从redis中读取,redis中没有,再去mysql中读取。

写数据时,先写到redis中,再定时异步回写到redis中,或者同步回写。

场景:

1、论坛帖子的访问频率比较高,且需要实时地更新阅读量,可以使用Redis记录帖子的阅读量,提升并发度和性能

2、商品信息,更新的频率不高,但是读取的频率比较高,特别是热门商品,因此将热门商品信息存储在Redis中

2、常见的缓存算法

LRU(least recently used) 最近最少使用

LFU(least frequently used) 最不经常使用

FIFO 先进先出

3、常见的缓存工具和框架

这里介绍的是Java环境中的

本地缓存

Guava LocalCache、Ehcache、Caffeine

  • Ehcache 的功能更加丰富,Caffeine 的性能要比 Guava LocalCache 好。

分布式缓存

Redis、MemCache、Tair

  • Redis 最为主流和常用。

4、缓存常见问题

写入问题:

  • 缓存何时写入?如何避免多线程环境下重读写入?

  • 缓存如何失效?

  • 缓存和DB的一致性如何保证

经典三连问

  • 如何避免缓存穿透?

  • 如何避免缓存击穿?

  • 如何避免缓存雪崩?

5、如何避免雪崩

实际业务中,如果缓存系统出现了问题(宕机),程序中应该手动捕获这个异常,并且记录日志,然后从数据库查询数据返回给用户,这样将不会导致业务不可用。但随着而来的一个问题就是,缓存雪崩。

缓存雪崩,是指缓存由于有些原因无法提供服务,所有请求全部抵达DB,导致DB负荷大增,最终挂掉的情况。

如何解决:

方法(1)缓存高可用

通过搭建缓存的高可用,避免缓存挂掉导致无法提供服务的情况,从而降低出现缓存雪崩的情况的概率。

假设我们使用Redis作缓存,可以使用Redis Sentinel或Redis Cluster实现高可用。

方法(2)本地缓存

使用本地缓存,即使分布式缓存挂掉了,也可以将DB查询到的结果缓存到本地,避免后续的请求全部到达DB。

java环境中可以使用的本地缓存工具上文已经介绍。

方法(3)请求DB限流

限制DB的每秒请求树,避免DB挂掉,这样做至少有两个好处:

1、可能有一部分用户还可以使用,系统还没死透

2、未来缓存服务恢复后,系统可以立即恢复,无需再处理DB也挂掉的情况

当然,被限流的请求,最好也要有相应的处理,走【服务降级】,提供一些默认的值,或者友情提示。

Java环境中可以使用Guaua RateLimiterSentinelHystrix实现限流功能

方法(4)提前演练

6、如何避免缓存穿透

缓存穿透,是指查询缓存与数据库中一个一定不存在的数据,由于查询不到,将会前往数据库中查找,同样找不到,则不写入缓存。这是没意义的,也是非常消耗资源的,流量大时DB可能就挂掉了。

要是有人利用不存在的key频繁的攻击我们的应用,这就是漏洞。

两种解决办法:

方法(1)缓存空对象

当从DB查询数据为空,仍然将这个空结果缓存,使用特殊的标识,使其和真正的数据区分开。另外,需要设置一个较短的过期时间,建议不超过五分钟。

适用场景:数据命中率不高、需要保证一致性的场景

优点:代码维护简单

缺点:需要更多的内存、数据不一致

方法(2)BloomFilter 布隆过滤器(常用)

在缓存服务的基础上,构建BloomFilter数据结构,用来存储对应的Key是否存在的标记,如果存在,说明该key对应的值不为空。整个逻辑如下:

  1. 根据key查询布隆缓存。如果不存在直接返回,如果存在,继续向下执行。【后续的流程,就是标准的查缓存流程】

  2. 根据key查询缓存。如果存在,直接返回。如果不存在,继续向下执行。

  3. 根据key查询DB,如果存在,则更新到缓存,并返回该值。

适用场景:命中率不高、数据相对固定、实时性要求不高的场景

优点:缓存空间占用小

缺点:代码维护困难

实际场景中方案二使用比较多,因为省内存,对缓存的负荷小。

7、Redis中不支持BloomFilter数据结构,怎么实现布隆过滤器?

  1. RedisBloom

  2. Redis-Lua-scaling-bloom-filter,使用lua脚本实现布隆过滤器的功能

  3. Redisson BloomFilter,Java Redis库实现布隆过滤器的功能

8、为什么说BloomFilter中不存在key,就可以判定缓存或数据库中不存在对应数据?

9、使用布隆过滤器应该注意的地方

(1)误判存在的不一定存在,不存在的一定不存在。由于布隆过滤器不允许删除的特点这样会导致,后来新增了一个数据,布隆过滤器也会一直判其不存在。

使用布隆过滤器时,需要提前将已经存在的key,初始化到布隆缓存中

新增的数据的key怎么加到布隆缓存中?

10、如何避免击穿?

缓存击穿,是指某个缓存中的数据过期了,恰好这时有大量请求对这个key进行访问。这些请求发现缓存已过期,就会往DB中查询并回写到缓存,如果请求过大可能会瞬间会压垮DB。

和雪崩、穿透有相似之处。

区别:

和雪崩的区别:前者针对某一个KEY,后者针对很多个KEY。其实在我看来也可以没区别,都是雪崩。

和穿透的区别:这个key在数据库中是真实存在对应的数据的

解决方案:

方案(1) 使用互斥锁(分布式锁)

目的就是限制DB查询量,只允许一个线程去查询DB

方案(2)手动过期

11、如何保证缓存和DB的一致性(通常指最终一致性)?

主要有两种情况会导致缓存和DB的不一致问题

1.并发场景下,读取老的DB数据,更新到缓存中

这里,主要指的是,更新 DB 数据之前,先删除 Cache 的数据。在低并发量下没什么问题,但是在高并发下,就会存在问题。在(删除 Cache 的数据, 和更新 DB 数据)时间之间,恰好有一个请求,我们如果使用被动读,因为此时 DB 数据还是老的,又会将老的数据写入到 Cache 中。

2.缓存和DB的操作,不在一个事务中,可能只有DB操作成功,缓存操作失败,导致不一致

当然,有一点我们要注意,缓存和 DB 的一致性,我们指的更多的是最终一致性。我们使用缓存只要是提高读操作的性能,真正在写操作的业务逻辑,还是以数据库为准。

解决方案:

方案(1)先淘汰缓存,再写数据库

实现方案:引入分布式锁,将并行写变为穿行写

  • 在写请求时,先淘汰缓存之前,先获取该分布式锁。

  • 在读请求时,发现缓存不存在时,先获取分布式锁。

方案(2)先写数据库,再更新缓存

感谢各位的阅读,以上就是"redis缓存常见的问题有哪些"的内容了,经过本文的学习后,相信大家对redis缓存常见的问题有哪些这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0