上一篇传送门:点我

redis学习笔记,后续会继续补充

什么是redis?为什么要用redis?

redis是一个开源的、使用C语言编写、支持网络、可基于内存亦可持久化的日志型、noSql、Key-Value数据库,并提供多种语言的API。 由于redis的数据是存储于内存之中的,它的读写速度非常快,每秒可以处理超过10万次读写操作,所以它被广泛应用于缓存从而提升数据的读写性能,减轻mysql数据库的压力。同时redis支持字符串、哈希、列表、集合和有序集合等多种不同的数据结构,这使得redis可以非常灵活地存储和处理各种类型的数据。并且redis的操作都是原子操作,这也能保证在并发环境下数据的一致性和安全性。

redis的数据类型有哪些?

redis有五种基本类型:String(字符串,最基本的数据类型,使用场景:存储如id的简单用户信息)、Hash(哈希,key-value键值对,使用场景:适合用于存储对象信息,将对象的属性存储为字段,将字段对应的值存储为字段值)、List(列表,可重复,按插入顺序有序排序,使用场景:日志消息、聊天记录)、Set(集合,无序,不可重复,使用场景:网站访客、在线用户列表)、zset(有序集合,通过给每个元素打分,按打分高低排序,使用场景:存储以发布时间为排序依据的信息)。 除了五种基本类型,还有Geospatial(地理位置)、Hyperloglog(基数统计)、Bitmap(二进制位图)等几种种特殊的数据类型。

redis的持久化策略是什么?

redis的持久化指的是将内存数据保存到硬盘,以防止机器重启后数据丢失。 redis的持久化策略主要有RDB和AOF两种。

RDB是Redis的默认持久化方式,它会在指定的时间间隔内生成数据集的时间点快照。这种方式的优点是生成的RDB文件紧凑,非常适合用于备份和恢复数据。由于RDB持久化是通过fork子进程来执行的,主进程可以继续处理客户端请求,因此对性能的影响较小。然而,RDB的缺点是它是间隔一段时间进行持久化,如果Redis在持久化过程中发生故障,可能会丢失最近一次持久化之后的数据。

另一种持久化策略是AOF,它会记录Redis服务器接收到的所有写操作命令,并在服务器启动时通过重新执行这些命令来重建数据集。AOF的优点是提供了更好的数据安全性,因为它记录了每一个写操作命令,即使Redis在持久化过程中发生故障,也可以通过重放AOF文件中的命令来恢复数据。此外,AOF文件易于理解和解析。然而,AOF的缺点是文件通常比RDB文件大,且恢复速度可能较慢。为了压缩AOF文件的大小,当AOF文件扩大到一定程度后,AOF文件会进行重写:redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个文件所保存的数据库状态是相同的,但是新的AOF文件不会包含任何浪费空间的冗余命令,通常体积会较旧AOF文件小很多。

在redis4.0后,又提出了一种混合策略,即将RDB和AOF混合一起使用。在使用混合模式中,所有的数据操作也是保存在AOF当中,当进行恢复文件时,会将原有的AOF删除,并将其中的数据全部以快照的形式保存至RDB文件之中。

说说redis的过期策略

Redis主要有三种过期策略:定时删除、惰性删除和定期删除。

定时删除:为每个设置过期时间的key创建一个定时器,在key的过期时间到达时立即执行删除操作。这种策略对内存友好,因为能确保过期数据尽快被释放。但缺点是当过期key较多时,会占用大量CPU时间来处理删除操作,从而影响缓存的响应时间和吞吐量。

惰性删除:在每次访问key时检查其是否过期,如果过期则进行删除。这种策略对CPU友好,因为只有在访问时才进行过期检查。但缺点是可能导致大量过期key长时间占用内存而不被释放,对内存不友好。

定期删除: 每隔一段时间执行一次删除过期key的操作。通过限制删除操作的时长和频率,可以在不同情况下平衡CPU和内存的使用。这种策略是定时删除和惰性删除的一种折中方案。

redis的内存淘汰策略

redis的内存淘汰策略允许redis在内存资源紧张时,根据一定的策略主动删除一些键值对,以释放内存空间并保持系统的稳定性。以下是redis常见的内存淘汰策略: noeviction(不淘汰策略): 默认淘汰策略,当内存不足以容纳新写入数据时,新写入操作会报错。这种策略可以确保已存在的数据不会被意外地删除,但也可能导致新写入操作失败。 volatile-lru(最近最少使用):从设置了过期时间的键中选择最少使用的键进行删除。该策略优先删除最久未被访问的键,保留最常用的键。 volatile-ttl(根据过期时间优先):从设置了过期时间的键中选择剩余时间最短的键进行删除。该策略优先删除剩余时间较短的键,以尽量保留剩余时间更长的键。 volatile-random(随机删除):从设置了过期时间的键中随机选择一个键进行删除。 allkeys-lru(全局最近最少使用):从所有键中选择最少使用的键进行删除。无论键是否设置了过期时间,都将参与淘汰。 allkeys-random(全局随机删除):从所有键中选择一个键进行删除。

