面试题:Redis 吐血整理"/>
【测开求职】面试题:Redis 吐血整理
部分大厂除了要求测开工程师掌握MySQL之外,对Redis也有要求,本篇文章整理了Redis相关的面试题,之前完全没有接触过Redis的朋友们也无需担心,可以看第二个部分的"入门笔记",两小时可以速通。亲测第一部分的面试题应对各个大厂的测开工程师毫无压力👉
目录
- 一、面试题
- Redis是什么
- Redis的优缺点
- Redis的应用场景
- Redis为什么这么快
- 为什么不直接用Redis做数据库
- Redis的常见数据结构
- Redis的持久化机制
- Redis内存用完了会怎么办
- Redis事务
- Redis存在线程安全问题吗
- Redis事务支持隔离性吗
- Redis事务支持原子性吗
- Redis支持回滚吗
- 缓存雪崩
- 缓存击穿
- 缓存穿透
- 入门笔记
- 初始Redis
- Redis常见命令
- Redis 的数据结构
- 通用命令
- String 类型
- redis 的 key 的格式
- Hash类型
- List 类型
- Set类型
- SortedSet 类型
- redis的java客户端
一、面试题
以下面试题参考:
.html
Redis是什么
- Redis是一个由c语言编写的,高性能非关系型数据库
- 与传统的数据库不同的是,Redis的数据库是存在内存中的,读写速度非常快,广泛应用于缓存方向
- Redis可以将数据写入磁盘中,保证数据的安全不丢失
- Redis的操作是原子性的
Redis的优缺点
优点:
- 基于内存:读写速度快
- 支持多种数据结构:String、Hash、List、Set、ZSet
- 支持持久化:支持RDB和AOF两种持久化机制,持久化功能可以有效地避免数据丢失问题
- 支持事务:Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行
- 支持主从复制:主节点会自动将数据同步到从节点,可以进行读写分离。
- 单线程:Redis命令的处理是单线程的。Redis6.0引入了多线程,需要注意的是,多线程用于处理网络数据的读写和协议解析,Redis命令执行还是单线程的
缺点:
- 对结构化查询的支持比较差
- 容量受到物理内存的限制,不适合用作海量数据的高性能读写,使用的场景主要局限在较小数据量的操作
- 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂
Redis的应用场景
- 缓存热点数据:缓解数据库压力
- 计数器:利用 Redis 原子性的自增操作,可以实现计数器的功能,比如统计用户点赞数、用户访问数等。
- 分布式锁:在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
- 简单的消息队列:可以使用Redis自身的发布/订阅模式或者List来实现简单的消息队列,实现异步操作。
- 限速器:可用于限制某个用户访问某个接口的频率,比如秒杀场景用于防止用户快速点击带来不必要的压力。
- 好友关系:利用集合的一些命令,比如交集、并集、差集等,实现共同好友、共同爱好之类的功能。
Redis为什么这么快
- 基于内存:Redis是使用内存存储,没有磁盘IO上的开销。数据存在内存中,读写速度快
- IO多路复用模型:Redis 采用 IO 多路复用技术。Redis 使用单线程来轮询描述符,将数据库的操作都转换成了事件,不在网络I/O上浪费过多的时间
- 高效的数据结构:Redis 每种数据类型底层都做了优化,目的就是为了追求更快的速度
IO多路复用:一种同步IO模型,实现一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;没有文件句柄就绪时会阻塞应用程序,交出cpu。多路是指网络连接,复用指的是同一个线程
为什么不直接用Redis做数据库
虽然Redis非常快,但它还有一些限制,不能完全替代主数据库。
- 事务处理:只支持简单的事务处理,对复杂的事务处理无能为力,比如跨多个键的事务处理
- 数据持久化:Redis是内存数据库,数据存储在内存中,如果服务器崩溃或断电,数据可能丢失。虽然Redis提供了数据持久化机制,但有一些限制。
- 数据结构:只支持一些简单的数据结构,比如字符串、列表、哈希表等。如果需要处理复杂的数据结构,比如关系型数据库中的表,那么Redis可能不是一个好的选择
- 数据安全:Redis没有提供像主数据库那样的安全机制,比如用户认证、访问控制等等。
所以,使用Redis作为缓存是一种很好的方式,可以提高应用程序的性能,并减少数据库的负载。
Redis的常见数据结构
基本数据类型
- String:是Redis中最简单的存储类型,有三类(普通字符串、整数型、浮点型),都是以字节数组形式存储,只不过编码方式不同,最大空间不能超过512m
- Hash:类似于java中的hashMap,存储键值对
- List:和java中的linkedlist类似,常用来存储有序可重复数据,比如说朋友圈的点赞列表,评论列表
- Set:和java中hashset类似,常用来存储无序不可重复数据。提供了交集、并集等方法,对于实现共同好友、共同关注等功能特别方便。
- SortedSet:有序Set,内部维护了一个score参数来实现。适用于排行榜和带权重的消息队列等场景。
特殊数据类型:
- Bitmap:位图,可以认为是一个以位为单位数组,数组中的每个单元只能存0或者1,数组的下标在 Bitmap 中叫做偏移量。Bitmap的长度与集合中元素个数无关,而是与基数的上限有关。
- Hyperlog:用来做基数统计的算法,其优点是,在输入元素的数量或者体积非常大时,计算基数所需的空间总是固定的、并且是很小的。典型的使用场景是统计独立访客。
- Geo:主要用于存储地理位置信息,并对存储的信息进行操作,适用场景如定位、附近的人等
这里的基数指的是什么啊:集合中不重复的元素
Redis的持久化机制
持久化:把内存数据写到磁盘,防止服务器宕机导致数据库丢失。有两种数据持久化机制:
- RDB:默认方式
- 根据指定的规则定时将内存中的数据存储在磁盘上
- 优点:速度快,使用单独的进程来进行持久化,主进程不会进行任何IO操作,保证了Redis的高性能
- 缺点:无法做到实时持久化;存在老版本的Redis无法兼容新版本的RDB格式的问题
- AOF:主流方式
- 以独立日志的方式记录每次写命令
- 优点:解决了数据持久化的实时性,默认情况下系统每30秒会执行一次同步操作
- 缺点:速度慢
两种持久化机制应该如何选择
- 如果数据不敏感,且可以从其他地方重新生成,可以关闭持久化
- 如果数据比较重要,且能够承受几分钟的数据丢失,比如缓存等,只需要使用RDB即可
- 如果是用做内存数据,要使用Redis的持久化,建议是RDB和AOF都开启
当RDB与AOF两种方式都开启时,Redis会优先使用AOF恢复数据,因为AOF保存的文件比RDB文件更完整。
Redis内存用完了会怎么办
- Redis的写命令会返回错误信息(但是读命令是可以正常读的)
- 可以配置内存淘汰机制,当Redis内存达到上线时会重刷掉旧的内容
Redis事务
Redis事务的原理:
- 将一个事务范围内的若干命令发送给Redis,然后再让Redis依次执行这些命令
Redis事务的生命周期:
- 使用MULTI开启一个事务
- 在开启事务的时候,每次操作的命令将会被插入到一个队列中,此时这些命令不会被真的执行
- 使用EXEC命令提交事务
Redis存在线程安全问题吗
从服务端层面来看:
- 不需要任何同步机制,不会存在线程安全
- Redis6.0增加的多线程只是用来处理网络IO事件的,对于指令的执行过程,仍然是主线程处理,所以不会存在安全问题
从客户端层面来看:
- 有多个客户端同时执行多个指令的时候,无法保证原子性
- 解决办法:对客户端访问的资源加锁、尽可能使用Redis中的原子指令、通过Lua来实现多个指令的操作
Redis事务支持隔离性吗
Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。
Redis事务支持原子性吗
Redis单条命令是原子性执行的,但事务不保证原子性。
原子性:一个事务中的多条命令,要么全部执行,要么全部不执行
Redis支持回滚吗
不支持回滚,事务中任意命令执行失败,其余命令仍然会被执行
缓存雪崩
缓存雪崩:
- 大量数据在同一时间过期(失效)
- 如果刚好此时有大量的请求,Redis无法命中就是能访问数据库
- 数据库压力骤增,严重的会造成数据库宕机,这就是缓存雪崩的问题
解决办法: - 将缓存的失效时间打散:在原有的失效时间基础上增加一个随机数,防止大量数据在同一时间内失效
- 设置缓存不过期:使用后台服务来更新缓存数据,不设置过期
缓存击穿
缓存击穿:
- 某个热点数据过期,此时大量的请求访问该热点数据
- Redis无法命中就会直接访问数据路,数据库很容易被高并发的请求冲垮,这就是缓存击穿问题
解决办法: - 互斥锁:保证同一时间只有一个业务线程请求缓存
- 不给热点数据设置过期时间:可以通过程序在热点数据要过期时进行更新
缓存穿透
缓存穿透:
- 当发生缓存雪崩和缓存击穿时,数据库中还是保存了要访问的数据的
- 但是缓存穿透是指,用户访问的数据既不在缓存中,也不在数据库中
- 当有大量这样的请求来时,数据库压力剧增,这就是缓存穿透问题
缓存穿透发生的原因 - 业务误操作:缓存和数据库中的数据都被误删了
- 黑客恶意攻击:故意访问大量不存在的业务数据
解决办法:
- 限制非法请求
- 设置空值或者默认值:在缓存数据中设置一些空值或者默认值,这样就不会访问数据库
- 使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在
入门笔记
=3&spm_id_from=pageDriver&vd_source=4af69ca6d4c9233482138fb1c303b63b
初始Redis
- sql是关系型数据库,nosql是非关系型数据库,两者的区别是:
-
Redis是键值数据库,NoSql数据库
-
Remote dictionary sever 远程词典服务器,是一个基于内存的键值型NOSQL数据库
-
特征
- 键值型: value支持多种数据结构,功能丰富
- 单线程,每个命令具备原子性
- 低延迟,速度快(这是因为他基于内存🍓、IO多路复用、良好的编码)
- 支持数据的持久化(内存虽然快,但是一旦断电数据就消失了,所以需要数据持久化):定期将数据从内存持久化到硬盘
- 支持主从集群(从节点可以备份主节点的数据,主从可以读写分离,提高效率)、分片集群(把数据拆分成多份)
- 支持多语言客户端
-
安装
-
原作者根本就没有编写windows版本的,只要linux版本
Redis常见命令
Redis 的数据结构
最主要的是这八个,还有其他的
- 官方文档中的命令介绍:/
- redis在线练习:/
通用命令
- KEYS pattern : 查看复合模板的所有key,因为模板的查询是模糊的,效率比较低,所以不建议在生产环境中使用
> keys *
1) "name"
2) "age"
- DEL key : 指定删除一个key
> del age
(integer) 1
> keys *
1) "name"
- EXISTS key:判断一个key是否存在
> exists age
(integer) 0
- EXPIRE:给key设置一个有效期,有效期到了之后删除该key
- TTL:查看一个key的有效时间。-1 代表永久有效、-2代表已失效
> expire age 10
(integer) 1
> ttl age
(integer) 6
> ttl age
(integer) 2
String 类型
字符串类型,是Redis中最简单的存储类型,有以下三类,都是以字节数组形式存储,只不过编码方式不同,最大空间不能超过512m
- string:普通字符串
- int:整数类型,可以自增自减
- float:浮点类型,可以自增自减
String 类型的常见命令: - SET
- GET
- MEST
- MGET
- INCR:让整型key自增1
- INCREBY
- INCRBYFLOAT
- SETNX
- SETEX
> incrbyfloat score 0.5
1.6
> incrbyfloat score 0.5
2.1
redis 的 key 的格式
redis中没有table的概念,如何区分不同类型的key呢?比如说要存储用户、商品信息到redis,有一个用户的id是1,商品的id也恰好是1
- Redis中的key允许有多个单词形成层级关系,多个单词之间用:隔开
- 项目名:类型:id
- heima:user:1
- heima:product:1
Hash类型
value是一个无序字典,类似于java中的hashMap
> hgetall heima:user:1
1) "name"
2) "gaoyi"
3) "age"
4) "25"
List 类型
和java中的linkedlist类似,常用来存储有序数据,比如说朋友圈的点赞列表,评论列表,有以下特征:
- 有序
- 可重复
- 插入删除快
- 查询速度一般
如何用list模拟一个栈:lpush lpop
如何用list模拟一个队列 lpush rpop
如何利用list模拟一个阻塞队列 blpop brpop
Set类型
和java中hashset类似,可以看做是一个value为null的hashmap,有以下特征
- 无序
- 不可重复
- 查找快
- 支持交集、并集、差集等功能
> sadd friends gao gai ta
(integer) 3
> smembers friends
1) "gai"
2) "ta"
3) "gao"
> scard friends
3
> sismember friends gao
(integer) 1
> sadd girlfriends lisa lusy gao
(integer) 3
> sinter friends girlfriends
1) "gao"
> sdiff friends girlfriends
1) "gai"
2) "ta"
> sunion friends girlfriends
1) "gai"
2) "gao"
3) "ta"
4) "lisa"
5) "lusy"
SortedSet 类型
- 可排序的set集合,和java中的treeset有些类似,但是底层数据结构却差别很大。
- SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序
- 经常用来实现排行榜这样的功能
- 底层实现是一个跳表(skiplist)加hash表,有以下特征:
- 可排序
- 不重复
- 查询速度快
redis的java客户端
- jedis:学习成本低,但是线程不安全,需要使用搭配线程池来使用
- lettuce
- redisson
更多推荐
【测开求职】面试题:Redis 吐血整理
发布评论