zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

Redis面试题

2023-09-11 14:20:02 时间

1、什么是Redis?

Redis是现在最受欢迎的NoSQL数据库之⼀,Redis是⼀个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,其具备如下特性:

  • 基于内存运行,性能高效(每秒可以处理超过 10万次读写操作);
  • 支持分布式,理论上可以无线扩展;
  • key-value存储系统(key是字符串,键有字符串、列表、集合、散列表、有序集合等);
  • 开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语⾔的API;

2、Redis数据类型有哪些、

Redis主要有 5 种数据类型,包括 String,List,Set,Zset,Hash,满足大部分的使用要求。

但Redis还为我们提供了几种⾼级数据结构,bitmaps,HyperLogLong、Geo,其中bitmaps,HyperLogLong底层是基于String,Geo则是基于zset

String

介绍:

字符串类型是Redis最基础的数据结构。首先键都是字符串类型,而且其他几种数据结构都是在字符串类型基础上构建的,所以字符串类型能为其他四种数据结构的学习奠定基础。字符串类型的值实际可以是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、数字(整数、浮点数),甚至是⼆进制(图片、音频、视频),但是值最大不能超过512MB。

计数

使用Redis 作为计数的基础功能工具,它可以实现快速计数、查询缓存的功能,同时数据可以异步落地到其他数据源。

共享Session

⼀个分布式Web服务将⽤户的Session信息(例如用户登录信息)保存在各自服务器中,这样会造成⼀个问题,出于负载均衡的考虑,分布式服务会将⽤户的访问均衡到不同服务器上,用户刷新⼀次访问可能会发现需要重新登录,这个问题是用户无法容忍的。

为了解决这个问题,可以使⽤Redis将用户的Session进⾏集中管理,,在这种模式下只要保证Redis是高可用和扩展性的,每次⽤户更新或者查询登录信息都直接从Redis中集中获取。

限速

比如,很多应⽤出于安全的考虑,会在每次进行登录时,让用户输⼊手机验证码,从而确定是否是用户本⼈。但是为了短信接⼝不被频繁访问,会限制⽤户每分钟获取验证码的频率,例如⼀分钟不能超过5次。⼀些⽹站限制⼀个IP地址不能在⼀秒钟之内⽅问超过n次也可以采⽤类似的思路。

List

list 即是链表

列表( list)类型是用来存储多个有序的字符串,a、b、c、d、e五个元素从左到右组成了⼀个有序

的列表,列表中的每个字符串称为元素(element) 列表类型有两个特点:第⼀、列表中的元素是有序的,这就意味着可以通过索引下标获取某个元素或者某个范围内的元素列表。第⼆、列表中的元素可以是重复的。

Hash

介绍:hash 类似于 JDK1.8 前的 HashMap,内部实现也差不多(数组 + 链表)。

使用场景:

使用String类型存储:

set user:1:name king;
set user:1:age 18;
set user:1:sex boy;

优点:简单直观,每个键对应⼀个值

缺点:键数过多,占⽤内存多,⽤户信息过于分散,不⽤于生产环境

将对象序列化存入 Redis

set user:1 serialize(userInfo);

优点:编程简单,若使⽤序列化合理内存使用率高

缺点:序列化与反序列化有⼀定开销,更新属性时需要把userInfo全取出来进⾏反序列化,

更新后再序列化到redis

使用Hash类型

hmset user:1 name King age 18 sex boy

优点:简单直观,使⽤合理可减少内存空间消耗

缺点:要控制内部编码格式,不恰当的格式会消耗更多内存

Set

介绍:set 类似于 Java 中的 HashSet 。Redis 中的 set 类型是⼀种无序集合,集合中的元素没有先后顺序。当你需要存储⼀个列表数据,又不希望出现重复数据时,set 是⼀个很好的选择。

使用场景:

set 提供了判断某个成员是否在⼀个 set 集合内的重要接⼝,这个也是 list 所不能提供的。可以基于 set轻易实现交集、并集、差集的操作。