谈谈布隆过滤器

布隆过滤器是一种基于位数组和多个哈希函数的数据结构,它用于高效地判断一个元素是否可能属于某个集合。布隆过滤器的主要优点是空间效率和查询时间都非常优秀,并且不需要存储元素本身,适用于对保密性要求高的场景。但是,布隆过滤器也存在一些缺点,比如它有一定的误识别率,可能会导致假阳性的结果,并且无法直接删除集合中的元素。在实际应用中,我们需要根据具体需求和场景来选择合适的数据结构。(不存在一定不存在,存在不一定存在)

以下三个问题可能不会直接问,面试官可能会问:在项目开发过程 中,有没有遇到什么关于redis的问题呢?可以引出以下三个问题。

什么是缓存击穿?如何解决缓存击穿?

缓存击穿是指当某个热点key在缓存中不存在(可能是因为过期或被删除),而此时又有大量的并发请求需要这个key的数据,这些请求就会直接穿透到数据库进行查询,这会导致数据库查询的压力过大,系统性能会大大降低。 解决缓存击穿问题,可以采取以下几种方案: 永不过期: 可以给这些热点数据过期时间设置为永不过期,而冷数据的过期时间设置为定时过期,同时可以写一个算法判断当某个冷数据访问量激增时,修改当前过期时间为永不过期; 加锁排队: 当缓存失效时,不是立即去数据库查询,而是先使用同步锁保证只有一个请求去数据库查询数据,查询完成后释放锁,并将数据放入缓存。其他请求在锁释放之后,能够在redis中拿到数据。(进入synchronized后还要再查询一次redis,这是为了防止上一个抢到锁的线程已经对redis进行了更新); 缓存空对象: 当从数据库查询不到数据时,可以将一个空值缓存起来,并设置一个较短的过期时间。然后再去数据库中查询数据,把查到的数据更新在缓存中,从而避免了缓存击穿问题的出现。

什么是缓存雪崩?如何解决缓存雪崩?

缓存雪崩是指当缓存中的大量数据在同一时间集中过期或是缓存服务器宕机时,导致原本应该由缓存处理的请求直接涌向数据库,造成数据库瞬间压力剧增,甚至可能导致数据库崩溃的现象。 为了解决缓存雪崩问题,可以采取以下几种策略: 设置随机过期时间: 给缓存数据设置随机的过期时间,使得缓存的失效时间分布在一个合理的时间段内,而不是集中在某一时刻,从而避免了数据的集中过期; 加锁排队: 当缓存失效时,不是立即去数据库查询,而是先使用同步锁保证只有一个请求去数据库查询数据,查询完成后释放锁,并将数据放入缓存。其他请求在锁释放之后,能够在redis中拿到数据; 构建redis高可用集群: 主要针对缓存服务器宕机的情景,通过Redis集群中的哨兵模式,当缓存服务器主节点发生故障宕机时,可以选择一台从节点服务器去代替主节点继续工作。

什么是缓存穿透?如何解决缓存穿透?

缓存穿透是指查询的数据不存在数据库也不存在缓存中,所以每次请求该数据都会直接穿透缓存去查询数据库,这时的用户很可能是攻击者,例如发起id为“-1”的数据或是id为特别大(大到数据库不存在)的数据,导致数据库压力过大或是直接宕机。 参数校验: 在业务请求的入口处进行数据合法性校验,检查请求参数是否合理、是否包含非法值、是否恶意请求等,提前有效阻断非法请求(无法完全杜绝); 缓存空对象: 当从数据库查询不到数据时,可以将一个空值缓存起来,并设置一个较短的过期时间。这样,后续的相同查询就可以直接从缓存中获取空值,避免了数据库的查询。 使用布隆过滤器: 在缓存之前,可以先通过布隆过滤器判断数据是否存在。如果布隆过滤器判断数据不存在,则直接返回,不再查询数据库和缓存。

redis和mysql如何保持数据一致性?

在使用了redis的程序中,当程序需要读取某个数据时,会首先尝试去redis中加载,如果命中了就直接返回,如果没有命中,就会直接从数据库中查询,查询到数据库之后,再把数据缓存到redis里面。此时由于更新mysql和redis的操作是存在先后顺序的,所以会出现mysql和redis数据不一致的问题。保持数据一致性可以有以下几种方法:

