重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要讲解了“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缓存常见的问题有哪些这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!