集合类型比较典型的使用场景是标签( tag)。例如⼀个用户可能对娱乐、体育比较感兴趣,另⼀个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。有了这些数据就可以得到喜欢同⼀个标签的人,以及用户的共同喜好的标签,这些数据对于用户体验以及增强用户黏度比较重要。

例如⼀个电子商务的网站会对不同标签的用户做不同类型的推荐,比如对数码产品⽐较感兴趣的人,在各个页面或者通过邮件的形式给他们推荐最新的数码产品,通常会为⽹站带来更多的利益。除此之外,集合还可以通过⽣成随机数进进比如抽奖活动,以及社交图谱等等。

Zset

介绍:

有序集合相对于哈希、列表、集合来说会有⼀点点陌生,但既然叫有序集合,那么它和集合必然有着联系,它保留了集合不能有重复成员的特性,但不同的是,有序集合中的元素可以排序。但是它和列表使用索引

下标作为排序依据不同的是,它给每个元素设置⼀个分数( score)作为排序的依据。

有序集合中的元素不能重复,但是score可以重复,就和⼀个班里的同学学号不能重复,但是考试成绩可以相同。

有序集合提供了获取指定分数和元素范围查询、计算成员排名等功能,合理的利用有序集合,能帮助我们在实际开发中解决很多问题。

使用场景:

有序集合⽐较典型的使⽤场景就是排⾏榜系统。例如视频⽹站需要对⽤户上传的视频做排⾏榜,榜单的维度可能是多个⽅⾯的:按照时间、按照播放数量、按照获得的赞数。

Bitmap

介绍:

现代计算机用⼆进制(位)作为信息的基础单位,1个字节等于8位,例如“big”字符串是由3个字节组成,但实际在计算机存储时将其⽤⼆进制表示,“big”分别对应的ASCII码分别是 98、105、103,对应的⼆进制分别是 01100010、01101001和 01100111。

Bitmaps 本身不是⼀种数据结构,实际上它就是字符串,但是它可以对字符串的位进行操作。

Bitmaps 单独提供了⼀套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。可以把

Bitmaps 想象成⼀个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在 Bitmaps 中叫做偏移量。

使用场景:适合需要保存状态信息(比如是否签到、是否登录...)并需要进⼀步对这些信息进行分析的场景。比如用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。

3、Redis 效率为什么这么高

IO多路复用机制详解 - Yeang - 博客园

  1. 数据存放是居于内存到硬盘中
  2. 数据结构简单,对数据操作也简单
  3. 采用的是单线程模式,避免了不必要的上下文切换消耗时间,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
  4. IO多路复用原则,非阻塞IO(一个线程去维护多个Redis操作)
  5. 基于跳跃表的数据结构(高搜索、高删除)

下边我们针对多路 I/O 复用模型进行简单的探讨:

多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。

  1. Select 是把所有的I/O 装载进来
  2. Channel 进行传输
  3. Buffer 缓冲区
  4. epoll 通过轮询方式读取

4、Redis 怎样存放对象

  • 以JSON格式存放

        优点:跨语言

        缺点:明文数据不安全

  • 以二进制的形式存放

        主要一些敏感数据

5、Redis分为多少个库,为什么?

总共分为16个库

因在微服务开发,是根据模块拆分,因Rediskey是不允许重复,为了保证每个服务可以存放相同的key

6、MySQL怎样 Redis 数据保持一性?

什么是数据⼀致性问题?

只要使用到缓存,无论是本地内存做缓存还是使⽤ redis 做缓存,那么就会存在数据同步的问题。

更新缓存方案

1、先更新缓存,再更新DB

这个方案我们⼀般不考虑。原因是更新缓存成功,更新数据库出现异常了,导致缓存数据与数据库数据完全不⼀致,而且很难察觉,因为缓存中的数据⼀直都存在。

2. 先更新DB,再更新缓存

