【Redis】常见面试题

什么是Redis?

Redis 和 Memcached 有什么区别? 

为什么用 Redis 作为 MySQL 的缓存? 

主要是因为Redis具备高性能和高并发两种特性。

高性能:MySQL中数据是从磁盘读取的,而Redis是直接操作内存,速度相当快。

高并发:单台设备的Redis的QPS(每秒钟处理完请求的次数)是MySQL的十倍,Redis单机的QPS能轻松破10w,而MySQL单机的QPS很难破1w。所以,直接访问Redis能够承受的请求是远远大于直接访问MySQL的。

Redis数据类型

介绍Redis数据结构之前,先来介绍以下Redis对象系统。

什么是Redis对象系统?

Redis中基于双向链表、简单动态字符串、字典、跳跃表、整数集合、压缩列表、快速列表等数据结构实现了一个对象系统,并且实现了5种不同的对象,每种对象都使用了至少一种前面的数据结构,优化对象在不同场合下的使用效率。

对象结构 RedisObject 包含:type、encoding、lru、refcount、*ptr,下面逐一介绍:

type:表示对象的数据类型,包括字符串类型、列表类型、集合类型、有序集合类型、哈希类型,占4位。

encoding:对象的编码类型,占4位,标识了该对象使用了哪种底层的数据结构。

lru:该字段是一个时间戳,表示对象最近一次被访问的时间,用于实现内存管理。当 Redis 设置了最大内存限制并需要进行逐出策略时,LRU 被用来决定哪些数据应该被淘汰。

refcount:表示对该 RedisObject 的引用计数,当某个操作引用这个对象时,refcount 会加1;当引用被释放时,refcount减1。引用计数为0时,对象会被销毁,释放内存。

*ptr:指向底层数据实现的指针。

对象结构的功能?

  • 为5种不同的对象类型提供同一的表示形式。
  • 针对不同的场景,Redis 支持同一种对象类型使用多种不同的数据结构。
  • 支持引用计数,实现对象共享机制。
  • 记录对象的访问时间,便于删除对象。

字符串对象底层实现:

列表对象底层实现:

集合对象底层实现:

哈希对象底层实现:

有序集合对象底层实现:

Redis常见数据类型和应用场景

String

介绍
内部实现
String 类型的底层的数据结构实现主要是 int SDS (简单动态字符串)。

具体如下:

 

常用命令

普通字符串的基本操作:

批量设置:

计数器(字符串的内容为整数的时候可以使用): 

过期(默认为永不过期):

不存在就插入:

应用场景

1.缓存对象

2.常规计数

因为 Redis 处理命令是单线程,所以执行命令的过程是原子的。因此 String 数据类型适合计数场
景,比如计算访问次数、点赞、转发、库存数量等等。

比如计算文章的阅读量:

3.分布式锁

4.共享 Session 信息

List

介绍

内部实现

常用命令

应用场景

消息队列

消息队列在存取消息时,必须要满足三个需求,分别是 消息保序、处理重复的消息和保证消息可
靠性。
1.如何满足消息保序需求?

2.如何处理重复的消息?

3.如何保证消息可靠性?

总结:

list 作为消息队列有什么缺陷?

list 不支持多个消费者消费同一条消息。Redis 从 5.0 版本开始提供 Stream 数据类型,同样满足消息队列三大需求,而且它还支持多个消费者消费同一条消息。

Hash

介绍

内部实现 

常用命令

应用场景

1.缓存对象

2.购物车

以用户 id 为 key,商品 id 为 field,商品数量为 value,恰好构成了购物车的3个要素。

Set

介绍

内部实现

常用命令

Set 常用操作

Set 运算操作

交集运算:

并集运算:

 

差集运算:

 

应用场景

1.点赞

Set 类型可以保证一个用户只能点一个赞。

2.共同关注

Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号等。

3.抽奖活动

存储某活动中中奖的用户名 ,Set 类型因为有去重功能,可以保证同一个用户不会中奖两次。

Zset

介绍

内部实现

常用命令

Zset 常用操作

