Redis高频面试集合44问

  • Redis概述

    • 什么是Redis?

    • Redis的优缺点?

    • Redis为什么常常用做缓存?相比于guava有什么优势?

    • Redis和Memcached的区别与共同点?

    • Redis是单线程还是多线程?Redis为什么这么快?

    • Redis6.0之后为什么引入了多线程?

    • Redis的数据类型有哪些?

    • Redis的数据结构有哪些?

    • Redis的应用场景有哪些?

    • Redis是单线程的,如何提高CPU的利用率?

  • 过期键的删除策略

    • 键的过期删除策略

    • Redis的内存淘汰机制是什么样的?

  • Redis的持久化

    • 什么是Redis的持久化?

    • Redis常见的持久化机制有哪些?有什么有优缺点?

  • Redis的事务

    • 什么是Redis的事务

    • Redis事务的相关命令

    • Redis事务执行的三个阶段

    • Redis事务的特性

    • Redis事务为什么不支持回滚?

  • Redis的集群、主从、哨兵

    • Redis集群的实现方案有哪些?

    • Redis主从架构中数据丢失吗

    • 如何解决主从架构数据丢失问题?

    • Redis集群的主从复制过程是什么样的?

    • Redis是如何保证主从服务器一致处于连接状态以及命令是否丢失?

    • 因为网络原因在主从复制过程中停止复制会怎么样?

    • 了解Redis哈希槽吗?

    • Redi集群最大的节点个数是多少?为什么?

    • Redis集群是如何选择数据库的?

    • Redis高可用方案如何实现?

  • Redis的分区

    • Redis的分区作用是什么?

    • Redis分区有哪些实现方案?

    • Redis分区的缺点?

  • Redis的分布式问题

    • 什么是分布式锁?

    • 分布式锁具有哪些特性?

    • 分布式锁的实现方法?

    • Redis如何实现分布式锁?

    • Redis并发竞争key问题应该如何解决?

    • 什么是RedLock

  • Redis的缓存问题

    • 说下什么是缓存雪崩、缓存穿透、缓存击穿,及它们的解决方案

    • 如何保证缓存与数据库双写时的数据一致性?

  • Redis其他高频面试题

    • 一个字符串类型的值能存储最大容量是多少?

    • Redis如何实现大量数据插入?

    • 如何通过Redis实现异步队列?

    • 如何通过Redis实现延时队列?

    • Redis回收使用什么算法?

    • Redis 里面有1亿个 key,其中有 10 个 key 是包含 java,如何将它们全部找出来?

    • 生产环境中的Redis是如何部署的

Redis概述

什么是Redis?

Redis是一个高性能的非关系型的键值对数据库,使用C编写实现的。与传统的数据库不同的是Redis是存在内存中的,所以读写速度非常快,每秒可以处理超过10万次的读写操作,这也是Redis常常被用作缓存的原因。

Redis的优缺点?

优点:

  • 读写性能好,读的速度可达110000次/s,写的速度可达81000次/s。

  • 支持数据持久化,有AOF和RDB两中持久化方式

  • 数据结构丰富,支持String、List、Set、Hash等结构

  • 支持事务,Redis所有的操作都是原子性的,并且还支持几个操作合并后的原子性执行,原子性指操作要么成功执行,要么失败不执行,不会执行一部分。

  • 支持主从复制,主机可以自动将数据同步到从机,进行读写分离。

缺点:

  • 因为Redis是将数据存到内存中的,所以会受到内存大小的限制,不能用作海量数据的读写

  • Redis不具备自动容错和恢复功能,主机或从机宕机会导致前端部分读写请求失败,需要重启机器或者手动切换前端的IP才能切换

Redis为什么常常用做缓存?相比于guava有什么优势?

缓存的定义是访问速度比一般随机存取存储器快的一种高速存储器,而因为Redis是基于内存提供了高性能的数据存取功能,其比较显著的优势就是非常地快。

缓存可以分为本地缓存或者分布式缓存,比较常用的guava缓存就是一种本地缓存,其主要特点是轻量并且快速,生命周期随着JVM的销毁而结束,缺点是在多实例的情况下,每个实例都要自己保存一份缓存,这样会导致缓存的一致性出现问题。

Redis则是分布式缓存,在多实例情况下,每个实例都共享一份缓存数据,缓存具备一致性。缺点是要保持Redis的高可用整体架构会比较复杂。

Redis和Memcached的区别与共同点?

相同点:

  • 两者的读写性能都比较高

  • 都是基于内存的数据库,通常被当作缓存使用

  • 都有过期策略

  • 都是基于C语言实现

不同点:

不同点 Redis Memcached
是否支持复制 支持主从复制 不支持复制
key长度 长度最大为 2GB 长度最多为 250 个字节
数据类型 不仅支持key-value类型的数据,还支持hash、list、set、zset等数据等数据类型的数据 仅支持key-value类型的数据
数据持久化 支持数据持久化,可以将数据保存到磁盘 不支持数据持久化
网络IO模型 单线程的多路 IO 复用模型 多线程的非阻塞IO模式
集群 原生支持cluster 模式集群 无原生

Redis是单线程还是多线程?Redis为什么这么快?

Redis6.0之前是单线程的,为什么Redis6.0之前采用单线程而不采用多线程呢?

简单来说,就是Redis官方认为没必要,单线程的Redis的瓶颈通常在CPU的IO,而在使用Redis时几乎不存在CPU成为瓶颈的情况。使用Redis主要的瓶颈在内存和网络,并且使用单线程也存在一些优点,比如系统的复杂度较低,可为维护性较高,避免了并发读写所带来的一系列问题。