这个⽅案也我们⼀般不考虑,原因跟第⼀个⼀样,数据库更新成功了,缓存更新失败,同样会出现数据不⼀致问题。

这种更新缓存的方式还有并发问题。

同时有请求A和请求B进⾏更新操作,那么会出现

(1)线程A更新了数据库

(2)线程B更新了数据库

(3)线程B更新了缓存

(4)线程A更新了缓存

这就出现请求A更新缓存应该⽐请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。

删除缓存方案

3、先删除缓存,后更新DB

该方案也会出问题,具体出现的原因如下。

此时来了两个请求,请求 A(更新操作)和请求 B(查询操作)

请求 A 会先删除 Redis 中的数据,然后去数据库进⾏更新操作;

此时请求 B 看到 Redis 中的数据时空的,会去数据库中查询该值,补录到 Redis 中;

但是此时请求 A 并没有更新成功,或者事务还未提交,请求B去数据库查询得到旧值;

那么这时候就会产生数据库和 Redis 数据不⼀致的问题。如何解决呢?其实最简单的解决办法就是延时双删的策略。就是

(1)先淘汰缓存

(2)再写数据库

(3)休眠1秒,再次淘汰缓存

这么做,可以将1秒内所造成的缓存脏数据,再次删除。

那么,这个1秒怎么确定的,具体该休眠多久呢?

针对上⾯的情形,自行评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百ms即可。这么做的⽬的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

4、先更新DB,后删除缓存

这种方式,被称为Cache Aside Pattern,读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放⼊缓存,同时返回响应。更新的时候,先更新数据库,然后再删除缓存。

这种情况不存在并发问题么?

依然存在。假设这会有两个请求,⼀个请求A做查询操作,⼀个请求B做更新操作,那么会有如下情形产生。

(1)缓存刚好失效

(2)请求A查询数据库,得⼀个旧值

(3)请求B将新值写⼊数据库

(4)请求B删除缓存

(5)请求A将查到的旧值写⼊缓存

然而,发⽣这种情况的概率⼜有多少呢?

发⽣上述情况有⼀个先天性条件,就是步骤(3)的写数据库操作⽐步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,⼤家想想,数据库的读操作的速度远快于写操作的(不然做读写分离⼲嘛,做读写分离的意义就是因为读操作⽐较快,耗资源少),因此步骤(3)耗时⽐步骤(2)更短,这⼀情形很难出现。⼀定要解决怎么办?如何解决上述并发问题?

首先,给缓存设有效时间是⼀种方案。

其次,采用异步延时删除策略。

但是,更新数据库成功了,但是在删除缓存的阶段出错了没有删除成功怎么办?这个问题,在删除缓存类的⽅案都是存在的,那么此时再读取缓存的时候每次都是错误的数据了。

此时解决⽅案有两个,⼀是就是利⽤消息队列进⾏删除的补偿。具体的业务逻辑⽤语⾔描述如下:

1、请求 A 先对数据库进⾏更新操作

2、在对 Redis 进⾏删除操作的时候发现报错,删除失败

3、此时将Redis 的 key 作为消息体发送到消息队列中

4、系统接收到消息队列发送的消息后

5、再次对 Redis 进⾏删除操作

但是这个⽅案会有⼀个缺点就是会对业务代码造成⼤量的侵⼊,深深的耦合在⼀起,所以这时会有⼀个优化的⽅案,我们知道对 Mysql 数据库更新操作后再binlog日志中我们都能够找到相应的操作,那么我们可以订阅Mysql数据库的binlog日志对缓存进⾏操作。

订阅binlog程序在mysql中有现成的中间件叫canal,阿⾥开源的,⼤家可以⾃⾏查阅官⽹,⽤以完成订阅binlog⽇志的功能。

6、Redis内存满了怎样解决,内存淘汰策略有哪些

  1. 增加服务的配置,这样指标不治本,不采用
  2. 采用内存淘汰策略

