首页 > 数据库 >Redis面试题

Redis面试题

时间:2024-07-09 23:29:23浏览次数:22  
标签:面试题 缓存 Redis redis 数据 节点 分布式

Redis面试题

一、Redis缓存

1、缓存预热、缓存穿透、缓存雪崩、缓存击穿

  • 缓存预热: 系统上线后,提前将相关数据加载到缓存中,避免用户先查库,然后再查缓存。

  • 缓存穿透: 指缓存和数据库中都没有的数据,导致所有的请求都落在数据库上,造成数据库短时间内承受大量请求而崩掉。
    解决方案:
    1)缓存空对象:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。
    2)布隆过滤器:是指在客户端和redis之间又加了一层布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储查询压力,但不一定是准确的,返回存在却不一定是存在。
    Redisson实现的布隆过滤器:底层主要是先去初始化一个比较大的数组,里面存放的是二进制0或1,在一开始全是0,当存储一个key时,经过3次hash计算,模于数组长度找到数据的下标后把数组中原来的0改为1,这样就能通过三个数组的位置标明一个key的存在。
    缺点:存在一定的误判率,一般可以设置这个误判率,5%以内一般都能接受。

  • 缓存雪崩: 指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
    解决方案:
    1)给不同key的TTL(过期时间)添加随机值,将失效时间分散开来。
    2)缓存预热:指系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题

  • 缓存击穿: 缓存击穿问题也叫热点key问题,就是被一个高并发访问并且缓存重建业务较复杂的key突然失效了,无数请求访问会在瞬间给数据库带来巨大的冲击。
    解决方案:
    1)互斥锁:用锁的方式只让一个线程来重建缓存数据,其他线程等待缓存构建。适用于强一致性,性能没那么高
    2)逻辑过期:设置热点key永不过期,一个线程来获取互斥锁开启写入线程,其他线程获取互斥锁失败,则获取缓存中的旧数据。适用于不严格要求数据一致性。

2、redis作为缓存,MySQL的数据如何与缓存进行同步(保证双写一致性)

  • 采用redisson实现的读写锁来保证强一致性:
    在读的时候添加 共享锁,可以保证读读不互斥,读写互斥。更新数据时,使用 排他锁,读写、读读都互斥,这样就能保证在写数据的同时是不会让其他线程读数据的,避免了脏数据。需注意要将读方法和写方法上的锁使用同一把锁。
    排他锁底层使用的是setnx,保证了同时只能有一个线程操作锁住的方法。
    延迟双删: 如果是写操作,先把缓存中的数据删除,然后更新数据库,最后再延时删除缓存中的数据,其中这个延时多久不太好确定,在延时的过程中可能出现脏数据,并不能保证强一致性,所以没有采用它。

  • 数据同步允许有一定的延迟:
    采用阿里的canal组件实现数据同步,不需要更改业务代码,部署一个canal服务。canal服务把自己伪装成mysql的一个从节点,当mysql数据更新以后,canal会读取binlog数据,然后在通过canal的客户端获取到数据,更新缓存即可。

3、redis作为缓存,如何持久化数据?

  • redis中提供了两种数据持久化的方式:RDB、AOF。
  • RDB是一个快照文件,他是把redis内存存储的数据写到磁盘上,当redis实例宕机恢复数据的时候,方便从RDB的快照文件中恢复数据。
  • AOF的含义是追加文件,当redis操作写命令的时候,都会存储这个文件中,当redis实例宕机恢复数据的时候,会从这个文件中再次执行一遍命令来恢复数据。
  • 两种方式中,RDB恢复的速度比较快。因为是二进制文件,在保存的时候体积也比较小,所以恢复的比较快,但是它有可能会丢数据,通常项目中也会使用AOF来恢复数据,虽然AOF恢复数据比较慢,但是数据安全要高些,在AOF文件中可以设置刷盘策略,如可设置每秒批量写入一次命令。
    在这里插入图片描述在这里插入图片描述

4、redis的key过期后会立即删除吗?(redis的数据过期策略)

  • Redis对数据设置数据的有效时间,数据过期以后,就需要将数据从内存中删除掉,可以按照不同的规则进行删除,这种删除规则就被称之为数据的过期删除策略。
    在这里插入图片描述

