细说redis-p2(2022.03.20)

Mr.DreamerZ Mr.DreamerZ     2022-12-05     577

关键词:

上一章我们已经了解了redis是干嘛以及集群等功能以及细节。这一章我们来聊聊缓存的设计和使用redis需要注意的点以及过期数据处理的策略。

细说Redis-p2

1. 多级缓存的设计

通常来说亿万级流量电商微服务架构如下

让我们一层层的来剖析一下

1.1 Ngnix层

Ngnix是高性能的HTTP和反向代理web服务器,有不是很清楚的同学可以去看看我之前写的Nginx文章,能够让大家对Nginx有一个大致的了解。
对于电商系统来说,比如说双11的时候,肯定会有那种特别火商品,刚开始抢购就会有上万人或者十万、百万人去抢购,比如说:限量的茅台酒、当天折扣的奢侈品等。
对于这些商品,都是热点数据中的热点数据。通常这一类数据,我们都会避免让请求直接打到redis或者web上面,来减轻redis的负担。
流程如下:
1.nginx会找到对应的本地html模板
2.nginx读取本地的缓存中获取数据
3.渲染后形成页面,返回给用户
要知道,这个速度很快,因为全是内存操作

1.2 EhCache层

这里不对 EhCache做过多说明,不清楚的同学可以看看下面两篇帖子
EhCache是什么
EhCache和Redis的区别
简单来说,多级缓存的目的就是为了提速和减轻web的访问压力。不管是我们刚刚提到的使用nginx转发到本地内存或是现在的EhCache,都是为了提高访问的速度。因为你光用redis根本没办法承受如此大的流量冲击

1.3 Redis层

Redis应该是我们作为缓存工具做常见的了,基本上来说就是为访问数据库最后一道拦截了。要知道磁盘和内存的读取速率大约差了4个数量级。都在内存中找要远远好过都在磁盘中找。

mysql的访问不再赘述

总结下:之所以采用这套架构就是为了提高服务的可用性以及尽可能的对读取速度提速

2. Redis的常见问题

2.1 缓存击穿

概念:
简单来说,缓存击穿就是说请求的数据在Redis中找不到(可能这个时刻失效了),导致该请求直接打到数据库中。但是如果在同一时刻出现大量的这种情况,将会导致数据库挂掉。

解决办法:
为了避免同一时刻大量的缓存失效,我们通常在设置过期时间时,加上一个随机时间。这样可以避免同一个时刻大量的缓存失效的情况。

2.2 缓存穿透

概念:
查询一个缓存层和数据库中都不会命中的数据。导致Redis和数据都被击穿

出现这种情况的原因:
1.自身的业务逻辑出现问题或者数据出现问题
2.恶意的攻击

解决方案:
1.空值缓存:
如果出现Redis及数据库中都没有的数据,那么设置一个空值缓存,将其放入我们的内存中(这样可以避免Redis去存这一系列的数据)。

2.我们也可以使用布隆过滤器来更好的解决这个问题

2.3 缓存雪崩

概念:缓存雪崩其实和缓存击穿有些类似,都是指在缓存中找不到数据了。但是缓存雪崩更为可怕,它是指缓存层支撑不住或宕掉后, 大量请求打向后端存储层。
解决方案:
1.保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cluster。
2. 依赖隔离组件为后端限流熔断并降级。比如使用Sentinel或Hystrix限流降级组件。

3.Redis对于过期键清除策略

3.1 被动删除(惰性删除)

当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期 key

3.2 主动删除

由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key

3.3 主动清理策略

当前已用内存超过maxmemory限定时,触发主动清理策略
主动清理策略在Redis 4.0 之前一共实现了 6 种内存淘汰策略,在 4.0 之后,又增加了 2 种策 略,总共8种

a) 针对设置了过期时间的key做处理:

  1. volatile-ttl:在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删 除,越早过期的越先被删除。
  2. volatile-random:就像它的名称一样,在设置了过期时间的键值对中,进行随机删除。
  3. volatile-lru:会使用 LRU 算法筛选设置了过期时间的键值对删除。
  4. volatile-lfu:会使用 LFU 算法筛选设置了过期时间的键值对删除。

b) 针对所有的key做处理:

  1. allkeys-random:从所有键值对中随机选择并删除数据。
  2. allkeys-lru:使用 LRU 算法在所有数据中进行筛选删除。
  3. allkeys-lfu:使用 LFU 算法在所有数据中进行筛选删除

c) 不处理:

  1. noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息"(error) OOM command not allowed when used memory",此时Redis只响应读操作。

