必知必会 | 关于Redis缓存这三大问题,必知必会



HI!我是小小,咱们昨天没有见面,是由于昨天小小一天都在火车上呆,准备去广州的考试,因此脱稿一天,不过今天,小小的小blog已经开始恢复更新了。web

汇报一下进度

小小今天坐车路过武汉,武汉武昌的一张路过照片。redis

下面开始今天的正文,看见小小怎么辛苦的份上,滑到底下,给个素质三连?数据库


缓存雪崩

缓存雪崩是指在某一个时间段内,缓存集中过时失效,若是这个时间段内有大量请求,而查询数据量巨大,全部的请求都会达到存储层,存储层的调用量会暴增,引发数据库压力过大甚至宕机。数组

缘由

  1. Redis忽然宕机
  2. 大部分数据失效

举个栗子

好比咱们基本上都经历过购物狂欢节,假设商家举办 23:00-24:00 商品打骨折促销活动。程序小哥哥在设计的时候,在 23:00 把商家打骨折的商品放到缓存中,并经过redis的expire设置了过时时间为1小时。这个时间段许多用户访问这些商品信息、购买等等。可是恰好到了24:00点的时候,刚好还有许多用户在访问这些商品,这时候对这些商品的访问都会落到数据库上,致使数据库要抗住巨大的压力,稍有不慎会致使,数据库直接宕机(over)。缓存

当商品没有失效的时候是这样的:

当缓存GG(失效)的时候倒是这样的:

对于缓存雪崩有如下解决方案:

(1)redis高可用微信

redis有可能挂掉,多增长几台redis实例,(一主多从或者多主多从),这样一台挂掉以后其余的还能够继续工做,其实就是搭建的集群。数据结构

(2)限流降级并发

在缓存失效后,经过加锁或者队列来控制读数据库写缓存的线程数量,对某个key只容许一个线程查询数据和写缓存,其余线程等待。编辑器

(3)数据预热分布式

数据加热的含义就是在正式部署以前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不一样的key。

(4)不一样的过时时间

设置不一样的过时时间,让缓存失效的时间点尽可能均匀。

缓存穿透

什么是缓存穿透,当用户在查询一条数据的时候,而此时数据库和缓存没有任何关于这条数据的任何记录的时候,当这条数据再缓存中没找到数据,就会向数据库请求数据,这样就会对数据库形成比较大的压力。如:用户查询一个 id = -1 的商品信息,通常数据库 id 值都是从 1 开始自增,很明显这条信息是不在数据库中,当没有信息返回时,会一直向数据库查询,给当前数据库的形成很大的访问压力。解决方案有俩个,分别为缓存空对象,布隆过滤器。

缓存空对象

缓存空对象它就是指一个请求发送过来,若是此时缓存中和数据库都不存在这个请求所要查询的相关信息,那么数据库就会返回一个空对象,并将这个空对象和请求关联起来存到缓存中,当下次仍是这个请求过来的时候,这时缓存就会命中,就直接从缓存中返回这个空对象,这样能够减小访问数据库的压力,提升当前数据库的访问性能。咱们接下来能够看下面这个流程而且为了大量的空对象过多,致使缓存空对象也过多,因此须要利用Redis的过时机制,解决这个问题。

setex key seconds valule:设置键值对的同时指定过时时间(s)

在Java中

redisCache.put(Integer.toString(id), null, 60) //过时时间为 60s

布隆过滤器

布隆过滤器用来过滤东西的。它是一种基于几率的数据结构,主要使用爱判断当前某个元素是否在该集合中,运行速度快。咱们也能够简单理解为是一个不怎么精确的 set 结构(set 具备去重的效果)。可是有个小问题是:当你使用它的 contains 方法去判断某个对象是否存在时,它可能会误判。也就是说布隆过滤器不是特别不精确,可是只要参数设置的合理,它的精确度能够控制的相对足够精确,只会有小小的误判几率。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就确定不存在。

举个栗子

打个比方,当它说不认识你时,确定就不认识;当它说见过你时,可能根本就没见过面,不过由于你的脸跟它认识的人中某脸比较类似 (某些熟脸的系数组合),因此误判之前见过你。在上面的使用场景中,布隆过滤器能准确过滤掉那些已经看过的内容,那些没有看过的新内容,它也会过滤掉极小一部分 (误判),可是绝大多数新内容它都能准确识别。这样就能够彻底保证推荐给用户的内容都是无重复的。

特色

  1. 一个很是大的二进制位数组(数组中只存在 0 和 1)
  2. 拥有若干个哈希函数(Hash Function)
  3. 在空间效率和查询效率都很是高
  4. 布隆过滤器不会提供删除方法,在代码维护上比较困难。

每一个布隆过滤器对应到 Redis 的数据结构里面就是一个大型的位数组和几个不同的无偏 hash 函数。所谓无偏就是可以把元素的 hash 值算得比较均匀。向布隆过滤器中添加 key 时,会使用多个 hash 函数对 key 进行 hash 算得一个整数索引值而后对位数组长度进行取模运算获得一个位置,每一个 hash 函数都会算得一个不一样的位置。再把位数组的这几个位置都置为 1 就完成了 add 操做。( 每个 key 都经过若干的hash函数映射到一个巨大位数组上,映射成功后,会在把位数组上对应的位置改成1。)

为何存在误判率

当 key1 和 key2 映射到位数组上的位置为 1 时,假设这时候来了个 key3,要查询是否是在里面,刚好 key3 对应位置也映射到了这之间,那么布隆过滤器会认为它是存在的,这时候就会产生误判(由于明明 key3 是不在的)。

提升准确率

  1. 哈希函数的好坏
  2. 存储空间大小
  3. 哈希函数个数 hash函数的设计也是一个十分重要的问题,对于好的hash函数能大大下降布隆过滤器的误判率。同时,对于一个布隆过滤器来讲,若是其位数组越大的话,那么每一个key经过hash函数映射的位置会变得稀疏许多,不会那么紧凑,有利于提升布隆过滤器的准确率。同时,对于一个布隆过滤器来讲,若是key经过许多hash函数映射,那么在位数组上就会有许多位置有标志,这样当用户查询的时候,在经过布隆过滤器来找的时候,误判率也会相应下降。

缓存击穿

一个被常常访问而且查询到的key,常常有用户访问,可是这个时候,这个key正好到了失效时间,或者忽然变成冷门key,此时仍然有大量的关于这个的key的请求,这样会形成大量的并发访问到数据库,形成数据库的压力剧增。致使缓存击穿的产生。

缘由有两条。

  1.  一个冷门的key,忽然有大量的用户请求访问。

  2. 一个热门的key刚好到了过时的时间。

缓存击穿问题的解决: 加锁,对于key过时的时候,查询数据库的时候加锁,可让只有一个链接访问到数据库,而后获取到key缓存到redis中,减小了缓存的压力。在单机幻觉使用单机的锁,在分布式环境下使用分布式锁。


关于做者

一个生于二线,生存在一线的程序猿,佛系生活,佛系度日,我是小小,咱们下期再见。

小明菜市场

推荐阅读

● 必备收藏 |详解 | 求你别用效率低下的I/O了,要不试试这种I/O

● 明了 | 看了这篇文章,多年不能理解的分布式事物,终于看懂了!

● 推荐 | 做为IDEA的死忠粉,这样设置,效果棒棒哒!

● 异常 | 求你别再写满屏的try-catch了,用全局异常好吗?- 夹私货-行测

● 探讨 | 深刻探讨Redis管道

给我个好看再走好吗?


本文分享自微信公众号 - 小明菜市场(fileGeek)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索