Redis面试题

本文详细介绍了Redis的基础数据结构如字符串、哈希、列表、集合和有序集合,以及常用的命令操作。此外,还涵盖了Java操作Redis的方式,Redis中的分布式锁解决方案,集群与缓存一致性问题,以及持久化和布隆过滤器的原理。
摘要由CSDN通过智能技术生成

1、基础

1.1 Redis的数据结构

redis 中有多种数据类型,每种数据类型的底层都由一种或多种数据结构来支持。正是因为有了这些数据结构,Redis 在存储与读取上的速度才不受阻碍。
在这里插入图片描述
解释说明
字符串(string):普通字符串,常用
哈希(hash):适合存储对象
列表(list):按照插入顺序排序,可以有重复元素
集合(set):无序集合,没有重复元素
有序集合(sorted set / zset):集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素

1.2 Redis常用命令

字符串string操作命令

  • SET key value 设置指定key的值
  • GET key 获取指定key的值
  • SETEX key seconds value 设置指定key的值,并将 key 的过期时间设为 seconds 秒
  • SETNX key value 只有在 key 不存在时设置 key 的值
  • incr命令 自增
  • decr命令 自减
  • incrby key step 自增步数
  • decrby key step 自减步数
  • SETBIT key offset value 设置Key,对应的Value第N个二进制位,标记0或1
  • GETBIT key offset 获取Key,对应的Value第N个二进制位的状态
  • BITCOUNT key [start end] 统计Key,对应的Value对应的第N个字节的二进制数量,1为有效

哈希Hash操作命令
Redis中的Hash类型可以看成具有String Key和String Value的map容器,hash特别适合用于存储对象数据。所以该类型非常适合于存储值对象的信息。如Username、Password和Age等。如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash可以存储4294967295(2^32-1, 40多亿)个键值对。

  • HSET key field value 将哈希表 key 中的字段 field 的值设为 value
  • HGET key field 获取存储在哈希表中指定字段的值
  • HDEL key field 删除存储在哈希表中的指定字段
  • HKEYS key 获取哈希表中所有字段
  • HVALS key 获取哈希表中所有值
  • HGETALL key 获取在哈希表中指定 key 的所有字段和值

列表list操作命令
在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是:4294967295(2^32-1, 40多亿)

  • LPUSH key value1 [value2] 将一个或多个值插入到列表头部
  • LPOP key 移除并获取列表第一个元素
  • RPUSH key value1 [value2] 将一个或多个值插入到列表尾部
  • RPOP key 移除并获取列表最后一个元素
  • LRANGE key start stop 获取列表指定范围内的元素
  • LLEN key 获取列表长度

集合set操作命令
在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。需要说明的是,这些操作的时间复杂度为O(1),即常量时间内完成次操作。Set可包含的最大元素数量是4294967295(2^32-1),和List类型不同的是,Set集合中不允许出现重复的元素。

  • SADD key member1 [member2] 向集合添加一个或多个成员
  • SMEMBERS key 返回集合中的所有成员
  • SCARD key 获取集合的成员数
  • SINTER key1 [key2] 返回给定所有集合的交集
  • SUNION key1 [key2] 返回所有给定集合的并集
  • SDIFF key1 [key2] 返回给定所有集合的差集
  • SREM key member1 [member2] 移除集合中一个或多个成员
  • SISMEMBER key member 判断集合中是否有某个成员
  • SRANDMEMBER key [count] 返回集合中任意一个或多成员

有序集合sorted set操作命令
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 集合中最大的成员数为4294967295(2^32-1)。

  • ZADD key score1 member1 [score2 member2] 向集合添加一个或多个成员或者更新已存在成员的 分数
  • ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合中指定区间内的成员
  • ZREVRANGE key start stop [WITHSCORES] 通过索引区间反向返回有序集合中指定区间内的成员
  • ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment
  • ZREM key member [member …] 移除有序集合中的一个或多个成员

通用命令
Redis中的通用命令,主要是针对key进行操作的相关命令:

  • KEYS pattern 查找所有符合给定模式( pattern)的 key
  • EXISTS key 检查给定 key 是否存在
  • TYPE key 返回 key 所储存的值的类型
  • TTL key 返回给定 key 的剩余生存时间(TTL, time to live),以秒为单位
  • DEL key 该命令用于在 key 存在是删除 key