1.先更新数据库,再更新缓存 当应用执行写操作时,同时更新 redis 和 mysql。这样可以确保两个数据源中的数据始终保持一致。但这种方法可能增加写操作的复杂性和延迟。

2.先删除缓存,再更新数据库

在更新 mysql 之前先删除 redis 中的缓存项,然后再执行更新操作。这样可以避免缓存中的数据与 mysql中的新数据不一致。但是,在删除缓存和更新数据库之间可能会存在时间差,这段时间内如果有读请求,可能会导致缓存击穿。

3.延迟双删策略

先删除 redis 缓存,然后更新 mysql,设置一个短暂的延迟时间,之后再次删除 redis 缓存。这种策略是为了应对在高并发场景下,第一个删除操作和数据库更新操作之间的时间差内,有其他线程将旧数据存入缓存的问题。

4.基于消息队列的同步

可以使用消息队列来异步地处理数据同步。当mysql数据更新后,发送一个消息到消息队列,然后由消费者服务来处理这个消息,并更新 redis。这样可以减少写操作的延迟,并提高系统的吞吐量。

谈谈redis集群

redis集群有几种实现方式。一个是主从集群,一个是redis cluster。

主从集群就是在redis集群里面包括一个主节点和多个从节点,主节点负责数据的读写,从节点负责数据的读取,主节点收到数据的变更会同步到从节点上实现数据的同步,通过主从集群可以实现redis的读写分离,提升数据的查询效率。但是redis主从集群不提供容错和恢复的功能,一旦主节点挂了,不会选取出新的主节点,这会导致后续的所有写请求直接失败。因此redis提供了哨兵机制,专门用来监听redis主从节点,提供故障的自动恢复能力,哨兵会监控redis主从节点的状态,当主节点故障时会自动地从剩下的从节点中选举出一个新的主节点。

redis cluster则实现了redis的分布式存储,即每个节点存储不同的数据实现数据的分片功能,在redis cluster中引入了slot槽来实现数据分片,slot的取值范围是0-16383,每个节点会分配一个slot区间,当存取key时,redis会根据key计算一个slot的值,从而找到对应的节点进行数据的读写。在高可用方面,redis cluster引入了主从复制的模式,一个主节点有一个或多个从节点,当主节点故障,会自动从从节点中选举一个节点作为主节点继续提供服务。

Redission实现分布式锁有了解吗?

Redission是一个基于Redis实现的Java分布式对象存储和缓存框架。Redission是利用Redis的键值存储特性和其提供的一些原子操作来实现分布式锁的。

当客户端尝试获取锁时,Redission会向Redis发送一个SETNX命令(如果redis存在该键则set失败),并设置一个唯一的锁标识和锁的超时时间。如果锁不存在,则Redis会设置该锁并返回成功状态;如果锁已经存在,则Redis不会设置锁并返回失败状态。 通过这种方式,Redission保证了在任意时刻只有一个客户端能够获取到锁。

由于有一些业务处理时间可能会较长,以至于超出了原先设定的锁超时时间,从而导致锁已经超时,线程业务还未处理完的情况发生。为了解决这个超时问题,Redission还实现了一个看门狗机制。当客户端获取到锁后,会启动一个定时任务作为看门狗,每隔一段时间就去判断当前线程是否还持有锁,如果持有,就会在锁即将过期时自动续期。这样,只要客户端持有锁并且正常执行,锁就不会因为超时而被释放。当客户端释放锁时,会显式地关闭看门狗任务,并发送一个删除命令到Redis来删除锁。

如果redis使用了主从集群的模式,当设置锁时,其实是只在主节点里设置上了锁,当主节点设置完毕后才会进行主从节点的同步,但是如果此时主节点宕机了,从节点就没办法同步到这把锁,此时依然可能会出现线程安全问题。此时可以通过Red Lock进行解决,Red Lock只有在全部的节点存储完毕时,才会给出锁存储成功的相应,从而保证了redis的强一致性。

如何在Redis中实现延迟队列?

延迟队列是一种特殊的数据结构,它用来存储将来某个时间点处理的数据或任务,它允许我们按照预定的延迟时间把数据推送到队列中,然后可以在适当的时候去处理这些数据。 在Redis中,可以使用有序集合ZSet来实现延迟队列 。也就是把每个任务作为有序集合的一员,分数表示任务的执行时间,把任务按照时间排序,使用Redis的定时任务功能,并通过ZPOPMIN命令,定期检查有序集合中的成员找到到期的任务并把它移出有序集合,然后可以执行相应的操作来处理这些任务,从而实现了延迟队列的特性。在Redis中实现延迟队列,可以用来处理需要按照延迟时间执行的任务和事件,通过使用有序集合和定时触发的机制,可以轻松的创建一个可靠的延迟队列。

下一篇传送门:点我

推荐文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: