Redis常见面试题与答案

Redis的基本数据类型

Redis有哪些常用的数据类型?

  • String:字符串(最常用的缓存)
  • Hash:哈希(保存对象)
  • List:有序列表(消息队列)
  • Set:无序集合(抽奖、点赞、求交集、并集、差集)
  • Zset:有序集合(热门排行榜)
  • BitMap:位图(统计用户在线状态、活跃用户数、签到等)
  • HyperLogLog:基数统计(统计网站UV)
  • Geospatial:地理空间(地理位置相关查询与计算)

String的底层结构是什么?

  • 是一种叫做sds的数据结构(simple dynamic string 简单动态字符串),本质上其实还是字符串数组。
  • sds又可以细分为:sdshdr5(2^5 byte)、sdshdr8(2^8 byte)、sdshdr16(2^16 byte)、sdshdr32(2^32 byte)、sdshdr64(2^64 byte),用于存储不同长度的字符串。

为什么Redis要用sds实现字符串?

  • c语言本身没有字符串类型,只有字符串数组,定义字符串数组时需要先分配足够内存,否则会发生内存溢出,而sds无需担心内存溢出问题,它支持动态扩容;
  • 字符串数组获取长度必须遍历数组,时间复杂度为O(n),而sds中定义了len属性,可以直接获取长度,时间复杂度为O(1);
  • 字符串数组在进行修改时会做内存重新分配,而sds可以通过空间预分配和惰性空间释放来防止多次重新分配内存;
    • 空间预分配:对字符串进行空间扩展的时候,扩展的内存比实际需要的多,这样可以减少连续执行字符串增长操作所需的内存重分配次数。
    • 惰性空间释放:对字符串进行缩短操作时,程序不立即使用内存重新分配来回收缩短后多余的字节,而是使用 free 属性将这些字节的数量记录下来,等待后续使用。
  • c语言字符串通过第一个’\0’来标记字符串结束,因此不能保存图片、音频等二进制文件,而sds是通过len属性来确定长度,因此可以保存二进制文件。

String有几种编码类型?

  • int:存储8个字节的长整型(最大值 2^63 - 1),超出范围会升级为embstr;
  • embstr:存储小于44字节的字符串,embstr中的redisObject与sds存储连续,创建时只需分配一次内存空间,存取效率高,且embstr不可修改,修改后会升级为raw;
  • raw:存储大于44字节的字符串,raw中的redisObject与sds分开存储,创建时只需分配两次内存空间,适合存储较大或频繁修改的字符串。

Hash的底层实现是什么?

  • ziplist与hashtable

什么是ziplist(压缩列表)?

  • ziplist是一个经过特殊编码,由连续内存块组成的双向链表。为了达到压缩内存,节省空间的目的,它不存储上一个和下一个节点的指针,而是存储上一个节点的长度和当前节点的长度,因此可以通过计算长度来实现元素遍历。这样做虽然牺牲了一定的查询效率,但也节省了空间,(以时间换空间)因此适合元素不多的场景。
  • 在hash类型中,同时满足以下两个条件时才使用ziplist:
    • hash对象保存的键值数 < 512;
    • 所有键和值的字符串长度都 < 64 byte。

ziplist与数组的区别?

  • ziplist和数组都是连续内存,需要预分配,但是数组元素长度相同,ziplist的元素长度可以不同;
  • 数组的元素保存了索引下标,而ziplist的元素只存储了上一节点和当前节点的长度;
  • 数组通过下标来遍历,ziplist通过元素记录的长度遍历;
  • 数组的查询时间复杂度O(1),ziplist的查询时间复杂度O(n)。

hashtable的特点是什么?

  • hashtable与java中的hashtable类似,也是一个数组 + 链表的结构,同样采用拉链法解决hash冲突。
  • 在redis的hashtable的底层数据结构中有两个ht:
    • ht[0],是存放数据的table,作为非扩容时容器;
    • ht[1],只有正在进行扩容时才会使用,它也是存放数据的table,长度为ht[0]的两倍。
  • 当总元素个数与hash槽的比值大于dict_force_resize_ratio(1)时,会触发扩容,即触发ht[0] 到 ht[1] 的rehash过程。

hashtable的扩容原理

  • hashtable扩容采用渐进式rehash,避免数据量大时,一次性rehash产生阻塞;
  • 在rehash期间,会维护一个rehashIndex,用来表示rehash进度,初始值为0,代表rehash进行中;
  • 每次迁移完一个槽位,rehashIndex + 1;
  • 迁移过程中如果有请求进来,将请求路由到的index与rehashIndex比较,如果大于rehashIndex,代表这部分数据还没有迁移完成,访问ht[0],否则访问ht[1];
  • 全部迁移完成后rehashIndex更新为-1。

List的底层实现是什么?

  • List的底层实现是quicklist,quicklist是一个与linkedlist类似的双向链表,每个quicklist的节点又包含多个ziplist,这样就结合了两者的优点,既保证一定的查询效率,又节省了一定内存空间。

Set的底层实现是什么?

  • set的底层实现为intset或hashtable,如果都是整型数字,则用intset存储,否则用hashtable。

Zset的底层实现是什么?

  • 默认使用ziplist存储,如果元素数量大于128或任意元素长度大于等于64byte,则使用skiplist + dict 存储。

什么是skiplist(跳跃表)?

  • 每相邻的两个节点都增加了一个指针,让指针指向下下个节点,这样所有新增加的指针连成了一个新的链表,但包含的节点数只有原来的一半。这样当我们查找数据时,先沿着新链表查找,类似于二分查找的思想。
  • 例如查找23的位置:

img

  1. 23首先和7比较,再和19比较,直到发现比23大的值;
  2. 当处于19节点时,发现26比23大,则与19的下一节点22比较;
  3. 22比23要小,下一节点26比23要大,说明要查找的23元素并不在链表内。
  • 因为level的值是随机的,skiplist可能不只是跳一层,也可能跳两层、三层等,如下图:

img

  • skiplist查找的时间复杂度为O(Log n);
  • 可以在O(1)的时间复杂度下获得skiplist的头节点、尾节点、长度和高度。

持久化

Redis有哪几种持久化方式?

  • Redis支持两种方式的持久化,一种是RDB方式、另一种是AOF(append-only-file)方式。前者会根据指定的规则“定时”将内存中的数据存储在硬盘上,而后者在每次执行命令后将命令本身记录下来。两种持久化方式可以单独使用其中一种,也可以将这两种方式结合使用。

AOF文件过大怎么办?

  • Redis提供了AOF文件的重写机制,优化掉冗余的命令;
  • 重写过程在AOF文件大小达到指定阈值时触发,由子进程执行;
  • 子进程并不是基于原有AOF文件进行重新,而是全量遍历当前内存中的数据,写入新的AOF文件,在此期间新的写请求命令会先写到缓冲区aof_rewrite_buf中,最后合并到一起。

内存回收策略

LRU和LFU的区别?

  • LRU是最近最少使用页面置换算法(Least Recently Used),也就是首先淘汰最长时间未被使用的页面(按使用时间排序);
  • LFU是最近最不常用页面置换算法(Least Frequently Used),也就是淘汰一定时期内被访问次数最少的页(按使用次数排序)。

Redis有哪些种内存回收策略?

  1. noeviction:默认的策略,如果内存使用达到阈值,所有引起申请内存的命令会报错;
  2. allkeys-random:添加数据时,如果内存使用达到阈值,就会扫描所有的key,随机淘汰一些key;
  3. volatile-random:添加数据时,如果内存使用达到阈值,扫描那些设置里过期时间的key,随机淘汰一些key;
  4. volatile-ttl:添加数据时,如果内存使用达到阈值,扫描那些设置里过期时间的key,淘汰一些即将过期的key(按失效时间排序);
  5. allkeys-lru:添加数据时,如果内存使用达到阈值,就会扫描所有的key,淘汰一些最近未使用的key(按最近使用时间排序);
  6. volatile-lru:添加数据时,如果内存使用达到阈值,扫描那些设置里过期时间的key,淘汰一些最近未使用的key(按最近使用时间排序);
  7. allkeys-lfu:添加数据时,如果内存使用达到阈值,就会扫描所有的key,淘汰一些最近最少使用的key(按最近使用次数排序);
  8. volatile-lfu:添加数据时,如果内存使用达到阈值,就会淘汰一些设置了过期时间的,并且最近最少使用的key(按最近使用次数排序)。

高可用

Redis有哪些高可用方案?

  • 主从、哨兵、集群。

哨兵节点的最少数量是多少?

  • 三个,一主两从。

哨兵Leader选举的原理是什么?

  • 哨兵的Leader选举是基于共识算法Raft;
  • Raft协议动画演示
    • Raft
  • 参与选举的三种角色:
    • Leader:负责事务请求的处理与数据同步;
    • Follower:可以处理非事务请求,以及Leader选举;
    • Candidate:候选者,在Leader选举期间,Follower会成为候选者;
  • 集群总节点数需要满足 2n + 1(n >= 1);
  • Leader选举的触发时机:
    • 集群初始化;
    • Leader宕机;
  • 成为Leader的条件:
    • 每个Candidate会在一个随机时间后进行广播发起投票,默认会投自己;
    • 其它节点接收到投票请求后会判断该节点的term(任期)是否优于自己,如果满足则会同意;
    • 当超过半数节点投票同意后该Candidate会成为新的Leader,同时term + 1;
    • 如果平票,则在一个超时时间后重新开启投票流程;
  • Leader的数据同步:
    • Leader 基于2pc实现数据同步,超过半数的Follower 响应成功后数据才算成功写入;
  • 如何处理脑裂或网络分区;
    • 以节点多的分区数据为准。

哨兵模式与集群模式的区别?

  • 哨兵模式是主从模式的升级版,主节点和从节点都保存了全量数据,而集群模式是对整个数据集进行了横向的分片,每个分片节点只保存一部分数据集;
  • 集群模式相比哨兵模式而言部署和运维成本更高,适合数据量更大的场景。

Redis集群方案不可用的情况有哪些?

  • 集群master半数以上宕机,无论是否有从库存活(无法进行选举);
  • 集群某一节点的主从全部宕机,集群进入fail状态。也可以理解成进群的slot映射[0-16383]不完整时进入fail状态。

缓存的经典七大问题

缓存失效

  • 在过期时间基础上加上随机时间,避免同时失效。

缓存穿透

  • 对于某些DB不存在的值,可以缓存一个特殊值,避免频繁访问DB;
  • 构建BloomFilter记录全量数据,这样可以过滤掉不存在的key。

缓存雪崩

  • 对DB的访问增加读写开关,当发现 DB 请求变慢、阻塞,慢请求超过阈值时,就会关闭读开关,部分或所有读 DB 的请求进行 failfast 立即返回,待 DB 恢复后再打开读开关。
  • 对缓存增加多个副本,缓存异常或请求 miss 后,再读取其他缓存副本,而且多个缓存副本尽量部署在不同机架,从而确保在任何情况下,缓存系统都会正常对外提供服务。
  • 对缓存体系进行实时监控,当请求访问的慢速比超过阈值时,及时报警,通过机器替换、服务替换进行及时恢复;也可以通过各种自动故障转移策略,自动关闭异常接口、停止边缘服务、停止部分非核心功能措施,确保在极端场景下,核心功能的正常运行。

缓存一致性问题

  • cache 更新失败后,可以进行重试,如果重试失败,则将失败的 key 写入队列机服务,待缓存访问恢复后,将这些 key 从缓存删除。这些 key 在再次被查询时,重新从 DB 加载,从而保证数据的一致性。
  • 缓存时间适当调短,让缓存数据及早过期后,然后从 DB 重新加载,确保数据的最终一致性。
  • 缓存的更新方案:缓存的三种读写方式_学无止境-CSDN博客_只读缓存 读写缓存

数据并发竞争

  • 使用全局锁。即当缓存请求 miss 后,先尝试加全局锁,只有加全局锁成功的线程,才可以到 DB 去加载数据。其他进程/线程在读取缓存数据 miss 时,如果发现这个 key 有全局锁,就进行等待,待之前的线程将数据从 DB 回种到缓存后,再从缓存获取。
  • 对缓存数据保持多个备份,即便其中一个备份中的数据过期或被剔除了,还可以访问其他备份,从而减少数据并发竞争的情况。

Hot key

  • 对于特殊的业务场景,提前分析收集热门的key;
  • 如果热门的key的名称为hotkey,可以将它分散为 hotkey#1、hotkey#2、hotkey#3,……hotkey#n,这 n 个 key 分散存在多个缓存节点,然后 client 端请求时,随机访问其中某个后缀的 hotkey,这样就可以把热 key 的请求打散,避免一个缓存节点过载。

Big key

  • 对于value超过阈值的key进行序列化压缩等。

分布式锁

Redisson如何实现可重入锁?

  • Redisson是通过lua脚本实现的lock和unlock,底层使用的数据结构是hash;
  • hash的key为锁实际的key,hash中会有一个entry,entry的key为传入的唯一threadId,value为重入次数,重入一次会+1,释放一次会-1;
  • 每次加锁都会更新失效时间,同时还有定时任务进行失效时间的延长(看门狗);
  • lock和unlock是基于Redis的Pub Sub模式实现锁的等待和唤醒的,lock过程如果无法获得锁,当前线程执行subscribe(threadId),订阅该threadId的锁事件,当对应threadId的锁完全释放后,会执行publish发布锁释放事件,这样订阅该事件的所有线程便可以重新竞争锁。