1.3 在java中操作Redis

Redis 的 Java 客户端很多,官方推荐:

  • Jedis
    Jedis 是 Redis 官方首选的 Java 客户端开发包,jedis就是集成了redis的一些命令操作,提供了连接池管理。
  • Redisson (分布式场景)
    Redisson适用于分布式执行服务和分布式调度任务服务里的远程任务。常用于基于Redis实现一个分布式锁的场景。Redisson底层采用的是Netty 框架。

在Spring Boot项目中提供了对应的Starter,即 spring-boot-starter-data-redis。Spring-data-redis是spring大家族的一部分,提供了在spring应用中通过简单的配置访问redis服务,对redis底层开发包(Jedis,JRedis, and RJC)进行了高度封装。

Spring Data Redis
Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
操作字符串类型数据
redisTemplate.opsForValue()
操作哈希类型数据
HashOperations hashOperations = redisTemplate.opsForHash();
操作列表类型数据
ListOperations listOperations = redisTemplate.opsForList();
操作集合类型数据
SetOperations setOperations = redisTemplate.opsForSet();
操作有序集合类型数据
ZSetOperations zSetOperations = redisTemplate.opsForZSet();

2、redis的概念

redis是一个高性能的key-value数据库,他是完全开源免费的,而且redis是一个NOSQL类型数据库,是为了解决高并发、高扩展,大数据存储等一系列的问题而产生的数据库解决方案,是一个非关系型数据库。但是,他还是不能代替关系型数据库,只能作为特定环境下的扩充。

3、常用数据类型以及应用场景

3.1 String字符串

应用场景
①单值缓存
在这里插入图片描述
②对象缓存
在这里插入图片描述
③计数器
文章阅读数、点赞数、评论量
④分布式锁
定时任务防止同一时刻重复执行,可以在业务执行代码前使用分布式锁控制

3.2 Hash(散列Hash)

应用场景
①缓存对象信息(帖子标题、摘要、作者信息)
②记录帖子的点赞数、评论数、点击数
③电商购物车

3.3 list列表

应用场景
①文章列表
②微博微信公众号消息
③最新消息排行榜(如朋友圈的时间线)
④消息队列:生产者可以使用push操作将任务存在list中,消费者使用pop操作将任务取出

3.4 无序集合set

应用场景
①抽奖
②微博点赞、收藏、标签
③利用不可重复性,实现共同好友、访问某地址ip去重,当前在线用户人数去重等
在这里插入图片描述

3.5 有序集合sorted set

应用场景
①微博的热搜榜
②刷礼物实时排行榜
③博客社区本周热议
④带权重的消息队列

4、redis缓存哪些数据

五种数据类型

5、分布式锁

概念
分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。
分布式锁应该具备哪些条件
1、在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
2、高可用的获取锁和释放锁
3、高性能的获取锁和释放锁
4、具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
5、具备锁失效机制,即自动解锁,防止死锁
6、具备非阻塞锁特性,即没有获取到锁直接返回获取锁失败
实现方案
1、setnx+expire
setnx:只有key不存在时设置key的值
expire:先设置key,然后为给定 key 设置过期时间
问题:
在执行完setnx后服务器重启了,就会导致没有设置过期时间,导致死锁。
setnx和expire不是原子操作,可以使用Lua脚本保证原子性。
2、set的扩展命令(set ex px nx)
除了使用 Lua 脚本,保证 SETNX + EXPIRE 两条指令的原子性,我们还可以使用 Redis 的 SET 指令扩展参数(SET key value [EX seconds] [PX milliseconds] [NX|XX]),它也是原子性的

SET key value[EX seconds][PX milliseconds][NX|XX]

NX :表示key不存在的时候,才能set成功,也即保证只有第一个客户端请求才能获得锁,而其他客户端请求只能等其释放锁,才能获取。
EX seconds :设定key的过期时间,时间单位是秒。
PX milliseconds: 设定key的过期时间,单位为毫秒
XX: 仅当key存在时设置值
问题:
1、锁过期释放了,业务还没执行完
2、锁被别的线程误删
解决:
1、使用redisson框架
2、加唯一随机值校验,校验成功再删除

3、redisson框架
在这里插入图片描述
只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了锁过期释放,业务没执行完问题。

