Redis相关总结

Redis缓存



前言

Redis 的常见用于热点数据缓存,限时业务、计数器、排行榜、分布式锁、队列等 。但是redis在使用的过程中也存在很多细节问题,这篇文章
总结了redis应用的常见问题以及相关的底层原理。

一、缓存穿透、缓存击穿、缓存雪崩

缓存穿透:是指查询一个不存在的数据,如果DB不存在一直不能回写缓存则,请求的数据每次都会穿透到DB,导致将压力全部施加到DB,导致系统崩溃。
(1)解决方案:增加cachMiss,如果是恶意请求 (2)布隆过滤器:将所有可能存在的数据hash到一个足够大的bitmap中,不存在的数据将被拦截防止查询到DB (3)redis中不存在则返回

2.缓存击穿:对于设置了过期时间的key,缓存失效同时大量请求过来,此时如果不加处理,大量并发仍然可能造成数据库瓶颈。

解决方案:(1)当缓存失效时,加锁查库回置缓存(2)根据业务设置缓存用不过期,逻辑过期,异步刷缓存等

二、缓存与数据库双写时数据一致性

首先在缓存与数据库双写的场景中就一定会出现不一致的问题,我们可以通过一些操作降低此类问题出现的概率。
(1)先更新缓存再更新数据库。这种策略在多线程环境可能会出现数据覆盖。
(2)先删除缓存,再更新数据库。多线程环境下可能会将旧数据加载到缓存,造成数据不一致问题。 这种方案如果使用延迟双删不仅会过度设计,还会降低系统的并发量,引入新的问题。(比如休眠时间设置问题等)
(3)先更新数据库,再删除缓存。缓存更新策略《Cache-Aside pattern》其中指出;更新:先把数据存入数据库中,成功之后再让缓存失效。
方案三 在极端情况下仍然可能存在问题。比如删除缓存失败等
此处引入重试机制即可:
在这里插入图片描述
(1)首先更新数据库
(2)当各种原因删除缓存失败,将失败的key写入消息队列
(3)消费消息,获取需要删除的key进行重试删除。
为了不侵入业务逻辑,我们可以启动一个任务去订阅数据库的binlog,取出操作的数据以及key加入消息队列,进行删除缓存操作。

三、redis事务

redis事务特征:
隔离性:redis事务具有隔离性,所有命令都会串行化按照顺序执行,不会受外界的干扰
原子性:事务要么全部执行要么不执行

四、redis的持久化机制是什么?

RDB机制:是指将一定时间间隔的数据以快照的形式保存在磁盘上。是默认的持久化方式。这种方式就是将内存中数据以快照方式写入磁盘,默认文件是dump.rdb 对RDB来说提供了三种机制:save、bgsave、自动化。

1)RDB(REDIS BASE)文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。
(2)生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

缺点:在快照持久化期间修改的数据不会被保存,可能丢失数据。

AOF机制(APPEND OF FILE ):全量备份耗时较长,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。