Zset 运算操作(相比于 Set 类型,ZSet 类型没有支持差集运算

应用场景

1.排行榜

有序集合比较典型的使用场景就是排行榜。例如学生成绩的排名榜、游戏积分排行榜、视频播放排名、电商系统中商品的销量排名等。

2.电话、姓名排序

获取所有号码: 

 ZRANGEBYLEX phone - +

 获取 132 号段的号码:

ZRANGEBYLEX phone [132 (133

 获取132、133号段的号码:

ZRANGEBYLEX phone [132 (134

BitMap

介绍

内部实现

常用命令

bitmap 基本操作

bitmap 运算操作

# BitMap间的运算
# operations 位移操作符,枚举值AND 与运算 &OR  或运算 |XOR 异或 ^NOT 取反 ~
# result 计算的结果,会存储在该key中
# key1 … keyn 参与运算的key,可以有多个,空格分割,not运算只能一个key
# 当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0。返回值是保存到 destkey 的字符串的长度(以字节byte为单位),和输入 key 中最长的字符串长度相等。BITOP [operations] [result] [key1] [keyn…]
# 返回指定key中第一次出现指定value(0/1)的位置
BITPOS [key] [value]
应用场景

1.签到统计

2.判断用户登录状态

3.连续签到的用户总数

如何统计出连续 7 天打卡的用户总数呢?

我们把每天的日期作为 Bitmap 的 key,userId 作为 offset,若是打卡则将 offset 位置的 bit 设置成 1。key 对应的集合的每个 bit 位的数据则是一个用户在该日期的打卡记录。

一共有 7 个这样的 Bitmap,对这 7 个 Bitmap 对应的 bit 位做与运算。如果最终 userId 对应的 bit 位为 1,就说明该用户 7 天连续打卡。将结果保存到一个新 Bitmap 中,我们再通过 BITCOUNT 统计 bit = 1 的个数便得到了连续打卡 7 天的用户总数了。

HyperLogLog

介绍

内部实现
常用命令

127.0.0.1:6379>pfadd uv1 a b c d e#uv1中5个元素:[a,b,c,d,e]
(integer) 1
127.0.0.1:6379>pfcount uv1 #uv1中数量为5
(integer)5
127.0.0.1:6379>pfadd uv2 b c d e f #uv2中5个元素:[b,c,d,e,f]
(integer) 1
127.0.0.1:6379>pfcount uv2 #uv2中数量为5
(integer)5
127.0.0.1:6379>pfcount uv1 uv2#获取uv1和uv2去重之后数量合集:[a,b,c,d,e,f], 数量为6
(integer)6
应用场景

百万级网页 UV(独立访客)计数

Redis HyperLogLog 优势在于只需要花费 12 KB 内存,就可以计算接近 2^64 个元素的基数,和元
素越多就越耗费内存的 Set 和 Hash 类型相比,HyperLogLog 就非常节省空间。

在统计 UV 时,可以用 PFADD 命令(用于向 HyperLogLog 中添加新元素)把访问页面的每个用户都添加到 HyperLogLog 中。

PFADD page1:uv user1 user2 user3 user4 user5

接下来,就可以用 PFCOUNT 命令直接获得 page1 的 UV 值了,这个命令的作用就是返回
HyperLogLog 的统计结果。

PFCOUNT page1:uv

GEO

介绍

内部实现

常用命令
# 存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。
GEOADD key longitude latitude member [longitude latitude member ...]# 从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。
GEOPOS key member [member ...]# 返回两个给定位置之间的距离。
GEODIST key member1 member2 [m|km|ft|mi]# 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。单位:[m|km|ft|mi]->[米|干米|英里|英尺]
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
应用场景

滴滴叫车

Stream

介绍

内部实现
常用命令

应用场景

消息队列

注:前面介绍的这些操作 List 也支持。

Stream 特有功能

Stream 可以使用 XGROUP 创建消费组,创建消费组之后,Stream 可以使用 XREADGROUP
令让消费组内的消费者读取消息。

消息队列中的消息一旦被消费组里的一个消费者读取了,就不能再被该消费组内的其他消费者读
取了,即同一个消费组里的消费者不能消费同一条消息
但是,不同消费组的消费者可以消费同一条消息但是有前提条件,创建消息组的时候,不同消
费组指定了相同位置开始读取消息)。
基于 Stream 实现的消息队列,如何保证消费者在发生故障或宕机再次重启后,仍然可以读
取未处理完的消息?
Streams 会自动使用内部队列(也称为 PENDING List)留存消费组里每个消费者读取的消息,直
到消费者使用 XACK 命令通知 Streams“消息已经处理完成”。
消费确认增加了消息的可靠性,一般在业务处理完成之后,需要执行 XACK 命令确认消息已经被
消费完成。如果消费者没有成功处理消息,它就不会给 Streams 发送 XACK 命令,消息仍然会留存。此时,消费者可以在重启后,用 XPENDING 命令查看已读取、但尚未确认处理完成的消息。
一旦消息被消费者处理了,消费者就可以使用 XACK 命令通知 Streams,然后这条消息就会被删除。
总结:
Redis 基于 Stream 消息队列与专业的消息队列有哪些差距?
一个专业的消息队列,必须做到两大块:
  • 消息不丢
  • 消息可堆积

Redis 发布/订阅机制为什么不可以作为消息队列?

总结

 

Redis数据结构

SDS

C语言 char* 字符数组的缺陷

SDS 做了哪些优化? 

总结:Redis 的 SDS 结构是在原本字符数组基础上,增加了三个元数据:len、alloc、flags,用来解决 C 语言字符串的缺陷。

具体来说 SDS 的优势:

SDS 扩容规则: 

比如 sdshdr16 和 sdshdr32 这两个类型,它们的定义分别如下:

这样设计有什么好处?

举例:使用编译优化,由原来的 8 字节变为 5 字节。

链表

Redis 的 List 对象的底层实现之一就是链表。下面我们来看一下链表的结构设计:

链表的优点

1.listNode 链表节点的结构里带有 prev 和 next 指针,获取某个节点的前置节点或后置节点的时
间复杂度只需O(1)
,而且这两个指针都可以指向 NULL,所以链表是无环链表;

2.list 结构因为提供了表头指针 head 和表尾节点 tail,所以获取链表的表头节点和表尾节点的时
间复杂度只需O(1)

3.list 结构因为提供了链表节点数量 len,所以获取链表中的节点数量的时间复杂度只需O(1)

4.listNode 链表节点使用 void* 指针保存节点值,并且可以通过 list 结构的 dup、free、match 函数
指针为节点设置该节点类型特定的函数,因此链表节点可以保存各种不同类型的值

链表的缺陷

1.链表每个节点之间的内存都是不连续的,意味着无法很好利用 CPU 缓存。能很好利用 CPU 缓
存的数据结构是数组,因为数组的内存是连续的,这样就可以充分利用 CPU 缓存来加速访问。
2.保存一个链表节点的值都需要一个链表节点结构头的分配, 内存开销较大

压缩列表

zlbytes:占4个字节,记录整个压缩列表占用的内存字节数(总字节数)。

zltail:占4个字节,记录压缩列表尾节点 entryN 距离压缩列表的起始地址的字节数。

zllen:占2个字节,记录了压缩列表的节点数量。

entry[1-N]:长度不定,保存数据。

zlend:占1个字节,标记压缩列表的末端,固定值 0xFF(十进制255)。

举例:假如有三个节点: 

注:如果 prevlen 属性的长度为 5 字节,那么第一字节会被设置为0xFE(十进制值254),而之后的四个字节则用于保存前一节点的长度。 

举例说明: 

连锁更新

总结压缩列表的缺陷

quicklist

typedef struct quicklist {//quicklist的链表头quicklistNode* head;//quicklist的链表尾quicklistNode* tail;//所有压缩列表中的总元素个数unsigned long count;//quicklistNodes的个数unsigned long len;...
} quicklist;
typedef struct quicklistNode {//前一个quicklistNodestruct quicklistNode* prev;//后一个quicklistNodestruct quicklistNode* next;//quicklistNode指向的压缩列表unsigned char* zl;//压缩列表ziplist的总长度unsigned int sz;//压缩列表ziplist中的元素个数unsigned int count : 16;....
} quicklistNode;

用一张图更好的理解一下: 

listpack

listpack 结构设计

哈希表

Redis哈希表结构如下:

哈希表节点结构如下:

dictEntry 结构里不仅包含指向键和值的指针,还包含了指向下一个哈希表节点的指针,这个指针
可以将多个哈希值相同的键值对连接起来,以此来解决哈希冲突的问题,这就是链式哈希。

除此之外,dictEntry 结构里键值对中的值是一个「联合体 v」定义的,因此,键值对中的值可以是一个指向实际值的指针,或者是一个无符号的 64 位整数或有符号的 64 位整数或 double 类型的值。这么做的好处是可以节省内存空间,因为当「值」是整数或浮点数时,就可以将值的数据内嵌在 dictEntry 结构里,无需再用一个指针指向实际的值,从而节省了内存空间。

哈希冲突

什么是哈希冲突?

哈希表实际上是一个数组,数组里每一个元素就是一个哈希桶。当一个键值对的键经过 Hash 函数计算后得到哈希值,再经过(哈希值 % 哈希表大小),得到的结果值就是该 key-value 对应的数组元素位置,也就是第几个哈希桶。当有两个以上数量的 key 被分到哈希表中同一个哈希桶上时,此时称这些 key 发生了冲突

链式哈希

Redis 采用了「链式哈希」的方法来解决哈希冲突。实现的方式就是每个哈希表节点都有一个 next 指针,用于指向下一个哈希表节点,因此多个哈希表节点可以用 next 指针构成一个单向链表,被分配到同一个哈希桶上的多个节点可以用这个单向链表连接起来,这样就解决了哈希冲突。

链式哈希的缺陷:

随着链表长度的增加,在查询该位置上的数据的耗时就会增加,最差情况下时间复杂度为O(n)。

要想解决这一问题,就需要进行 rehash,也就是对哈希表的大小进行扩展。

rehash

在实际使用哈希表时,Redis 定义了一个 dict 结构体,这个结构体里定义了两个哈希表(ht[2]),原因就是 rehash 的时候需要两个哈希表。

渐进式 rehash

rehash 触发条件

整数集合

整数集合是 Set 对象的底层实现之一。当一个 Set 对象只包含整数值元素,并且元素数量不大时,
就会使用整数集合这个数据结构作为底层实现。

整数集合结构设计

整数集合本质上是一块连续内存空间,它的结构定义如下:

整数集合的升级操作

整数集合升级有什么好处?

整数集合支持降级操作吗?

跳表

跳表结构体

跳表节点结构体

跨度是用来干什么的?

首先明确的是,跨度与遍历操作无关,遍历操作只需要用前向指针(struct zskiplistNode *forward)就可以完成,跨度实际是为了计算这个节点在跳表中的排位。具体怎么做的呢?因为跳表中的节点都是按序排列的,那么计算某个节点排位的时候,从头节点到该节点的查询路径上,将沿途访问过的所有层的跨度累加起来,得到的结果就是目标节点在跳表中的排位

跳表节点查询过程

跳表节点层数设置

如何维持相邻两层的节点数量的比例为 2 : 1 呢?

对于跳表最高的层数,Redis 7.0 定义为 32Redis 5.0 定义为 64, Redis 3.0 定义为 32

面试题:为什么 Zset 的实现用跳表而不用平衡树(如 AVL树、红黑树等)?

Redis线程模式

Redis是单线程吗?

Redis采用单线程为什么还这么快?

Redis6.0之前为什么使用单线程?

1.官方回答:CPU并不是制约Redis性能表现的瓶颈(即使单线程的程序无法利用多核CPU),更多情况下是受内存大小和网络I/O的限制,所以Redis核心网络模型采用单线程没有问题,如果想使用服务器的多核CPU,可以在一台服务器上启动多个节点或者采用分片集群的方式。

2.使用单线程后,可维护性高,多线程可能会导致并发读写问题,增加系统复杂性,同时存在线程切换、锁带来的性能损耗。

Redis 6.0 之后为什么引入了多线程?

随着网络硬件性能提升,Redis性能瓶颈有时会出现在网络I/O处理上。为了提高网络I/O并行度,Redis6.0对于网络I/O采用多线程处理(对于命令的执行,仍然采用单线程处理)。引入多线程I/O特性对性能提升至少一倍以上。

Redis 持久化

Redis 如何实现数据不丢失?

AOF 持久化是如何实现的? 

三种写回策略优缺点:

AOF日志过大,会触发什么机制?

AOF采用文件追加方式,文件会越来越大,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF重写机制,对AOF文件的内容压缩,只保留可以恢复数据的最小指令集。

重写 AOF 日志的过程是怎样的?

触发重写机制后,主进程会创建重写AOF的子进程,重写AOF子进程会读取数据库中所有数据,并逐一把内存数据的键值对转换成一条命令,再将命令写入新的AOF文件。

问题:在重写过程中,主进程依然可以正常处理命令,如果在子进程重写AOF日志过程中,主进程修改了已经存在的 key-value,那么会发生写时复制,此时会导致主进程与子进程数据不一致,如何解决?

RDB 持久化是如何实现的呢? 

RDB 持久化是把当前进程数据生成时间点快照保存到硬盘的过程(默认保存到dump.rdb中),避免数据意外丢失(Redis默认的持久化方式)。相比于AOF日志,RDB快照记录的是实际数据,因此在Redis恢复数据时,RDB恢复数据效率更高,只需将RDB文件读入内存即可,不需要像AOF那样需要额外执行操作命令才能恢复。

RDB做快照时会阻塞线程吗?

注:Redis的快照是全量快照,也就是每次执行快照,都是把内存中所有数据都记录到磁盘中。如果太频繁,会对Redis性能造成影响;如果频率太低,服务器故障时,丢失的数据会更多。

为什么会有混合持久化?

混合持久化工作流程:

Redis的大Key对持久化有什么影响? 

如何避免大Key? 

Redis 集群

Redis 如何实现服务高可用?

主从复制

在Redis中,用户可以通过执行 SLAVEOF 命令或者设置 slaveof 选项,让一个服务器去复制另一个服务器,我们称被复制的服务器为主服务器(master),而对主服务器进行复制的服务器则被称为从服务器(slave)。进行复制中的主从服务器双方的数据库将保存相同的数据,且主从服务器之间采用读写分离的方式,主服务器只写,从服务器只读。

为什么进行主从复制?

1.读写分离,性能扩展,降低主服务器的压力

2.容灾,快速恢复,主机挂掉时,从机变为主机

如何确定谁是主服务器,谁是从服务器?

  

命令传播:

主从服务器在完成第一次同步后,双方之间就会维护一个TCP长连接,目的是避免频繁的TCP连接和断开带来的性能开销。后续主服务器可以通过这个长连接继续将写操作命令传输给从服务器,然后从服务器执行该命令,使主从一致。

分摊主服务器的压力:

从服务器也可以拥有自己的从服务器,此时该从服务器不仅可以接受主服务器的同步数据,自己也可以作为主服务器将数据同步给自己所拥有的从服务器。通过这种方式,主服务器生成RDB和传输RDB的压力可以分摊到该从服务器上。

增量复制:

如果在命令传输中,TCP长连接断开,后续又恢复正常,怎么保证主从数据一致性?

在Redis2.8之前做法是主从服务器重新进行一次全量复制,从Redis2.8开始,主从服务器采用增量复制的方式继续进行同步,即只把网络断开期间的主服务器的写操作同步给从服务器。

面试题

Redis主从节点是长连接还是短连接?

长连接

怎么判断 Redis 某个节点是否正常工作? 

主从复制架构中,过期key如何处理?

Redis 是同步复制还是异步复制?

Redis 主节点每次收到写命令之后,先写到内部的缓冲区,然后异步发送给从节点。

主从复制中两个 Buffer(replication buffer 、repl backlog buffer)有什么区别? 

为什么会出现主从数据不一致?

如何应对主从数据不一致? 

主从切换如何减少数据丢失? 

主从切换中,产生数据丢失的情况有两种:

1.异步复制导致的数据丢失

解决:对于主节点,一旦所有从节点数据复制和同步的延迟超过 min-slaves-max-lag 定义的值,此时主节点拒绝接受任何请求。对于客户端,当发现 master 不可写后,采用降级措施,将数据暂时写入本地缓存和磁盘中。待 master 恢复正常后再重新写入。

2.集群产生脑裂导致数据丢失

解决:设置配置文件中参数,如果与主节点连接的从节点数量小于指定值或者主从复制延迟超过指定值,则主节点禁止写数据。

主从如何做到故障自动切换?

由哨兵自动完成故障发现和故障转移。

哨兵模式 

为什么有哨兵机制?

哨兵机制是如何工作的? 

1.监控:哨兵每隔1秒给所有主从节点发送PING命令,如果主从节点没有在规定时间响应哨兵的PING命令,哨兵会将它们标记为主观下线。为了减少误判,会部署多个哨兵节点组成哨兵集群(最少需要三台机器组成哨兵集群)。当一个哨兵判断主节点为主观下线后,就会向其他哨兵发起命令,其他哨兵收到命令后,根据自身和主节点的网络状况,做出赞成投票或拒绝投票的响应。当这个哨兵的赞同票数达到哨兵配置文件中的 quorum 设定的值后,此时主节点被哨兵标记为客观下线。(客观下线只适用于主节点)

由哪个哨兵做故障转移?

先选举候选者:哪个哨兵判断主节点为客观下线哪个就是候选者。

候选者选举成为leader: 2.选主+通知:

主从故障转移包含以下步骤:

步骤一:选出新主节点

步骤二:将从节点指向新主节点

步骤三:通知客户端主节点已更换

步骤四:将旧主节点变为从节点

哨兵继续监视旧主节点,当旧主节点重新上线时,哨兵集群就会向它发送 SLAVEOF 命令,让它成为新主节点的从节点。至此,故障转移完成。

哨兵集群是如何组成的?

切片集群模式

哈希槽如何映射到具体的Redis节点上?

注意:如果采用手动分配哈希槽,需要把 16384 个槽都分配完,否则Redis集群无法正常工作。 

集群脑裂导致数据丢失怎么办?

什么是集群脑裂?

如何解决? 

Redis 过期删除与内存淘汰

过期删除策略

Redis是可以对key设置过期时间的,过期删除策略用于将已过期的键值对删除。

如何设置过期时间?

如果想查看某个 key 剩余的存活时间,可以使用 TTL <key> 命令。 

如果想取消 key 的过期时间,则可以使用 PERSIST <key> 命令。

如何判定 key 已过期了?

过期删除策略有哪些?

定时删除、惰性删除、定期删除

 

Redis 过期删除策略是什么? 

Redis采用惰性删除+定期删除这两种策略配合使用。

惰性删除:Redis在访问或者修改key之前,会检查key是否过期,如果过期,则删除该key,返回null给客户端;如果没过期,直接返回正常结果给客户端。

定期删除:默认每100ms进行一次过期检查(该值可在Redis配置文件中修改,默认hz 10,即每秒进行十次过期检查),每次从过期字典中随机抽取20个key(固定值),检查是否过期,删除过期的key;如果本轮检查已过期的key的超过5个(即占比超过25%),则继续抽取;如果已过期的key比例小于25%,则停止删除,等待下一轮再检查。

可见,定期删除是一个循环的过程。为了保证定期删除不会出现循环过度,导致线程卡死的现象,为此增加了定期删除循环流程的时间上限,默认不会超过25ms。

内存淘汰策略

当Redis运行内存超过最大运行内存时,就会触发内存淘汰策略删除符合条件的key,以此保障Redis的高效运行。

如何设置 Redis 最大运行内存?

Redis 内存淘汰策略有哪些?

LRU 算法和 LFU 算法有什么区别?

什么是LRU算法?

Redis是如何实现LRU算法的?

什么是LFU算法?

Redis是如何实现LFU算法的?

 

Redis 缓存设计 

什么是缓存雪崩?

大量缓存数据在同一时间过期或者Redis故障宕机时,如果此时有大量的用户请求,都无法在Redis中处理,于是全部请求都直接访问数据库,从而导致数据库压力骤增,甚至崩溃。

如何解决?

针对大量数据同时过期:

1.均匀设置过期时间:避免将大量数据设置成同一过期时间,在对缓存数据设置过期时间时,给这些数据的过期时间加上一个随机数,保证数据不会在同一时间过期。

2.互斥锁:如果发现数据不在Redis中,就加一个互斥锁,保证同一时间只有一个请求来构建缓存(从数据库读取数据,再将数据更新到Redis中),当缓存构建完成后,再释放锁。

3.监控缓存过期,提前更新

针对Redis故障宕机:

1.服务熔断或请求限流机制:服务熔断即暂停对缓存的访问,直接返回错误,不再访问数据库。

请求限流机制只将少部分请求发送到数据库进行处理。

2.构建Redis集群:当Redis主节点故障宕机,从节点切换成为主节点,继续提供缓存服务。

什么是缓存击穿?

如果缓存中某个热点数据过期了,此时大量的请求访问该热点数据,将无法从缓存中获取,直接访问数据库,导致数据库容易被高并发的请求击垮。

如何解决?

1.互斥锁

2.不给热点数据设置过期时间

什么是缓存穿透?

 如何解决?

布隆过滤器如何工作?

如何设计一个缓存策略,可以动态缓存热点数据呢?

说说常见的缓存更新策略? 

 Cache Aside策略:

Read/Write Through策略: 

 

Write Back策略:

数据库和缓存如何保证一致性?

先更新数据库,再更新缓存:

解决:

先更新缓存,再更新数据库: 

Cache Aside 策略:

该策略可以细分为读策略与写策略:

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

A请求先删除缓存,在A更新数据库之前,B请求到来,B先访问缓存,发现缓存未命中,于是访问数据库,读取数据库的值并更新到缓存,此时A更新数据库为新值,但缓存中还是旧值,造成二者不一致。所以,此策略在读写并发时,存在缓存与数据库不一致问题。

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

存在问题: 如果删除缓存失败,导致缓存中的数据还是旧值,而数据库中的数据是新值。

解决:利用消息队列进行删除的补偿。在删除缓存时,将数据加入到消息队列,由消费者从消息队列中读数据,执行删除操作,删除成功后,将数据从消息队列中移除。

Redis 实战

Redis 如何实现延迟队列?

Redis 的大 key 如何处理?

什么是 Redis 大 key?

如何查找大 key? 

1.redis-cli --bigkeys 查找大key

 2.使用 SCAN 命令查找大 key

3.使用 RdbTools 工具查找大 key

如何删除大 key?

删除操作的的本质是释放键值对所占用的内存空间,在释放内存时,操作系统会将释放的内存块插入到空闲内存块的链表中,以便后续进行管理和再分配。如果一下释放大量内存,操作空闲内存块链表时间就会增加,进而造成Redis主线程阻塞,导致其他请求无法响应。

1.分批次删除:先获取一定数量的大key,再将这些大key分批次删除。

2.异步删除:

Redis 管道有什么用?

管道技术是客户端提供的一种批处理技术,用于一次处理多个Redis命令,从而提高交互的性能。

Redis 事务支持回滚吗?

不支持。对于MySQL事务中,只要有一条命令执行失败,事务就会回滚到之前的状态,但Redis事务中,一条命令失败不会影响其他正确的命令,其他正确的命令仍然可以执行成功。

如何用 Redis 实现分布式锁的?

如何使用分布式锁?

如何解锁?

基于 Redis 实现分布式锁有什么优缺点?

优点:

1.性能高效:redis读写速度快,适合高并发的锁操作场景。

2.实现方便:可直接使用setnx方法实现。

3.避免单点故障:Redis是跨集群部署的,自然就避免了单点故障。

缺点:

1.超时时间不好设置:时间过长,影响性能;时间过短,起不到保护共享资源的目的。

2.Redis主从复制中数据是异步复制的,导致分布式锁的不可靠性:

Redis 如何解决集群情况下分布式锁的可靠性?

Redlock 算法加锁的过程?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/68248.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python学opencv|读取图像(四十二)使用cv2.add()函数实现多图像叠加

【1】引言 前序学习过程中&#xff0c;掌握了灰度图像和彩色图像的掩模操作&#xff1a; python学opencv|读取图像&#xff08;九&#xff09;用numpy创建黑白相间灰度图_numpy生成全黑图片-CSDN博客 python学opencv|读取图像&#xff08;四十&#xff09;掩模&#xff1a;三…

将 OneLake 数据索引到 Elasticsearch - 第 1 部分

作者&#xff1a;来自 Elastic Gustavo Llermaly 学习配置 OneLake&#xff0c;使用 Python 消费数据并在 Elasticsearch 中索引文档&#xff0c;然后运行语义搜索。 OneLake 是一款工具&#xff0c;可让你连接到不同的 Microsoft 数据源&#xff0c;例如 Power BI、Data Activ…

开源项目Umami网站统计MySQL8.0版本Docker+Linux安装部署教程

Umami是什么&#xff1f; Umami是一个开源项目&#xff0c;简单、快速、专注用户隐私的网站统计项目。 下面来介绍如何本地安装部署Umami项目&#xff0c;进行你的网站统计接入。特别对于首次使用docker的萌新有非常好的指导、参考和帮助作用。 Umami的github和docker镜像地…

Java程序基础⑪Java的异常体系和使用

目录 1. 异常的概念和分类 1.1 异常的概念 1.2 异常的分类 2. 异常的体系结构 3. 异常的处理 3.1 异常的抛出 3.2 异常的捕获与处理 3.3 异常的处理流程 4. 自定义异常类 4.1 自定义异常类的规则 4.2 自定义异常案例 1. 异常的概念和分类 1.1 异常的概念 在Java中&…

大话特征工程:1.维数灾难与特征轮回

一、维度深渊 公元 2147 年&#xff0c;人类文明进入了数据驱动的超级智能时代。从金融到医疗&#xff0c;从教育到娱乐&#xff0c;所有决策都仰赖“全维计算网络”&#xff08;高维特征空间&#xff09;。这套系统将全球所有信息抽象成数以亿计的多维特征&#xff08…

libOnvif通过组播不能发现相机

使用libOnvif库OnvifDiscoveryClient类&#xff0c; auto discovery new OnvifDiscoveryClient(QUrl(“soap.udp://239.255.255.250:3702”), cb.Build()); 会有错误&#xff1a; end of file or no input: message transfer interrupted or timed out(30 sec max recv delay)…

JVM常见知识点

在《深入理解Java虚拟机》一书中&#xff0c;介绍了JVM的相关特性。 1、JVM的内存区域划分 在真实的操作系统中&#xff0c;对于地址空间进行了分区域的设计&#xff0c;由于JVM是仿照真实的机器进行设计的&#xff0c;那么也进行了分区域的设计。核心区域有四个&#xff0c;…

Windows系统Tai时长统计工具的使用体验

Windows系统Tai时长统计工具的使用体验 一、Tai介绍1.1 Tai简介1.2 安装环境要求 二、下载及安装Tai2.1 下载Tai2.2 运行Tai工具 三、Tai的使用体验3.1 系统设置3.2 时长统计3.3 分类管理 四、总结 一、Tai介绍 1.1 Tai简介 Tai是一款专为Windows系统设计的开源软件&#xff…

【架构面试】二、消息队列和MySQL和Redis

MQ MQ消息中间件 问题引出与MQ作用 常见面试问题&#xff1a;面试官常针对项目中使用MQ技术的候选人提问&#xff0c;如如何确保消息不丢失&#xff0c;该问题可考察候选人技术能力。MQ应用场景及作用&#xff1a;以京东系统下单扣减京豆为例&#xff0c;MQ用于交易服和京豆服…

HTML一般标签和自闭合标签介绍

在HTML中&#xff0c;标签用于定义网页内容的结构和样式。标签通常分为两类&#xff1a;一般标签&#xff08;也称为成对标签或开放闭合标签&#xff09;和自闭合标签&#xff08;也称为空标签或自结束标签&#xff09;。 以下是这两类标签的详细说明&#xff1a; 一、一般标…

Android GLSurfaceView 覆盖其它控件问题 (RK平台)

平台 涉及主控: RK3566 Android: 11/13 问题 在使用GLSurfaceView播放视频的过程中, 增加了一个播放控制面板, 覆盖在视频上方. 默认隐藏setVisibility(View.INVISIBLE);点击屏幕再显示出来. 然而, 在RK3566上这个简单的功能却无法正常工作. 通过缩小视频窗口可以看到, 实际…

Java Web-Tomcat Servlet

Web服务器-Tomcat Web服务器简介 Web 服务器是一种软件程序&#xff0c;它主要用于在网络上接收和处理客户端&#xff08;如浏览器&#xff09;发送的 HTTP 请求&#xff0c;并返回相应的网页内容或数据。以下是关于 Web 服务器的详细介绍&#xff1a; 功能 接收请求&#…

[Computer Vision]实验二:图像特征点提取

目录 一、实验内容 二、实验过程及结果 2.1 Harris角点检测 2.2 SIFT算法 三、实验小结 一、实验内容 采用Harris与SIFT分别提取特征点及对应的描述子&#xff0c;对比两者的区别&#xff08;特征点数量、分布、描述子维度、图像变化对二者的影响等&#xff09;利用特征匹…

【AI非常道】二零二五年一月,AI非常道

经常在社区看到一些非常有启发或者有收获的话语&#xff0c;但是&#xff0c;往往看过就成为过眼云烟&#xff0c;有时再想去找又找不到。索性&#xff0c;今年开始&#xff0c;看到好的言语&#xff0c;就记录下来&#xff0c;一月一发布&#xff0c;亦供大家参考。 有关AI非…

牛客周赛 Round 78 A-C

A.时间表查询&#xff01; 链接&#xff1a;https://ac.nowcoder.com/acm/contest/100671/A 来源&#xff1a;牛客网 题目描述 今天是2025年1月25日&#xff0c;今年的六场牛客寒假算法基础集训营中&#xff0c;前两场比赛已经依次于 20250121、20250123 举行&#xff1b;而…

网安加·百家讲坛 | 樊山:数据安全之威胁建模

作者简介&#xff1a;樊山&#xff0c;锦联世纪教育能源工业互联网数字安全CSM(新能源运维师)课程特聘培训讲师&#xff0c;哈尔滨工业大学&#xff08;深圳&#xff09;信飞合创数据合规联合实验室特聘专家&#xff0c;武汉赛博网络安全人才研究中心资深专家&#xff1b;近24年…

java后端之登录认证

基础登录功能&#xff1a;根据提供的用户名和密码判断是否存在于数据库 LoginController.java RestController Slf4j public class LoginController {Autowiredprivate UserService userService;PostMapping("/login")public Result login(RequestBody User user) {…

基于SpringBoot的网上考试系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

Elastic Agent 对 Kafka 的新输出:数据收集和流式传输的无限可能性

作者&#xff1a;来 Elastic Valerio Arvizzigno, Geetha Anne 及 Jeremy Hogan 介绍 Elastic Agent 的新功能&#xff1a;原生输出到 Kafka。借助这一最新功能&#xff0c;Elastic 用户现在可以轻松地将数据路由到 Kafka 集群&#xff0c;从而实现数据流和处理中无与伦比的可扩…

【ROS2】RViz2界面类 VisualizationFrame 详解

1、简述 VisualizationFrame 继承自 QMainWindow 和 WindowManagerInterface; 窗口顶部是常规布局:菜单栏 和 工具栏 窗口中心是 RenderPanel,用来渲染3D画面 周围是dock区域,包括:DisplaysPanel、ViewsPanel、TimePanel、SelectionPanel 和 ToolPropertiesPanel Windo…