4、多机实现的分布式锁Redlock+Redisson

6、集群

为什么需要Redis集群
1、写并发
Redis单实例读写分离可以解决读操作的负载均衡,但对于写操作,仍然是全部落在了master节点上面,在海量数据高并发场景,一个节点写数据容易出现瓶颈,造成master节点的压力上升。
2、海量数据存储的压力
单实例Redis本质上只有一台Master作为存储,如果面对海量数据的存储,一台Redis的服务器就应付不过来了,而且数据量太大意味着持久化成本高,严重时可能会阻塞服务器,造成服务请求成功率下降,降低服务的稳定性。

什么是Redis集群
1.Redis3.0加入了Redis的集群模式,实现了数据的分布式存储,对数据进行分片,将不同的数据存储在不同的master节点上面,从而解决了海量数据的存储问题。
2. Redis集群采用去中心化的思想,没有中心节点的说法,对于客户端来说,整个集群可以看成一个整体,可以连接任意一个节点进行操作,就像操作单一Redis实例一样,不需要任何代理中间件,当客户端操作的key没有分配到该node上时,Redis会返回转向指令,指向正确的node。
3.Redis也内置了高可用机制,支持N个master节点,每个master节点都可以挂载多个slave节点,当master节点挂掉时,集群会提升它的某个slave节点作为新的master节点。
集群搭建的4种方式
1、主从模式
原理图:
在这里插入图片描述
介绍
1、redis单节点虽然有通过RDB和AOF持久化机制能将数据持久化到硬盘上,但数据是存储在一台服务器上的,如果服务器出现硬盘故障等问题,会导致数据不可用,而且读写无法分离,读写都在同一台服务器上,请求量大时会出现I/O瓶颈。为了避免单点故障 和 读写不分离,Redis 提供了复制(replication)功能实现master数据库中的数据更新后,会自动将更新的数据同步到其他slave数据库上。
2、普通的主从模式,当主数据库崩溃时,需要手动切换从数据库成为主数据库:
在从数据库中使用SLAVE NO ONE命令将从数据库提升成主数据继续服务。
启动之前崩溃的主数据库,然后使用SLAVEOF命令将其设置成新的主数据库的从数据库,即可同步数据。

2、哨兵模式
原理图
在这里插入图片描述
哨兵模式的作用
1、监控所有服务器是否正常运行:通过发送命令返回监控服务器的运行状态,处理监控主服务器、从服务器外,哨兵之间也相互监控。
2、故障切换:当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换master。同时那台有问题的旧主也会变为新主的从,也就是说当旧的主即使恢复时,并不会恢复原来的主身份,而是作为新主的一个从。
哨兵实现原理
1、哨兵在启动进程时,会读取配置文件的内容,通过如下的配置找出需要监控的主数据库
2、sentinel monitor master-name ip port quorum
#master-name是主数据库的名字
#ip和port 是当前主数据库地址和端口号
#quorum表示在执行故障切换操作前,需要多少哨兵节点同意。
3、这里之所以只需要连接主节点,是因为通过主节点的info命令,获取从节点信息,从而和从节点也建立连接,同时也能通过主节点的info信息知道新增从节点的信息。
4、一个哨兵节点可以监控多个主节点,但是并不提倡这么做,因为当哨兵节点崩溃时,同时有多个集群切换会发生故障。哨兵启动后,会与主数据库建立两条连接。
- 订阅主数据库_sentinel_:hello频道以获取同样监控该数据库的哨兵节点信息
- 定期向主数据库发送info命令,获取主数据库本身的信息。
主观下线和客观下线
1、哨兵节点发送ping命令时,当超过一定时间(down-after-millisecond)后,如果节点未回复,则哨兵认为主观下线。主观下线表示当前哨兵认为该节点已经下面,如果该节点为主数据库,哨兵会进一步判断是够需要对其进行故障切换,这时候就要发送命令(SENTINEL is-master-down-by-addr)询问其他哨兵节点是否认为该主节点是主观下线,当达到指定数量(quorum)时,哨兵就会认为是客观下线。
2、当主节点客观下线时就需要进行主从切换,主从切换的步骤为:
- 选出领头哨兵。
- 领头哨兵所有的slave选出优先级最高的从数据库。优先级可以通过slave-priority选项设置。
- 如果优先级相同,则从复制的命令偏移量越大(即复制同步数据越多,数据越新),越优先。
- 如果以上条件都一样,则选择run ID较小的从数据库。
- 选出一个从数据库后,哨兵发送slave no one命令升级为主数据库,并发送slaveof命令将其他从节点的主数据库设置为新的主数据库。
哨兵模式的优缺点
1、优点:
哨兵模式是基于主从模式的,解决可主从模式中master故障不可以自动切换故障的问题。
2、缺点:
- 是一种中心化的集群实现方案:始终只有一个Redis主机来接收和处理写请求,写操作受单机瓶颈影响。
- 集群里所有节点保存的都是全量数据,浪费内存空间,没有真正实现分布式存储。数据量过大时,主从同步严重影响master的性能。
- Redis主机宕机后,哨兵模式正在投票选举的情况之外,因为投票选举结束之前,谁也不知道主机和从机是谁,此时Redis也会开启保护机制,禁止写操作,直到选举出了新的Redis主机。

3、Redis Cluster
原理图
在这里插入图片描述
介绍
1、Redis Cluster是一种服务器Sharding技术(分片和路由都是在服务端实现),采用多主多从,每一个分区都是由一个Redis主机和多个从机组成,片区和片区之间是相互平行的。Redis Cluster集群采用了P2P的模式,完全去中心化。
2、redis cluster主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster,数据量不是很大时,使用sentinel就够了。redis cluster的性能和高可用性均优于哨兵模式。
3、Redis Cluster采用虚拟哈希槽分区而非一致性hash算法,预先分配一些卡槽,所有的键根据哈希函数映射到这些槽内,每一个分区内的master节点负责维护一部分槽以及槽所映射的键值数据。

特点
1、集群完全去中心化,采用多主多从;所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
2、客户端与 Redis 节点直连,不需要中间代理层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
3、每一个分区都是由一个Redis主机和多个从机组成,分片和分片之间是相互平行的。
4、每一个master节点负责维护一部分槽,以及槽所映射的键值数据;集群中每个节点都有全量的槽信息,通过槽每个node都知道具体数据存储到哪个node上

7、穿透

概念
查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库
解决方案
1、缓存空数据,查询返回的数据为空,把这个空结果进行缓存
优点:简单
缺点:消耗内存,可能会发生不一致的问题
2、布隆过滤器(缓存预热的时候,预热布隆过滤器)
缓存预热就是将热点数据缓存到redis中,布隆过滤器主要就是为了拦截不存在的数据。
优点:内存占用较少,没有多余key
缺点:实现复杂,存在误判

8、击穿

对于设置了过期时间的key,缓存在某个时间点过期的时候,恰好这个时间点,对这个key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并返回到缓存,这个时候大量的并发会把数据库压垮。
解决方案
1、互斥锁
当缓存失效时,不立即去加载数据库,先用redis的setnx设置一个互斥锁,当操作成功返回时再进行加载数据库的操作,并设会缓存,否则重试get缓存的方法。
强一致性
2、逻辑过期

  • 在设置key的时候,设置一个过期时间字段一块存入缓存,不给当前key设置过期时间
  • 当查询的时候,从redis中取出数据后判断时间是否过期
  • 如果过期则开通例外一个线程进行数据同步,当前线程正常返回数据,这个数据不是最新的数据
    高可用

9、雪崩

是指在·同一时间·段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力

解决方案
1、给不同的key的ttl添加随机值
2、集群
3、给缓存业务添加降级限流策略
4、给业务添加多级缓存

和击穿的区别是
击穿时一个key,雪崩是多个key

10、持久化

  • RDB
    RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件称为RDB文件,默认是保存在当前运行目录。
  • AOF
    AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。

11、布隆过滤器

原理图
在这里插入图片描述
布隆过滤器本质上是一个二进制数组,元素的值不是1就是0. 当我们存一个商品id为10的商品,假设我们经过三次哈希,存的数组下标为1,3,7,就将这三个下标的元素改为1.这样每次访问redis之前,先访问布隆过滤器。查询id为10的商品的时候,经过布隆过滤器的哈希算法,获取到该商品对应的下标是1,3,7。那么,如果这三个数组的下标对应的元素都为1 则表示存在该商品,放行这次请求。如果有一个为0,则不存在该商品。

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值