这篇文章主要讲解了“redis缓存常见的问题有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“redis缓存常见的问题有哪些”吧!
缓存,就是数据交换的缓冲区,针对服务对象的不同(CPU、内存、磁盘等)都可以构建缓存。
目的是,把读写速度慢的介质中的数据保存在读写速度快的介质中,提升效率。
例如:
· CPU高速缓存
· 内存缓存
将磁盘中常用的数据保存在内存中。
日常业务中,我们使用比较多的数据库是Mysql,缓存是Redis。Redis的性能比Mysql要快得多,因此我们将Mysql中的热点数据,缓存到Redis中,提升读取性能,减少数据库压力。
读数据时,从redis中读取,redis中没有,再去mysql中读取。
写数据时,先写到redis中,再定时异步回写到redis中,或者同步回写。
场景:
1、论坛帖子的访问频率比较高,且需要实时地更新阅读量,可以使用Redis记录帖子的阅读量,提升并发度和性能
2、商品信息,更新的频率不高,但是读取的频率比较高,特别是热门商品,因此将热门商品信息存储在Redis中
LRU(least recently used) 最近最少使用
LFU(least frequently used) 最不经常使用
FIFO 先进先出
这里介绍的是Java环境中的
本地缓存:
Guava LocalCache、Ehcache、Caffeine
Ehcache 的功能更加丰富,Caffeine 的性能要比 Guava LocalCache 好。
分布式缓存:
Redis、MemCache、Tair
Redis 最为主流和常用。
写入问题:
缓存何时写入?如何避免多线程环境下重读写入?
缓存如何失效?
缓存和DB的一致性如何保证
经典三连问:
如何避免缓存穿透?
如何避免缓存击穿?
如何避免缓存雪崩?
实际业务中,如果缓存系统出现了问题(宕机),程序中应该手动捕获这个异常,并且记录日志,然后从数据库查询数据返回给用户,这样将不会导致业务不可用。但随着而来的一个问题就是,缓存雪崩。
缓存雪崩,是指缓存由于有些原因无法提供服务,所有请求全部抵达DB,导致DB负荷大增,最终挂掉的情况。
如何解决:
方法(1)缓存高可用
通过搭建缓存的高可用,避免缓存挂掉导致无法提供服务的情况,从而降低出现缓存雪崩的情况的概率。
假设我们使用Redis作缓存,可以使用Redis Sentinel或Redis Cluster实现高可用。
方法(2)本地缓存
使用本地缓存,即使分布式缓存挂掉了,也可以将DB查询到的结果缓存到本地,避免后续的请求全部到达DB。
java环境中可以使用的本地缓存工具上文已经介绍。
方法(3)请求DB限流
限制DB的每秒请求树,避免DB挂掉,这样做至少有两个好处:
1、可能有一部分用户还可以使用,系统还没死透
2、未来缓存服务恢复后,系统可以立即恢复,无需再处理DB也挂掉的情况
当然,被限流的请求,最好也要有相应的处理,走【服务降级】,提供一些默认的值,或者友情提示。
Java环境中可以使用Guaua RateLimiter、Sentinel、Hystrix实现限流功能
方法(4)提前演练
缓存穿透,是指查询缓存与数据库中一个一定不存在的数据,由于查询不到,将会前往数据库中查找,同样找不到,则不写入缓存。这是没意义的,也是非常消耗资源的,流量大时DB可能就挂掉了。
要是有人利用不存在的key频繁的攻击我们的应用,这就是漏洞。
两种解决办法:
方法(1)缓存空对象
当从DB查询数据为空,仍然将这个空结果缓存,使用特殊的标识,使其和真正的数据区分开。另外,需要设置一个较短的过期时间,建议不超过五分钟。
适用场景:数据命中率不高、需要保证一致性的场景
优点:代码维护简单
缺点:需要更多的内存、数据不一致
方法(2)BloomFilter 布隆过滤器(常用)
在缓存服务的基础上,构建BloomFilter数据结构,用来存储对应的Key是否存在的标记,如果存在,说明该key对应的值不为空。整个逻辑如下:
根据key查询布隆缓存。如果不存在,直接返回,如果存在,继续向下执行。【后续的流程,就是标准的查缓存流程】
根据key查询缓存。如果存在,直接返回。如果不存在,继续向下执行。
根据key查询DB,如果存在,则更新到缓存,并返回该值。
适用场景:命中率不高、数据相对固定、实时性要求不高的场景
优点:缓存空间占用小
缺点:代码维护困难
实际场景中方案二使用比较多,因为省内存,对缓存的负荷小。
RedisBloom
Redis-Lua-scaling-bloom-filter,使用lua脚本实现布隆过滤器的功能
Redisson BloomFilter,Java Redis库实现布隆过滤器的功能
(1)误判。存在的不一定存在,不存在的一定不存在。由于布隆过滤器不允许删除的特点这样会导致,后来新增了一个数据,布隆过滤器也会一直判其不存在。
使用布隆过滤器时,需要提前将已经存在的key,初始化到布隆缓存中
新增的数据的key怎么加到布隆缓存中?
缓存击穿,是指某个缓存中的数据过期了,恰好这时有大量请求对这个key进行访问。这些请求发现缓存已过期,就会往DB中查询并回写到缓存,如果请求过大可能会瞬间会压垮DB。
和雪崩、穿透有相似之处。
区别:
和雪崩的区别:前者针对某一个KEY,后者针对很多个KEY。其实在我看来也可以没区别,都是雪崩。
和穿透的区别:这个key在数据库中是真实存在对应的数据的
解决方案:
方案(1) 使用互斥锁(分布式锁)
目的就是限制DB查询量,只允许一个线程去查询DB
方案(2)手动过期
主要有两种情况会导致缓存和DB的不一致问题
1.并发场景下,读取老的DB数据,更新到缓存中
这里,主要指的是,更新 DB 数据之前,先删除 Cache 的数据。在低并发量下没什么问题,但是在高并发下,就会存在问题。在(删除 Cache 的数据, 和更新 DB 数据)时间之间,恰好有一个请求,我们如果使用被动读,因为此时 DB 数据还是老的,又会将老的数据写入到 Cache 中。
2.缓存和DB的操作,不在一个事务中,可能只有DB操作成功,缓存操作失败,导致不一致
当然,有一点我们要注意,缓存和 DB 的一致性,我们指的更多的是最终一致性。我们使用缓存只要是提高读操作的性能,真正在写操作的业务逻辑,还是以数据库为准。
解决方案:
方案(1)先淘汰缓存,再写数据库
实现方案:引入分布式锁,将并行写变为穿行写
在写请求时,先淘汰缓存之前,先获取该分布式锁。
在读请求时,发现缓存不存在时,先获取分布式锁。
方案(2)先写数据库,再更新缓存
感谢各位的阅读,以上就是“redis缓存常见的问题有哪些”的内容了,经过本文的学习后,相信大家对redis缓存常见的问题有哪些这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。