规则名称

规则说明

volatile-lru

使用LRU算法删除一个键(只对设置了生存时间的键),最少使用的

allkeys-lru

使用LRU算法删除一个键,最少使用的

volatile-random

随机删除一个键(只对设置了生存时间的键)

allkeys-random

随机删除一个键

volatile-ttl

删除生存时间最近的一个键

Noeviction

不删除键,只返回错误

推荐使用LRU算法,least RecentlyUsed最近最少使用算法。也就是说默认删除最近最少使用的键。

作为内存数据库,出于对性能和内存消耗的考虑,Redis 的淘汰算法实际实现上并非针对所有key,而是抽样一小部分并且从中选出被淘汰的 key。

使用 Redis 缓存数据时,为了提高缓存命中率,需要保证缓存数据都是热点数据。可以将内存最大使用量设置为热点数据占用的内存量,然后启用 allkeys-lru 淘汰策略,将最近最少使用的数据淘汰。

7、Redis持久化有哪些

Redis 的数据全部在内存⾥,如果突然宕机,数据就会全部丢失,因此必须有⼀种机制来保证 Redis 的数据不会因为故障⽽丢失,这种机制就是Redis的持久化机制。

Redis的持久化机制有两种

  1. 第⼀种是RDB快照
  2. 第⼆种是AOF日志

RDB持久化

RDB持久化是将某个时间点上Redis中的数据保存到⼀个RDB⽂件中,如下所示

该⽂件是⼀个经过压缩的⼆进制⽂件,通过该⽂件可以还原⽣成RDB⽂件时Redis中的数据,如下所

示:

Redis提供了2个命令来创建RDB⽂件,⼀个是SAVE,另⼀个是BGSAVE

因为BGSAVE命令可以在不阻塞服务器进程的情况下执⾏,所以推荐使⽤BGSAVE命令。

载入RDB文件

载⼊RDB⽂件的目的是为了在Redis服务器进程重新启动之后还原之前存储在Redis中的数据。

然后,Redis载⼊RDB⽂件并没有专⻔的命令,而是在Redis服务器启动时自动执⾏的。

⽽且,Redis服务器启动时是否会载⼊RDB⽂件还取决于服务器是否启⽤了AOF持久化功能,具体判断

逻辑为:

  1. 只有在AOF持久化功能处于关闭状态时,服务器才会使⽤RDB⽂件来还原数据。
  2. 如果服务器开启了AOF持久化功能,那么服务器会优先使⽤AOF⽂件来还原数据。

AOF持久化

AOF持久化是通过保存Redis服务器所执⾏的写命令来记录数据库数据的,如下图所示

默认情况下,AOF持久化功能是关闭的,如果想要打开,可以修改配置。

载入AOF文件

因为AOF⽂件包含了重建数据库所需的所有写命令,所以Redis服务器只要读⼊并重新执⾏⼀遍AOF文件⾥⾯保存的写命令,就可以还原Redis服务器关闭之前的数据。

Redis读取AOF⽂件并还原数据库的详细步骤如下:

  1. 创建⼀个不带⽹络连接的伪客户端

(因为Redis的命令只能在客户端上下⽂中执⾏,⽽载⼊AOF⽂件时所使⽤的命令直接来源于AOF⽂

件⽽不是⽹络连接,所以服务器使⽤了⼀个没有⽹络连接的伪客户端来执⾏AOF⽂件保存的写命

令。伪客户端执⾏命令的效果和带⽹络连接的客户端执⾏命令的效果完全⼀样)

  1. 从AOF⽂件中分析并读取出⼀条写命令。
  2. 使⽤伪客户端执⾏被读取出的写命令。
  3. ⼀直执⾏步骤2和步骤3,直到AOF⽂件中的所有写命令都被执⾏完毕。

以上步骤如下图所示:

8、RDB持久化、AOF持久化的区别

  • 实现方式