5、假如缓存过多,内存有限,被占满了怎么办?(redis的数据淘汰策略)

  • 当Redis中的内存不够用时,此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉,这种数据的删除规则被称之为内存的淘汰策略。
  • 在redis这提供了8种不同的策略,默认使用的是noeviction,不删除任何数据,内存不足直接报错。
  • 数据库有1000万数据,Redis只能缓存20w数据,如何保证Redis中的数据都是热点数据?
    使用allkeys-lru策略,挑选最近最少使用的数据淘汰,留下的都是经常访问的热的数据。
  • Redis的内存用完了会发生什么,主要看数据淘汰策略是什么,如默认使用的是noeviction,会直接报错。
    在这里插入图片描述

6、

二、Redis分布式锁

1、Redis分布式锁如何使用?(使用场景)

  • 举例:
    抢券功能:如果是单体项目,直接用synchronized(this)同步代码块就能解决并发问题。但如果是服务集群部署,将同一份代码部署在多台机器中,则不能再使用同步锁,此时则可以使用redis的分布式锁来解决。

  • 分布式锁所要解决的问题的本质是:能够对分布在多台机器中的线程对共享资源的互斥访问。

  • Redis实现分布式锁主要利用redis的 setnx 命令。setnx是SET if not exists(如果不存在,则SET)的简写。

// 添加锁 NX是互斥,EX是设置超时时间
// 注意不能将该条命令分成两条命令实现,因其两条命令不能保证原子性
SET lock value NX EX 10
// 释放锁 删除
DEL key

2、Redis分布式锁如何合理的控制锁的有效时长?

  • 在获取Redis分布式锁锁成功后执行业务,如果执行业务的时间超时过期 或 在执行业务的途中服务宕机了,此时Redis会自动释放锁,从而可能造成数据的不一致性。

  • 解决方法:
    1)根据业务执行时间预估,但一般都可能无法预期,所以不建议使用
    2)给锁续期,再创建一个新的线程来监控业务执行了多久,如果监控到业务执行的时间比较长,就增加线程持有锁的时长,redisson实现的分布式锁已经实现了该功能。

3、Redisson实现的分布式锁执行流程(实现原理)

  • Redisson实现的分布式锁也是基于setnx 命令实现的,只是对其做了很多增强和优化。

  • 一个线程获取到分布式锁之后,就可以操作redis数据库了,不同的是Redisson会另开一个线程,类似看门狗一样,用来监控这个持有锁的线程,一般是每隔(releaseTime过期时间 / 3)的时间给持有锁的线程做一次续期。假设过期时间为30秒,则每10秒的时间都会给持有锁的线程续期,每次续期时间都为30秒。

  • 当业务完成以后,手动释放锁,同时需要通知这个监控线程锁已被删除了,则不需要再做监听了。

  • 若线程一开始获取分布式锁失败了,并不会直接中断失败,而是运用了while循环来不断的尝试获取锁,设置了一定的循环次数去获取锁,如果超过了这个次数就直接失败了。(重试机制)

  • 所有的加锁、释放锁、设置过期时间等操作都是基于lua脚本完成的。lua脚本的作用就是能保证基于redis实现的多行代码中的原子性。
    在这里插入图片描述

public void redisLock() throws InterruptedException {
	// 获取锁(重入锁),设置执行锁的名称
	RLock lock = redissonClient.getLock("lock1");
	// 尝试获取锁,参数分别是:分布式锁的最大等待时间 、 锁自动释放时间 、 时间单位
	// 第二个参数可不填,如果传入了第二个参数,代表可自己能确定业务的执行时间,则不会再另起一个线程做监控。
	// boolean isLock = lock.tryLock(10, 30, TimeUnit.SECONDS)
	boolean isLock = lock.tryLock(10, TimeUnit.SECONDS);
	// 判断是否获取成功
	if(isLock) {
		try {
			System.out.println(""执行业务);
		} finally {
			// 释放锁
			lock.unlock();
		}
	}
}