Redis线程模型

Redis 采用单线程为什么还这么快?

  • 首先,Redis 的大部分操作都在内存中完成,并且采用了高效的数据结构,比如哈希表和跳表;
  • 其次,因为是单线程模型避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题;
  • 另外,Redis并不是完全的单线程应用,除了核心的读写操作由专门的线程完成之外,还有很多辅助线程在后台执行工作,例如:
    • 主从同步;
    • 持久化;
    • 大key删除:直接通过del删除大key会导致Redis阻塞,例如数量较大的map、list或set等。Redis4.0引入了unlink命令,先标记再异步删除,避免阻塞;
    • 除了unlink之外,flushall、flushdb也都是异步操作;
  • 最后, Redis 采用了 I/O 多路复用机制,在Linux环境的epoll模式下,可以高效地进行网络通信,因为基于非阻塞的 I/O 模型,就意味着 I/O 的读写流程不再阻塞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556757.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言利用文件体写在桌面上,在C语言中怎样新建一个文件夹?

满意答案JacinthLancet推荐于 2017.10.12采纳率&#xff1a;56% 等级&#xff1a;12已帮助&#xff1a;35899人函数名: mkdir功 能: 建立一个目录(文件夹)用 法: int mkdir(char *pathname);程序例: (在win-tc和Dev-c下运行通过)#include #include #include int main(void){…

MySQL常见面试题与答案

存储引擎 InnoDB的主要特点是什么&#xff1f; MySQL5.5版本之后的默认存储引擎&#xff1b;支持事务&#xff1b;支持行级锁&#xff1b;支持MVCC&#xff1b;支持聚集索引方式存储数据。 InnoDB与MyISAM的区别&#xff1f; 存储引擎MyISAMInnoDB存储结构MyISAM在磁盘上存…

Spring 异常处理三种方式