RDB持久化是通过将某个时间点Redis服务器存储的数据保存到RDB⽂件中来实现持久化的。

AOF持久化是通过将Redis服务器执⾏的所有写命令保存到AOF⽂件中来实现持久化的。

  • ⽂件体积

由上述实现⽅式可知,RDB持久化记录的是结果,AOF持久化记录的是过程,所以AOF持久化⽣成的AOF⽂件会有体积越来越⼤的问题,Redis提供了AOF重写功能来减小AOF⽂件体积。

  • 安全性

AOF持久化的安全性要⽐RDB持久化的安全性⾼,即如果发⽣机器故障,AOF持久化要比RDB持久化丢失的数据要少。

因为RDB持久化会丢失上次RDB持久化后写⼊的数据,⽽AOF持久化最多丢失1s之内写⼊的数据(使用默认everysec配置的话)。

  • 优先级

由于上述的安全性问题,如果Redis服务器开启了AOF持久化功能,Redis服务器在启动时会使⽤AOF文件来还原数据,如果Redis服务器没有开启AOF持久化功能,Redis服务器在启动时会使⽤RDB⽂件来还原数据,所以AOF⽂件的优先级⽐RDB⽂件的优先级高。

9、Redis 支持事务回滚吗

redis不支持

redis事物中,只有取消事务,因在redis中没有对当前数据进行行锁概念;

10、Redis开启事物,如何保证key的一致性

利用watch监控当前数据,先获取当前数据的version,当version版本一致可以修改,否则版本不一致不能修改。

11、Redis 集群方案有哪些

1、主从模式

可以使用主从复制方式(不推荐)

从节点订阅主节点数据

2、哨兵机制

Sentienl ,哨兵是 redis 集群中非常重要的一个组件,主要有以下功能:

  1. 集群监控二负责监控 redis master 和引 slave 进程是否正常工作;
  2. 消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员;
  3. 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上;
  4. 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址;

哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。

  • 故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举;
  • 即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的;
  • 哨兵通常需要 3 个实例;
  • 来保证自己的健壮性。 哨兵+ re dis 主从的部署架构,是不保证数据零丢失的,只能保证 redis 集群的高可用性;
  • 对于哨兵redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测训湘演练;

3、Cluster 模式

Redis cluster 是一种服务端 Sharding 技术, 3.0 版本开始正式提供。采用 slot (槽)的概念,一共分成 16384 个槽。 将各请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行。

方案说明

  • 通过哈希的方式,将数据分片,每个节点均分存储一定哈希槽(哈希值)区间的数据,每份数据分片会存储在多个互为主从的多节点上数据写入先写主节点,再同步到从节点(支持配置为阻塞同步)默认分配了 1 6384 个槽位 。
  • 同一分片多个节点间的数据不保持强一致性(支持配置为阻塞模式) ;
  • 读取数据时,当客户端操作的 key 没有分配在该节点上时, redis会返回转向指令,指向正确的节点 ;
  • 扩容时需要需要把旧节点的数据迁移一部分到新节点;

在 redis cluster 架构下,每个 redis 要放开两个端口号,比如一个是 6379 ,另外一个就是加 lw 的端口号,比如 16379 。

16379 端口号是用来进行节点间通信的,也就是 cluster bus 的通信,用来进行故障检测 、配置更新、故障转移授权。cluster bus 用了另外一种二进制的协议, gossip 协议,用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间。

优占

  • 无中心化价格,支持动态扩容,对业务透明;
  • 具备 Sentinel 的监控和自动 Failover (故障转移)能力;
  • 客户端不需要连接集群所有节点,连接集群中了到可一个可用节点即可;
  • 高性能,客户端直连 redis 服务,免去了 proxy 优哩的损耗

缺点

  • 运维也很复杂,数据迁移需要人工干预 ;
  • 只能使用 0 号数据库,不支持批量操作( pineline 管道操作)
  • 分布式逻辑和存储模块藕合等

Sharding 模式