(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。(2)AOF日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损。
(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。
(4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据

缺点
(1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
(2)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的
(3)以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。

如果AOF文件出现异常,Redis在重启的时候会拒绝加载AOF文件,从而保证数据一致性。

一般请款下同时开启RDB和AO

使用命令
redis-check-aof -fix 
对文件进行修复

五、全量同步

Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:

  • 从服务器连接主服务器,发送SYNC命令;
  • 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
  • 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
  • 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
  • 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
  • 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;

完成上面几个步骤后就完成了从服务器数据初始化的所有操作,从服务器此时可以接收来自用户的读请求。

增量同步
Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。

六、Redis线程模型

redis内部使用文件事件处理器,由于该处理器是单线程的,所以redis才叫做单线程模型。
它采用IO多路复用机制同时监控多个socket,根据socket上的事件来选择对应的事件处理器进行处理。
文件事件处理器结构包括四部分:多个socket、IO多路复用程序、文件时间分派器,
事件处理器(包括:连接应答处理器、命令请求处理器命令回复处理器)

在这里插入图片描述

七、redis中的数据结构

SDS结构

简单动态数据(Simple dynamic string):redis 没有使用c语言传统的字符数组表示字符串,而是重新构建了一种简单动态数据。

struct sds {
    
    // 记录字节数组中已经使用的字节的数量
    int len;
   
   // 记录buf数组中未使用的字节的的数量     
    int free;
    // 字节数据,用于保存字符串
    car buf[];
}

动态简单数组具有 二机制安全、空间预分配、常数复杂度获取字符串长度。
SDS 和 C字符串的区别:
(1)杜绝缓冲区溢出:在c语言中使用strcat函数进行两个字符串的拼接,一旦没有分配足够长的内存空间就会造成缓冲区溢出。而对于SDS进行字符修改的时候会首先根据记录中的len检查内存空间是否满足需求。如果不满足,会进行相应的空间扩展,然后再进行修改操作。

(2)二进制安全:因为c中字符串以空字符作为字符串结束的标识,而对于一些二机制文件(图片等)内容可能包含空字符串,使用c语言字符串无法正确存储。而SDS以len判断字符串是不是结束。

(3)惰性空间释放:对于字符串进行压缩操作时,程序不立即使用内存重新分配来回收缩短后多余的字节而是使用free属性将可用空间数记录下来,再次使用时不用重新分配。

hash 结构

字典结构 保存键值对;

链表结构

双端:链表指针带有prev和next指针,获取某个节点的前置节点和后置节点的复杂度都是O(1);无环;带有表头指针和表尾指针,获取链表头节点和尾节点的复杂度都为O(1)。

zset结构

redis中zset 可能有两种结构一种是 ziplist 或者是skiplist。当有序集合中对象元素数量小于128时,保存的所有元素长度都小于64字节。此时使用的压缩列表作为底层实现。
什么是压缩列表? (ziplist)
其实ziplist本质上是字节数组;
各个字段含义如下: zlbytes 压缩列表的长度;
zltail 压缩列表尾元素相对压缩列表起始地址的偏移量;
zllen:压缩列表的元素数目;
zend:压缩列表的结尾;
entryx:压缩列表存储的若干个元素。

skiplist 通过向上抽出多级别索引,使得查找元素的时间复杂度近似于二分查找,跳表虽然会占据很多的内存空间,但是实现起来比较简单,而且对范围查询这个功能比红黑树要好很多。


八、redis实现分布式锁存在的问题?

使用redis 实现分布式锁最简单的事使用setnx命令,配合释放锁最简单的命令del;

jedis.set(key, value, nxxx, expx, time)
jedis.del

在这里插入图片描述
使用setnx存在的问题如下:A获取到锁,master在将锁同步给slave的时候由于各种故障问题宕机,slave节点未同步锁信息;此时slave晋升为主节点,势必有其他线程获取锁,此时就会存在多个线程持有锁的case;
无论是在redis的主从、哨兵、还是集群模式下都可能存在这种问题;

解决方案:
所以redis官方针对这种情况提出了红锁(Redlock)的概念。
redlock算法的设计原理;redLock算法是在CP环境中(数据一致性和分区容错性);假设有5个redis节点,这些节点之间既没有主从,也没有集群关系。客户端用相同的key和随机值在5个节点上请求锁,请求锁的超时时间应小于锁自动释放时间。当在3个(超过半数)redis上请求到锁的时候,才算是真正获取到了锁。如果没有获取到锁,则把部分已锁的redis释放掉。

九、redis 脑裂问题

在这里插入图片描述

由于网络原因,master节点和slave以及sential节点处于不同的网络分区,在这种情况下由于sential无法感知到master的存在故重新选举新的master,而此时原master节点还在接受客户端的请求却无法将数据同步到slave,等网络恢复,sential会将原maste降为slave,此时会有大量数据丢失。
解决脑裂问题需要设置redis配置文件中参数

min-slaves-to-write 3 // 连接到master的最少slave数量
min-slaves-max-lag 10 // slave连接到master的最大延迟时间

要求至少3个slave节点,且数据复制和同步的延迟不能超过10秒,否则的话master就会拒绝写请求,配置了这两个参数之后,如果发生集群脑裂,原先的master节点接收到客户端的写入请求会拒绝,就可以减少数据同步之后的数据丢失。

十 redis bigkey问题

bigkey是指占用内存空间非常大的key。例如一个String 类型的value占用了100MB的空间。
通过redis 的进程模型可知在处理redis命令的时候文件事件处理器是以一种有序的方式通过文件事件分派器将命令交由事件处理器进行处理,因此大key会占用处理资源,对redis处理后续请求造成阻塞并且在网络传输过程中造成网络拥堵;
在日常开发环境中我们可以通过redis-cli-bigkeys统计 bigkey的分布。

十一 redis的缓存失效策略

redis中缓存失效策略:定时删除、惰性删除、定期删除;
定时删除:在设置key的过期时间的同时,为key创建一个定时器,让定时器在key的过期时间来临时对key进行删除。
优点:保证内存尽快释放
缺点:若key过多,删除这些key会占用很多cpu的时间,且每个key创建一个定时器,也会有性能造成影响。

惰性删除
key过期的时候并不立即删除,而是下次查询的时候发现过期之后再删除。
优点:CPU时间占用比较少
缺点:若key长时间没有被获取,将不会被删除,可能造成内存泄漏。

定期删除
每隔一段时间执行一次删除过期key操作。
优点:可以控制删除操作的市场和频率来减少CPU的占用时间,避免惰性删除的时候内存泄漏问题。
确定:对内存友好方面不如定时策略,对CPU友好方面不如惰性策略。
生产环境中redis 一般采用:惰性+定期策略两个相结合。

Redis常见的淘汰算法有哪些?

LRU 最近最少使用算法:根据最近播哦使用的时间,离目前最远的数据优先被淘汰。

LFU 最不经常使用算法: 在一段时间内数据被使用次数最少的,优先被淘汰。
LRU 算法 使用LinkedHashMap 模拟。


LFU 算法


Redis的数据同步机制

在这里插入图片描述
首先redis有全量复制和增量复制两种模式。

全量拷贝

1.redis的slave节点首次连接master节点时,发送同步命令psync {runId}{offset}.其中runId表示master 的运行id,而offset表示数据偏移量。第一次发送psync{?}{-1} 表示需要进行全量复制。此时master会fork一个子线程执行bgsave命令生成RDB文件。于此同时master仍然可以处理客户端请求,将命令写入缓冲区。

2.当master将生成的RDB文件传输到slave节点。当RDB文件传输结束之后,向slave发送缓冲区的写命令。

3.slave接收到RDB文件丢弃旧数据,开始载入RDB文件。当执行RDB文件结束之后,slave执行从master缓冲区发送过来的写命令。

4.此后,master每执行一个写命令都会想slave发送相同的写命令。

增量拷贝

1.在网络出现闪断的情况或者命令丢失的情况时,当主从连接恢复之后。由于从节点之前保存了自己已经复制的偏移量和主节点运行runId。因此可以根据这两个参数进行部分复制操作。

2.主节点接收到psync命令时,首先核对参数与自身的runId是否一致,如果一致说明之前复制的事当前主节点;之后根据参数offset在自身积压的缓冲区查找,如果偏移量在缓冲区中,则对节点发送continue响应。表示可以进行部分复制否则要进行全量复制。

3.主节点根据偏移量把复制积压缓冲区中的数据发送给从节点,保证主从复制进入正常状态。

总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis相关的面试题涵盖了以下几个方面: 1. Redis的基本概念和特性:面试官可能会问到你对Redis的理解和熟悉程度。你可以回答Redis是一个开源的内存键值存储系统,具有高性能和持久化能力。它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合等。 2. Redis的数据持久化方式:Redis提供了两种方式来将数据持久化到磁盘上,分别是RDB(Redis Database)和AOF(Append Only File)。RDB是一种快照方式,可以将数据以二进制形式保存到硬盘上,而AOF则是将每个写操作追加到文件末尾。你可以解释一下这两种方式的优缺点,并说明在不同场景下应该选择哪种方式。 3. Redis的线程模型:在Redis 6.0之前,Redis是单线程的。而在Redis 6.0之后开始支持多线程。Redis内部使用基于epoll的多路复用来处理网络IO,而执行命令的核心模块仍然是单线程的。你可以简要介绍一下Redis的线程模型以及引入多线程的原因。 4. Redis的扩展模块:Redis支持通过扩展模块来增加额外的功能。例如,BloomFilter、RedisSearch和Redis-ML等扩展模块可以用于实现不同的功能需求。你可以提到一些常用的Redis扩展模块,并解释一下它们的作用和用途。 总结起来,面试中关于Redis的问题主要包括对Redis的基本概念和特性的理解、数据持久化方式、线程模型以及扩展模块的使用等方面。通过对这些问题的了解和回答,可以展示出你对Redis的熟悉程度和实际应用能力。同时,你还可以结合自己的经验和实际项目,给出一些实际的应用场景和解决方案,从而更好地回答面试官的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [面试 Redis 没底?这 40 道面试题让你不再慌(附答案)](https://blog.csdn.net/xmt1139057136/article/details/115423283)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [redis面试题总结(附答案)](https://blog.csdn.net/guorui_java/article/details/117194603)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值