Redis为什么这么快主要有以下几个原因:

  • 运行在内存中

  • 数据结构简单

  • 使用多路IO复用技术

  • 单线程实现,单线程避免了线程切换、锁等造成的性能开销。

Redis6.0之后为什么引入了多线程?

前面说了那么多Redis使用单线程的原因,但从Redis6.0后开始支持多线程了,简直打脸有点快。那么为什么较新的Redis版本又开始支持多线程了呢?

前面也说了Redis的瓶颈在内存和网络,Redis6.0引入多线程主要是为了解决网路IO读写这个瓶颈,执行命令还是单线程执行的,所以也不存在线程安全问题。

Redis6.0默认是否开启了多线程呢?

默认是没有开启的,如需开启,需要修改配置文件redis.conf:io-threads-do-reads  no,no改为yes

Redis的数据类型有哪些?

Redis的常见的数据类型有String、Hash、Set、List、ZSet。还有三种不那么常见的数据类型:Bitmap、HyperLogLog、Geospatial

数据类型 可以存储的值 可进行的操作 应用场景
STRING 字符串、整数、浮点数 对整数或浮点数可以进行自增、自减操作
对字符串操作
键值对缓存及常规计数: 微博数, 粉丝数
LIST 列表(内部使用双向列表实现) 向列表两端添加元素,或者获得列表的某一个片段 存储文章ID列表、存储评论列表等
SET 无序集合(内部使用值为空的散列表) 增加/删除元素、获取集合中元素、取交集并集等等 共同好友、共同关注等
ZSET 有序集合(内部使用散列表和跳表) 添加、获取、删除元素
根据分值范围或者成员来获取元素
计算一个键的排名
去重、获取排名前几的用户
HASH 包含键值对的无序散列表 添加、获取、移除单个键值对
获取所有键值对
检查某个键是否存在
常用于存储对象

Bitmap:位图,是一个以位为单位的数组,数组中只能存储1或0,数组的下标在Bitmap中叫做偏移量。Bitmap实现统计功能,更省空间。面试中常问的布隆过滤器就有用到这种数据结构,布隆过滤器可以判断出哪些数据一定不在数据库中,所以常被用来解决Redis缓存穿透问题。

Hyperloglog:HyperLogLog 是一种用于统计基数的数据集合类型,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。HyperLogLog 的优点是,在输入元素的数量或者体积非常大时,计算基数所需的空间总是固定 的、并且是很小的。缺点是 HyperLogLog 的统计规则是基于概率完成的,所以它给出的统计结果是有一定误差的,标准误算率是 0.81%。常见的应用场景:统计网站的UV

Geospatial:主要用于存储地理位置信息,常用于定位附近的人,打车距离的计算等。

Redis的数据结构有哪些?

很多人都会把数据结构和数据类型混为一谈,包括很多面试官问的时候也没有刻意区分这两个。Redis的数据结构比较多,篇幅有限,这里只重点介绍面试常问的跳跃表。

Redis的数据结构有简单动态字符串链表字典跳跃表整数集合压缩列表等。

简单动态字符串:大家都知道,Redis的底层是用C语言编写,但Redis并没有直接使用C语言传统的字符串表示,而是构建了一种名为简单动态字符串的抽象类型。

链表:链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活地调整链表的长度。链表是列表的底层实现之一

字典:字典,又称为符号表(symbol table)、关联数组(associativearray)或映射(map),是一种用于保存键值对(key-value pair)的抽象数据结构。字典在Redis中的应用相当广泛,比如Redis的数据库就是使用字典来作为底层实现的,对数据库的增、删、查、改操作也是构建在对字典的操作之上的。

整数集合: 整数集合(intset)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现。

压缩列表(ziplist):压缩列表是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型(sequential)数据结构。

对象:可能看到这里,很多人在想Redis的数据结构和数据类型的区别,其实上面介绍的是Redis的底层数据结构,但Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象有序集合对象这五种类型的对象,每种对象都用到了至少一种我们前面所介绍的数据结构,是不是这就和前面对上了。

看到这里很多人会好奇,为什么不直接使用这些底层数据结构,而是要创建对象系统。对象系统主要有以下优点:

  • 通过这五种不同类型的对象,Redis可以在执行命令之前,根据对象的类型来判断一个对象是否可以执行给定的命令。

  • 我们可以针对不同的使用场景,为对象设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率。

  • 实现了基于引用计数技术的内存回收机制,当程序不再使用某个对象的时候,这个对象所占用的内存就会被自动释放,了解Java虚拟机的垃圾回收机制看到这里是不是很熟悉。

  • edis还通过引用计数技术实现了对象共享机制,这一机制可以在适当的条件下,通过让多个数据库键共享同一个对象来节约内存。

对象这部分占了比较大的篇幅,其实面试中问的也不多,但为了更方便理解,介绍地多些。顺便看下这些底层数据结构和对象系统的对应关系。

最后介绍下面试中常问的跳跃表。

跳跃表(skiplist):跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。跳跃表支持平均O(logN)、最坏O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点。跳跃表作是序集合键的底层实现之一

和链表、字典等数据结构被广泛地应用在Redis内部不同,Redis只在两个地方用到了跳跃表,一个是实现有序集合键,另一个是在集群节点中用作内部数据结构,除此之外,跳跃表在Redis里面没有其他用途。

跳跃表本质上采用的是一种空间换时间的策略,是一种可以可以进行二分查找有序链表,跳表在原有的有序链表上增加了多级索引,通过索引来实现快速查询。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。

这是一个原始的有序列表,时间复杂度为O(n)。

为了提高查找效率,可以对链表建立一级索引,如下图,在之前找到11这个元素需要遍历6个节点,现在需要5个。链表越长,效率提升越明显。

为了继续提高查找效率可以继续增加索引

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值