Redis从入门到精通(九、Redis使用中常见的问题)

Redis 在为程序带来性能提高的同时,也会有缺点,这些都是我们需要考虑的,比如: Redis与持久化数据库的数据一致性问题,缓存雪崩问题,缓存穿透问题,缓存击穿问题等,本文就上述几个问题,简单的阐述一下解决思路。

缓存穿透

如果我们的查询数据路线是: App -> Redis -> MySQL(或其它RDBS),正常情况下,我们查询数据都会在Redis命中,Redis未命中的情况下才去查询MySQL,然后将查询到的数据写入到Redis中,这样下次就直接可以在Redis层命中。

那么如果查询一条MySQL中压根儿根本就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。这种查询不存在数据的现象我们称为缓存穿透

解决方案(缓存穿透)

  • 将null值存入redis,设置过期时间
  • BloomFilter

第一种方案比较简单易懂,查询不到数据,将Null值存到Redis中,并设置上过期时间,这样下次请求再过来,可以直接返回Null,不会再落到MySQL。

但是,针对于一些恶意攻击,攻击带过来的大量key 是不存在的,那么我们采用第一种方案就会缓存大量不存在key的数据。此时我们采用第一种方案就不合适了,我们完全可以先对使用第二种方案进行过滤掉这些key。关于 BloomFilter , 下文列出简单的描述,我们可以在应用层加一层 BloomFilter 来解决这个问题。

Bloomfilter: 布隆过滤器, 它是由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率。即Bloom Filter报告某一元素存在于某集合中,但是实际上该元素并不在集合中。但是如果某个元素确实没有在该集合中,那么Bloom Filter 是不会报告该元素存在于集合中的,所以不会漏报。

针对key非常多、请求重复率比较低的数据,我们就没有必要进行缓存,使用第二种方案直接过滤掉。而对于空数据的key有限的,重复率比较高的,我们则可以采用第一种方式进行缓存。


缓存击穿

在高并发的系统中,大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿

解决方案(缓存击穿)

  • 热点Key不设置过期时间
  • 使用 互斥锁,在第一个查询数据的请求上使用一个互斥锁来锁住它。后续线程阻塞,等第一个线程查询到数据并做了缓存,锁释放后后续线程,发现已经有缓存了,就直接走缓存。

第一种方案使用具有局限性,需要结合业务考虑是否可以不设置过期时间。
第二种方案,由于使用了互斥锁,所以性能肯定会差很多。


缓存雪崩

缓存雪崩的情况是说,当某一时刻发生大规模的缓存失效的情况 或者 缓存服务宕机了,会有大量的请求进来直接打到DB上面。称为 缓存雪崩

解决方案(缓存雪崩)

  • 保证Redis服务的高可用
  • 应用种使用本地缓存,以及限流降级等措施
  • 解决热点数据集中失效,为每个key设置不同的过期时间

Redis 的集群是必须要做的,保证Redis服务的高可用,在应用种也要处理Redis宕机的情况,比如做出限流或者降级的措施,采用本地缓存等,让查询请求尽可能少的落到数据库上。Redis的集群方案怎么来做,可以参考我之前的文章。

针对一些热点数据集中失效的问题,可以采用设置不同的过期时间的方案,在一个基础时间上左右浮动,例如: 30min + 3s,30min -5s .


Redis与持久层数据一致性的问题

App -> Redis -> MySQL ,App查询请求先请求Redis,如果查询不到再请求MySQL,查询到数据后将数据写入MySQL。

在这样的一条查询链路种,由于数据的写入可能会造成Redis与MySQL数据的不一致。

比如: 数据写入时,先写入Redis再写入MySQL,可能在写入MySQL时出现异常,导致数据不一致,反过来也是如此。

解决方案(数据不一致)

  • 写入时,删除Redis中的数据

总结

在实际使用过程种还是要结合具体的业务,来从上述几个方面来考虑程序的健壮性。最终的目的都是保护数据库。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Redis是什么 Redis是1个内存数据库,非关系型,基于Key-Value存储,速度快 支持多种数据类型,St...
    Goooooooooooal阅读 1,259评论 0 0
  • Redis用作缓存,主要两个用途:高性能,高并发,因为内存天然支持高并发 一.缓存穿透: 缓存穿透是指查询一个一定...
    Y了个J阅读 932评论 0 0
  • 今天看到一位朋友写的mysql笔记总结,觉得写的很详细很用心,这里转载一下,供大家参考下,也希望大家能关注他原文地...
    信仰与初衷阅读 4,768评论 0 30
  • 缓存是分布式系统中的重要组件,主要解决高并发,大数据场景下,热点数据访问的性能问题。提供高性能的数据快速访问。 一...
    Java架构师Carl阅读 1,238评论 0 23
  • 一、Redis 1、概述 Redis是速度非常快的非关系型内存键值数据库,可以存储键和物种不同类型的值之间的映射。...
    落地生涯阅读 792评论 0 3