4、Redisson实现的分布式锁是否是可重入锁?(可重入锁)

  • redis实现的分布式锁是不可重入的,但Redisson实现的分布式锁是可重入的,与Java中的ReentranLock是一样的,都是判断是否是同一个线程来判断是否可重入,如果是同一个线程则可重入。

  • 当业务比较复杂时,锁粒度比较细时 会用到重入锁的,可以避免多个锁当中产生死锁问题。

  • Redisson中的实现
    1)利用hash结构记录线程id和重入次数
    2)获取锁之后在原有的重入次数中加1,释放锁成功时再直接减1,直到重入次数为0时才可以将该锁的信息删除。
    在这里插入图片描述

5、Redisson实现的分布式锁能否解决主从数据的一致性?(不能)

  • 假如redis的集群架构有一个主节点(主库),用于写数据;两个从节点(从库),用于读数据。当主节点发生了写数据时,则需要将数据同步到两个从节点中。当Java应用获取锁往主库中写入数据后,还没来得及将数据同步到从库中,主库就宕机了(挂了),则此时就出现了主从数据不一致的情况。主库宕机后,redis使用的哨兵模式,则会从两个从库中选择一个作为主库,此时还能去获取锁,则出现了两个线程拥有同一把锁的情况,导致脏数据。

  • RedLock(红锁):不能只在一个redis实例上创建锁,应该是在多个实例上创建(n / 2 + 1)个,避免在一个redis实例上加锁。但使用红锁,会导致业务实现比较复杂、性能差、运维繁琐。

  • Redisson实现的分布式锁不能解决主从数据的一致性,但是可以使用redisson提供的红锁来解决,红锁的性能太低,如果业务中硬性要求要保证数据的强一致性,建议采用zookeeper实现的分布式锁。

  • Redis 主要保证的是高可用性,zookeeper才可以保证数据的强一致性。

6、Redis分布式锁

三、Redis集群

1、Redis集群有哪些方案?

  • Redis中提供的集群方案有三种:
    1)主从复制:单节点redis的并发能力是有上限的,要进一步提高redis的并发能力,就需要搭建主从集群,实现读写分离。
    2)哨兵模式:sentinel,中文名是哨兵。哨兵是 redis 集群机构中非常重要的一个组件,用来实现主从集群自动故障恢复,可保证redis的高并发高可用
    3)分片集群:可解决海量数据存储问题、高并发写问题,

在这里插入图片描述
在这里插入图片描述

2、主从数据同步流程(主从复制原理)

  • 主从同步:单节点redis的并发能力是有上限的,要进一步提高redis的并发能力,就需要搭建主从集群,实现读写分离,一般是一主多从,主节点负责写数据,从节点负责读数据,主节点写入数据之后,需要把数据同步到从节点中。

  • 主从同步分为两个阶段:全量同步、增量同步。

  • 主从全量同步:指从节点第一次与主节点建立连接时使用的同步,即全量同步。
    1)从节点请求主节点同步数据,其中从节点会携带自己的replication id和offset偏移量。
    replication id:数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的id,slave则会继承master节点的id。
    offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大,slave完成同步时也会记录当前同步的offset,如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
    2)主节点判断是否第一次请求,主要判断的依据是,主节点和从节点是否是同一个replication id,如果不是,就说明是第一次同步,那主节点就会把自己的replication id和offset偏移量发送给从节点,让从节点与主节点的信息保持一致。
    3)同时主节点会执行bgsave,生成rdb文件后,发送给从节点去执行,从节点先把自己的数据清空,然后执行主节点发送过来的rdb文件,这样就保持了一致。
    4)如果在rdb生成执行期间,依然有请求到了主节点,主节点会以命令的方式记录到缓冲区,缓冲区是一个日志文件
    5)最后把这个日志文件发送给从节点,这样就能保证主节点和从节点完全一致了,后期再同步数据时,都是依赖这个日志文件

  • 主从增量同步:指当从节点服务重启之后,数据不一致时的同步
    1)从节点会请求主节点同步数据,主节点还是判断是不是第一次请求,不是第一次就获取从节点的offset值
    2)然后主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步。
    在这里插入图片描述

3、哨兵模式(保证redis的高并发高可用)

  • 哨兵模式:实现了主从集群的自动故障恢复(监控、自动故障恢复、通知),如果master故障,sentinel(哨兵)会将一个slave提升为master。当故障实例恢复后也会以新的master为主,同时sentinel(哨兵)也充当redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给redis的客户端,即一般项目采用哨兵模式可保证redis的高并发高可用。

  • 哨兵的作用:
    1)集群监控:负责监控 redis master 和 slave 进程是否正常工作。sentinel(哨兵)会不断的检查master和slave是否按预期工作。
    2)自动故障恢复:如果 master node 故障挂掉了,会自动转移到 slave node 上,将一个slave提升为master,当故障实例恢复后也以新的master为主。
    3)消息通知:如果某个 redis 实例有故障,那么sentinel哨兵负责发送消息作为报警通知给管理员,sentinel充当redis客户端的服务发现来源,会将最新信息推送给redis的客户端。

  • 服务状态监控:sentinel基于心跳机制监测服务状态,每隔1s向集群的每个实例发送ping命令
    1)主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
    2)客观下线:如果超过指定数量quorum的sentinel都认为该实例已经下线,则该实例客观下线,quorum值最好超过sentinel实例数量的一半。

  • 哨兵选主规则:
    1)首先判断主与从节点断开时间长短,如果超过指定值就排该从节点
    2)然后判断slave-priority值,越小优先级越高
    3)如果slave-priority一样,则判断slave节点的offset值,越大优先级越高
    4)最后判断slave节点的运行id大小,越小优先级越高。

4、Redis集群脑裂,该怎么解决?

  • 集群脑裂:指使用哨兵模式集群时,由于主节点master和从节点和sentinel(哨兵)处于不同的网络分区,使得sentinel没有心跳感知到主节点master,所以通过选举的方式提升了一个从节点slave为主节点master,这样就存在两个主节点,就像大脑分裂了一样,会导致客户端还在old master那里写入数据,新节点无法同步数据,当网络恢复后,sentinel(哨兵)会将老的主节点降为slave从节点,这时再从新的主节点同步数据,这会导致老的主节点中的大量数据丢失。

  • 解决办法:可以修改redis的配置,可设置最少的slave节点个数,比如设置至少要有一个从节点才能同步数据;可设置主从数据复制和同步的延迟时间,达不到要求就拒绝请求,可避免大量数据丢失。

min-replicas-to-write 1  表示最少的slave节点为1个
min-replicas-max-lag 5   表示数据复制和同步的延迟不能超过5秒

5、redis的分片集群有什么作用?

  • 分片集群主要解决海量数据存储的问题,集群中有多个master,每个master保存不同数据
  • 每个master都可以设置多个slave节点,就可以继续增大集群的高并发能力。
  • 同时每个master之间通过ping监测彼此健康状态,就类似于哨兵模式了。
  • 当客户请求可以访问集群任意节点,最终都会被转发到正确节点。

6、redis分片集群中数据是怎么存储和读取的?

  • redis分片集群引入了哈希槽(slot)的概念,redis集群有16384个哈希槽,集群中每个主节点绑定了一定范围的哈希槽范围,key通过CRC16校验后对16384取模来决定哪个槽,通过槽找到对应的节点进行存储。

7、Redis是单线程,为什么还那么快?

  • Redis是纯内存操作,执行速度非常快
  • 采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题
  • 使用I/O多路复用模型,非阻塞IO
  • 例如 bgsave和bgrewriteaof 都是在后台执行操作,不影响主线程的正常使用,不会产生阻塞

在这里插入图片描述

8、IO多路复用模型

在这里插入图片描述

  • redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,I/O多路复用模型主要就是实现了高效的网络请求。

  • Linux系统中一个进程使用的内存情况划分部分:用户空间和内核空间
    用户空间只能执行受限的命令(Ring3),而且不能直接调用系统资源,必须通过内核提供的接口来访问。
    内核空间可以执行特权命令(Ring0),调用一切系统资源。

  • 常见的IO模型
    1)阻塞IO(Blocking IO)
    2)非阻塞IO(Nonblocking IO)
    3)IO多路复用(IO Multiplexing)

  • redis网络模型

  • Linux系统为了提高IO效率,会在用户空间和内核空间都加入缓冲区
    写数据时,要把用户缓冲数据拷贝到内核缓冲区,然后写入设备
    读数据时,要从设备读取数据到内核缓冲区,然后拷贝到用户缓冲区
    在这里插入图片描述

四、

标签:面试题,缓存,Redis,redis,数据,节点,分布式
From: https://blog.csdn.net/weixin_43763430/article/details/137212291

相关文章

  • 面试题目分享
    学习目标:从面试了解自己的不足。学习内容:1.你会什么语言?我该如何回答,我会java,c,c++等,在工作中我会用到合适的语言。牛逼吹的大话尊敬的面试官,我精通Java和Python,前者用于企业级后端开发,后者擅长数据分析。我也熟悉前端JavaScript/TypeScript和React。具备跨语言学习......
  • Redis
    Windows系统安装Redis1、修改配置(可参考Linux配置)修改Redis配置文件(服务模式启动)redis.windows-service.conf,前台方式启动时使用的配置文件为redis.windows.confbind127.0.0.1::1#将本地地址绑定注释掉,否则不能远程连接port6379#配置监听端口daemonizeyes#开......
  • php:安装phpredisadmin
    一,项目代码地址:https://github.com/erikdubbelboer/phpRedisAdmin二,下载:从命令行用wget下载[root@blogphpredisadmin]#wgethttps://github.com/erikdubbelboer/phpRedisAdmin/archive/refs/tags/v1.20.0.tar.gz下载完成后解压缩[root@blogphpredisadmin]#tar-zxvfv......
  • Redis实现可重入的分布式锁
    加锁脚本--加锁脚本--成功返回1,失败返回-1localkey=KEYS[1]localrequestId=KEYS[2]--单位毫秒localttl=tonumber(KEYS[3])localresult=redis.call('setnx',key,requestId)ifresult==1thenredis.call('pexpire',key,ttl)elseresult......
  • Redis实战(黑马点评--点赞关注)
    一、发布、查看探店笔记保存blog@PostMappingpublicResultsaveBlog(@RequestBodyBlogblog){//获取登录用户UserDTOuser=UserHolder.getUser();blog.setUserId(user.getId());//保存探店博文blogService.save(blog);//返回idret......
  • Redis实战(黑马点评--优惠券秒杀)
    一、redis实现全局唯一订单id1、问题:使用数据库自增id不合适当用户抢购商品时,生成的订单会保存到tb_voucher_order表中,而订单表如果使用数据库自增ID就会存在一些问题id规律性太明显受单表数据量的限制2、解决方法:全局id生成器符号位:1bit,永远为0时间戳:31bit,以秒为单位,可......
  • CenterOs7安装redis
    CenterOs7安装redis1.redis的安装1.1下载redis从官网下载redis,并且上传到服务器的安装位置1.2安装redis①解压redis,执行tar-zxvf安装包名称②makeredis源码,make③makeinstallmakeinstall2.redis的配置2.1配置启动脚本配置redis的启动脚本,放置于/etc/init.d/......
  • redis学习(007 实战:黑马点评:登录)
    黑马程序员Redis入门到实战教程,深度透析redis底层原理+redis分布式锁+企业解决方案+黑马点评实战项目总时长42:48:00共175P此文章包含第25p-第p34的内容文章目录短信登录功能session共享问题短信登录功能接口编写这里是Result的封装过滤器在......
  • Redis三大缓存问题:缓存穿透、缓存击穿、缓存雪崩的场景以及解决方法
    文章目录都是缓存惹的祸缓存穿透场景描述解决方法缓存键同时失效1.过期时间随机化2.使用多级缓存3.缓存预热4.加互斥锁缓存中间件故障1.服务熔断-Java示例2.构建Redis集群注意事项缓存击穿场景描述解决方法1.加互斥锁(MutexLock)2.永久缓存热点数据注意事......
  • redis常用命令
    redis常用命令:    1)连接操作命令   quit:关闭连接(connection)   auth:简单密码认证   helpcmd:查看cmd帮助,例如:helpquit      2)持久化   save:将数据同步保存到磁盘   bgsave:将数据异步保存到磁盘   lastsave:返回上次成功将数据保......