常见的使用策略

LRU 算法(Least Recently Used,最近最少使用) 淘汰很久没被访问过的数据,以最近一次访问时间作为参考。

LFU 算法(Least Frequently Used,最不经常使用) 淘汰最近一段时间被访问次数最少的数据,以次数作为参考。

4. 布隆过滤器

对于恶意攻击,向服务器请求大量不存在的数据造成的缓存穿透,还可以用布隆过滤器先做一次过滤,对于不存在的数据布隆过滤器一般都能够过滤掉,不让请求再往后端发送。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在(先记住这句话)

布隆过滤器其实就是一个大型的位数组和几个不一样的无偏 hash 函数(所谓无偏就是能够把元素的 hash 值算得比较均匀)

画重点:它的底层就是由一个很长很长的二进制的数组构成的。

布隆过滤器执行过程:
1.向布隆过滤器中添加key时,会使用多个hash函数对key进行 hash算得一个整数索引值(进行多次hash运算)

2.然后对位数组长度进行取模运算得到一个位置,每个hash函数都会算得一个不同的位置。再把位数组的这几个位置都置为1就完成了add 操作。

3.向布隆过滤器询问 key 是否存在时,跟add一样,也会把 hash的几个位置都算出来,看看位数组中这几个位置是否都为 1,只要有一个位为 0,那么说明布隆过滤器中这个key 不存在。如果都是 1,这并不能说明这个 key 就一定存在,只是极有可能存在。

问题:

  1. 为什么说当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在呢?
    刚刚我们提到了布隆过滤器会将这个key进行多次hash运算,然后将得到的数值和布隆过滤器的长度进行取模,然后将得到的结果在布隆过滤器上找到这个位置,看看这个位置上有没有放数据。
    所以说不存在肯定不存在,存在可能不存在的原因则是因为出现hash碰撞导致的。(因为这些位被置为 1 可能是因为其它的 key 存在所致。如果这个位数组 比较稀疏,这个概率就会很大,如果这个位数组比较拥挤,这个概率就会降低

  2. 布隆过滤器的长度如果设置的很小,那么出现差错的概率不就越大吗?
    所以说我们设置长度都是很长很长的。

  3. 设置的越长,那么占用的空间不就越大吗?
    这个不用担心,就算你设置1一个亿的长度,也占用不了多大的空间。因为布隆过滤器是是以位为单位,8个位(bit)才是1个byte。你设置为1一个亿又能占用多大呢?

所以说,使用布隆过滤器要比设置空值缓存好的多。因为如果出现恶意攻击,如果有1千万个不存在的key,那么对于内存或者redis的空间占用是非常大的。但是布隆过滤器的特性,对比下来则占用的空间非常小。

使用的时候要注意:布隆过滤器是不能进行修改的,只能一开始就将数据导入

细说redis-p1(2022.03.13)(代码片段)

Redis在我们工作中可以说用的非常多。大多用来会话存放、消息队列(支付)、活动排行榜或计数等。但我们其实很多时候是只管去用,却也没有对它进行更深层次的探索。这段时间正好也重温了一下Redis,写下来... 查看详情

细说redis-p1(2022.03.13)(代码片段)

Redis在我们工作中可以说用的非常多。大多用来会话存放、消息队列(支付)、活动排行榜或计数等。但我们其实很多时候是只管去用,却也没有对它进行更深层次的探索。这段时间正好也重温了一下Redis,写下来... 查看详情

102022春天过去了

什么东西都阻止不了它的生长吧 我能做的就是欣赏 珍惜这段时间 2022-02-122022-02-192022-02-262022-03-062022-03-13  2022-03-20 2022-03-26 完  查看详情

leetcode解题笔记链表(代码片段)

文章目录一、总结二、题目237.删除链表中的节点(2022/03/10)19.删除链表的倒数第N个结点(2022/03/11)206.反转链表(2022/03/18)21.合并两个有序链表(2022/03/19)234.回文链表(2022/03/20)141. 查看详情

leetcode解题笔记链表(代码片段)

文章目录一、总结二、题目237.删除链表中的节点(2022/03/10)19.删除链表的倒数第N个结点(2022/03/11)206.反转链表(2022/03/18)21.合并两个有序链表(2022/03/19)234.回文链表(2022/03/20)141. 查看详情

leetcode解题笔记链表(代码片段)

文章目录一、总结二、题目237.删除链表中的节点(2022/03/10)19.删除链表的倒数第N个结点(2022/03/11)206.反转链表(2022/03/18)21.合并两个有序链表(2022/03/19)234.回文链表(2022/03/20)141. 查看详情

细说泛型

C#2的头号亮点:泛型在C#1中,Arraylist总是会给人带来困扰,因为它的参数类型是Object,这就让开发者无法把握集合中都有哪些类型的数据。如果对string类型的数据进行算术操作那自然会报错,但是遺憾的是在編譯期不会给你任何... 查看详情

细说mysql索引

   1.什么是索引    索引是一种数据结构,会对添加索引的字段的值进行排序存放,提高查询效率;一张表中可以添加多个索引;innodb存储引擎默认使用的是b+tree索引结构,也支持哈希、全文索引。    2.索引的... 查看详情

细说mysql中磁盘与cpu的交互——神秘的bufferpool(代码片段)

文章目录1.MySQL是如何读取记录的——缓存的重要性2.InnoDB的BufferPool2.1什么是BufferPool2.2BufferPool的内部结构2.3free链表2.4如何知道磁盘页在BufferPool是否已存在——缓存页的hash2.5flush链表2.6LRU链表2.6.1BufferPool不够怎么办2.6.2简单的LRU... 查看详情

细说mysql中磁盘与cpu的交互——神秘的bufferpool(代码片段)

文章目录1.MySQL是如何读取记录的——缓存的重要性2.InnoDB的BufferPool2.1什么是BufferPool2.2BufferPool的内部结构2.3free链表2.4如何知道磁盘页在BufferPool是否已存在——缓存页的hash2.5flush链表2.6LRU链表2.6.1BufferPool不够怎么办2.6.2简单的LRU... 查看详情

细说log4j之概述

log4j官网:https://logging.apache.org/ 概述log4j目前存在2个版本:log4j1.x和log4j2.x,目前官方主推2.x版本(log4j1.x已于2015.08.05宣布停止开发,官方建议将1.x升级为2.x版本)。log4j1.x最后一个版本是1.2.17,详见:https://logging.apache.org/log4... 查看详情

2万字+20张图|细说redis九种数据类型和应用场景

作者:小林coding计算机八股文网(操作系统、计算机网络、计算机组成、MySQL、Redis):https://xiaolincoding.com大家好,我是小林。我们都知道Redis提供了丰富的数据类型,常见的有五种:String(字符串),Hash(哈希),List(列表),S... 查看详情

2万字+50张图,细说jvm内存分布内存对齐压缩指针!(代码片段)

今天为大家带来一篇2万字的硬核技术文章。本文我们将从计算机组成原理的角度详细阐述对象在JVM内存中是如何布局的,以及什么是内存对齐,如果我们头比较铁,就是不进行内存对齐会造成什么样的后果,最后引出压缩指针... 查看详情

:细说贝叶斯滤波:bayesfilters

认知计算,还要从贝叶斯滤波的基本思想讲起。这一部分,我们先回顾贝叶斯公式的数学基础,然后再来介绍贝叶斯滤波器。(一).概率基础回顾我们先来回顾一下概率论里的基本知识:1.(X): 表示一个随机变量,如果它有有限... 查看详情

细说:unicode,utf-8,utf-16,utf-32,ucs-2,ucs-4

转载自:http://www.cnblogs.com/malecrab/p/5300503.html==================1.Unicode与ISO10646全世界很多个国家都在为自己的文字编码,并且互不想通,不同的语言字符编码值相同却代表不同的符号(例如:韩文编码EUC-KR中“???”的编码值正好是汉... 查看详情

2万字+20张图|细说redis九种数据类型和应用场景(代码片段)

作者:小林coding计算机八股文网(操作系统、计算机网络、计算机组成、MySQL、Redis):https://xiaolincoding.com大家好,我是小林。我们都知道Redis提供了丰富的数据类型,常见的有五种:String(字符串),... 查看详情

ng-class细说by破狼

在angular中为我们提供了3种方案处理class:1:scope变量绑定,如上例。(不推荐使用)2:字符串数组形式。3:对象key/value处理。我们继续其他两种解决方案:1字符串数组形式是针对class简单变化,具有排斥性的变化,true是什么cl... 查看详情

性能再次大幅提升!细说vue.js3.2关于响应式部分的优化(代码片段)

背景Vue3正式发布距今已经快一年了,相信很多小伙伴已经在生产环境用上了Vue3了。如今,Vue.js3.2已经正式发布,而这次minor版本的升级主要体现在源码层级的优化,对于用户的使用层面来说其实变化并不大。其中... 查看详情