Spring 异常处理三种方式 异常处理方式一. ExceptionHandler异常处理方式二. 实现HandlerExceptionResolver接口异常处理方式三. ControllerAdviceExceptionHandler三种方式比较说明(强烈推荐各位看一下&#xff0c;我觉得自己总结的比较多&#xff0c;嘿嘿&#xff0c;不对之…

Netty常见面试题 与 答案

Netty基础知识 什么是Netty&#xff1f; Netty 是一款用于高效开发网络应用的 NIO 网络框架&#xff0c;它大大简化了网络应用的开发过程&#xff1b; 封装了JDK底层的NIO模型&#xff0c;提供高度可用的API&#xff0c;用于快速开发高性能服务端和客户端&#xff1b;精心设计…

CAS单点登录详细流程

一、CAS简介和整体流程 CAS 是 Yale 大学发起的一个开源项目&#xff0c;旨在为 Web 应用系统提供一种可靠的单点登录方法&#xff0c;CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。CAS 具有以下特点&#xff1a; 【1】开源的企业级单点登录解决方案。 【2】CAS Server 为…

android 图片自动拉伸,解决关于ImageView自适应的问题(拉伸变形,图片模糊)

今天接手一个项目发现有个地方的图片显示非常小&#xff0c;而且还不够清晰&#xff0c;也没办法自适应屏幕的显示&#xff0c;非常的影响美观&#xff0c;于是 就像这优化一下。先看看优化前的效果和优化后的效果。修复后修复前布局文件修复前&#xff1a;修复前布局文件修复后…

redisTemplate.opsForValue()中方法讲解

查看源码可以看到redisTemplate.opsForValue()中的方法都定义在ValueOperations<K, V> 中&#xff0c;该接口中一共有17个方法&#xff1a; public interface ValueOperations<K, V> {void set(K key, V value);void set(K key, V value, long timeout, TimeUnit …

spring boot配置dubbo(properties)

spring boot与dubbo配置(properties) dubbo和zookeeper配合使用&#xff0c;具体的它们之间的配置这里不说了。 一、spring boot与dubbo配置有两种方式&#xff1a; 1&#xff09;spring boot在自己的配置文件application.properties 配置dubbo。&#xff08;本篇主要说这个&…

spring boot配置dubbo(XML)

上一篇写的是spring boot在自己的properties配置文件中简单配置dubbo的步骤&#xff0c;那种配置有很多的功能&#xff08;比如超时时间、是否检查&#xff09;等等&#xff0c;配置起来也挺麻烦的&#xff0c;而我们也习惯传统的那种XML形式的dubbo配置。 这一篇写的是spring…

spring boot配置dubbo注意事项

spring boot配置dubbo注意事项 通过前两篇文章&#xff0c;知道了spring boot配置dubbo有两种方式。具体请回顾前两篇文章吧。 现在主要是说下spring boot在自己的application.properties 文件里配置dubbo内容&#xff0c;这种方式遇到的问题。 问题一&#xff1a;dubbo接口…

spring boot配置mybatis和事务管理

spring boot配置mybatis和事务管理 一、spring boot与mybatis的配置 1.首先,spring boot 配置mybatis需要的全部依赖如下&#xff1a; <!-- Spring Boot 启动父依赖 --> <parent><groupId>org.springframework.boot</groupId><artifactId>spr…

android hud sdk,Android HUD SDK | 百度地图API SDK

简介为了给用户提供更安全优质的服务&#xff0c;LBS开放平台针对Android平台的SDK产品引入Key认证机制&#xff0c;用户在使用之前需要先申请配置Key&#xff0c;并在程序相应位置填写您的Key。Key机制&#xff1a;每个Key仅且唯一对于1个应用验证有效&#xff0c;即对该Key配…

spring boot配置druid(德鲁伊)

spring boot配置druid(德鲁伊) 关于druid的介绍请看 阿里巴巴温少访谈 1.引入相关依赖&#xff0c;全部依赖是上一篇spring bootmybatis依赖的基础上&#xff0c;再加上下边的依赖&#xff0c;如下&#xff1a; <!-- Druid数据库连接池组件 --> <dependency><…

spring boot----简单入门

Spring Boot其实就是spring,为了简便spring框架的搭建&#xff0c;快速开发项目而推出的另一种方式。使用spring boot&#xff0c;搭建框架将变得特别快。可以有更多的时间在代码性能上优化了。 一、Spring Boot个人感觉的优点: ​ 1&#xff09;搭建一个简单运行的框架很快&…

android js 代码混淆工具,好用的JS(Javascript)混淆加密工具-HDS JSObfuscator 2.14版

好用的JS(Javascript)混淆加密工具-HDS JSObfuscator 2.14版书法字体2017.06.23css压缩分享一款好用的JS混淆加密工具:HDS JSObfuscator 2.14版&#xff0c;HDS JSObfuscator兼顾了JS压缩、JS混淆和JS加密三大功能。js加密工具的主要作用就是为了保护Javascript代码&#xff0c…

Maven 建立父子项目和跨项目调用内容的步骤

使用Maven管理项目&#xff0c;同时我们是做微服务&#xff0c;所以对于微服务项目来说&#xff0c;使用Maven建立起一个父子项目这种关系&#xff0c;很方便管理&#xff08;只是个人感觉&#xff09; 设计层面 &#xff08;1&#xff09;服务端和客户端肯定是分开写的&…

android支付宝运动修改器,一键修改支付宝运动步数-修改支付宝运动步数工具下载不要root手机版-西西软件下载...

修改支付宝运动步数工具是一款支付宝运动步数修改工具和教程,QQ微信也可以修改&#xff0c;最近在支付宝中推出了各种运动活动&#xff0c;很多朋友表示想要直接刷步数&#xff0c;不想去亲自运动来增加步数。那么下面手机乐园水银师小编就为大家介绍了支付宝快速刷步数的方法&…

spring boot配置tomcat部署

spring boot本身默认为jar包运行&#xff0c;可以改为war包&#xff0c;然后运行在tomcat里 具体修改的步骤如下&#xff1a; 1.在pom.xml文件里添加需要的依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>s…

android同步aar到jcenter,android上传aar到jcenter

一、jcenter配置1、jcenter官网注册账号官网地址&#xff1a;https://bintray.com注册页面&#xff1a;2、注册成功记录API Key 鼠标放在账户名上&#xff0c;点击Edit Profile,选择API Key,在这里是需要输入登录密码的&#xff0c;然后就可以看到你的key3、创建仓库点击此处进…

spring boot配置logback日志

spring boot配置logback日志 在上一篇spring boot入门里提过&#xff0c;Spring Boot默认的日志打印是logback,所以配置logback日志会很简单&#xff0c;但是也有注意的地方。 本次配置日志的需求 日志需要控制台打印和文件打印两种。其中文件打印按照日志级别分别保存到各自…