Redis Sharding 是 Redis cluster 出来之前,业界普遍使用的多 Redis 实例集群方法。其主要思想是采用哈希算法将 Redis 数据的 key 进行散列,通过 hash 函数,特定的 key 会映射到特定的 Redis 节点上. Java redis 客户端驱动 Redis ,支持 Redis sharding 功能,即 Shardedjedis 以及结合缓存池的 ShardedjedisPool

优点

优势在于非常简单,服务端的 Redis 实例彼此独立,线性扩展,系统的灵活性很强缺点相互无关联,每个 Redis 实例像单服务器一样运行;

缺点

非常容易由于 sharding 处理放到客户端,规模进一步扩大时给运维带来挑战。

客户端 sharding 不支持动态增删节点.服务端 Redis 实例群拓扑结构有变化时,每个客户端都需要更新调整。连接不能共享,当应用规模增大时,资源浪费制约优化。

12、谈谈Redis缓存穿透理解,解决方案有哪些?

问题描述

key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户ID获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

解决方案

一个不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

(1)对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过1分钟
(2)设置可访问的名单(白名单):
使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
(3)采用布隆过滤器:(布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。)
将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。
(4)进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务

(5)参数值校验

原理

布隆过滤器,英文BloomFilter,是一个时间复杂度和空间复杂度很低,并用来检测元素是否存在的一种数据结构。它本质上是一个位图,把元素通过多次的hash计算出来的值当作索引,如果索引对应的位图的二进制位为0,说明该元素不存在,如果都为1,该元素可能存在。“可能存在"我们称为布隆过滤器的误判率,这是由于hash冲突导致的。从这可以看出来,布隆过滤器适用与对大数据集进行去重、检验是否存在等场景,但由于它的误判率,并不适用"零错误的场景”。下面我们来看看它的原理。


 

上图就是布隆过滤器的原理,中间就是bitmap,每一位都是二进制位。然后上面的5和7就是已经存在的元素,他们分别经过3次hash运算,将bitmap对应的位改为了1。下面的10是一个不存在的元素,但是由于hash冲突,导致它计算出来的3个位都为1,这就会让布隆过滤器发生误判。由此可以得知,误判率上升有以下几种因素:1.bitmap太小,导致频繁的hash冲突;2.本身存在的元素过多,导致bitmap大多数位都为1;3.hash函数散列较差。并且可以发现,布隆过滤器是不支持删除元素的,如果将5删除,那么下标为3的位就会变为0,这样也会把7进行"误删"。


 

13、谈谈Redis缓存击穿理解,解决方案有哪些?

问题描述

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决问题
(1)预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
(2)实时调整:现场监控哪些数据热门,实时调整key的过期时长
(3)使用锁:
(1)就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db。
(2)先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX)去set一个mutex key
(3)当操作返回成功时,再进行load db的操作,并回设缓存,最后删除mutex key;
(4)当操作返回失败,证明有线程在load db,当前线程睡眠一段时间再重试整个get缓存的方法。

14、谈谈Redis缓存雪崩理解,解决方案有哪些?

问题描述

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案

缓存失效时的雪崩效应对底层系统的冲击非常可怕!
解决方案:
(1)构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)
(2)使用锁或队列:
用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况
(3)设置过期标志更新缓存:
记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。
(4)将缓存失效时间分散开:
比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

15、谈谈Redis缺点有哪些?

  • 可以从数据的一致性
  • 雪崩
  • 穿透
  • 击穿
  • 这些问题回答

16、谈谈Redis并发问题?

这里的并发指的是多个redisclient同时set key引起的并发问题。其实redis自身就是单线程操作,多个client并发操作,按照先到先执行的原则,先到的先执行,其余的阻塞。当然,另外的解决方案是把redisset操作放在队列中使其串行化,必须的一个一个执行,具体的代码就不上了,当然加锁也是可以的,至于为什么不用redis中的事务,留给各位看官自己思考探究。