Redis面试题万字汇总 [施工中]

news2025/1/15 12:57:54

1. Redis 数据结构

Redis底层有五种数据结构,

  1. String,

  1. long / double : 底层是小于Long的数字时, 使用的时long字符.它也可以支持double类型浮点数,

  1. embstr : 如果是短字符串,长度小于39个字节, 使用的是embstr数据结构. 之所以是39字节,主要是redis的jemalloc最小单位是64个字节, 而对一个String数据结构里有一个 int len 和int free, 还有一个'/0'. 一共占用了4 + 4 + 1,此外每个对象都需要一个16位的redisObject对象. 所以总占用是64-9-16 = 39. 5.0之后的版本里因为优化了int len 和int free都改为了一个byte数据(无符号), 此外还额外增加了一个char flag数据.所以增加了4个字节, 变成了44以下使用embStr.

  1. raw : 如果是大于39个字符, 那么使用的是raw数据结构. 这个数据结构相较于embstr

  1. 应用 1 : 缓存:string 最常用的就是缓存功能,会将一些更新不频繁但是查询频繁的数据缓存起来,以此来减轻 DB 的压力。

  1. 应用 2 : 计数器:可以用来计数,通过 incr 操作,如统计网站的访问量、文章访问量等。

  1. List

  1. quicklist(3.2 之后): 基于ziplist的双向链表,quicklist的每个节点都是一个ziplist

  1. ziplist : 列表对象保存的所有字符串元素的长度都小于 64 字节并且保存的元素数量小于 512 个,使用 ziplist

  1. linkedlist (3.2 之前) : 双向循环链表

  1. 应用 1 : 消息队列:Redis 的 list 是有序的列表结构,可以实现阻塞队列,使用左进右出的方式。Lpush 用来生产 从左侧插入数据,Brpop 用来消费,用来从右侧 阻塞的消费数据。

  1. Hashs

  1. hashTable

  1. ziplist : 哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节并且保存的键值对数量小于 512 个,使用ziplist 编码;

  1. 应用 1 : 存储Java对象, 虽然String也可以存储序列化之后的java对象,但是如果是想更新某个字段, 那么往往就需要使用hash存储对象的相关属性.

  1. Set

  1. hashtable

  1. intset : 如果集合对象保存的所有元素都是整数值并且保存的元素数量不超过 512 个,则使用 intset 编码

  1. 应用 1 : 存储好友/粉丝:set 具有去重功能;还可以利用set并集功能得到共同好友之类的功能。

  1. zSet

  1. skiplist

  1. ziplist : 如果有序集合保存的元素数量小于 128 个并且保存的所有元素成员的长度都小于 64 字节,用 ziplist 编码

  1. 当ziplist作为zset的底层存储结构时候,每个集合元素使用两个紧挨在一起的 ziplist 节点来保存,第一个节点保存元素的成员,第二个元素保存元素的分值。

  1. 当skiplist作为zset的底层存储结构的时候,使用skiplist按序保存元素及分值,使用dict来保存元素和分值的映射关系。

  1. 排行榜:有序集合最常用的场景。如新闻网站对热点新闻排序,比如根据点击量、点赞量等。

redis五种数据类型,当散列类型的 value 值非常大的时候怎么进行压缩

此外, 有三种高级的数据结构 HyperLogLog, Geo、BloomFilter, 我们接下俩

1.1 跳表

  1. zset底层数据结构?简单说说跳表底层的数据结构?

  1. zset底层数据结构是zipList和skipList

  1. 跳表是在链表上每隔几个元素建立一个索引链表, 然后在索引链表上再次建立索引链表.

  1. 什么时候采用压缩列表、什么时候采用跳表呢?

  1. 当元素不超过128个, 且每隔元素大小小于64字节的时候, 使用压缩列表, 否则使用跳表

  1. 跳表的时间复杂度

  1. logN

  1. 简单描述一下跳表如何查找某个元素呢?

  1. 从最上层的索引链表开始查找, 找到第一个不大于目标元素的节点, 然后指针向下一级链表转移, 直到找到最下层的源数据链表, 向后遍历查找满足条件的元素

  1. zset为什么用跳表而不用二叉树或者红黑树呢?

  1. 红黑树的删除新增效率更低, 因为需要考虑自平衡的操作,而跳表只需要考虑链表节点的删除, 最多也就是新增删除操作k次(k为索引链表的个数)

  1. 红黑树对范围查找支持较差.

跳表的数据结构图

跳表的查找,插入, 删除(logN)

1.2 zipList

ziplist 旨在提高内存存储效率,它存储字符串和整数值, 占用一块连续的内存空间,不仅可以利用 CPU 缓存,而且会针对不同长度的数据,进行相应编码,由于每个操作都需要重新分配 ziplist 使用的内存,因此实际复杂性与 ziplist 使用的内存量有关, 这种方法可以有效地节省内存开销, 但不适用于大数量级的情况。

存储结构:

完整的 ziplist的内存结构如下:

  • zlbytes : zipList所占用空间大小)

  • zltail : 记录整个 ziplist 中最后一个 entry 的偏移量

  • zllen : 记录 entry 的数量

  • entry: 真正存数据的结构

  • preLen: 前一个entry的长度, 为了从后向前遍历用(可以理解为链表的preNode指针)

  • encoding : 编码格式, 字符串或者整数

  • entry-data : 包括当前节点的len, 当前节点的lenSize, 节点存储的内容数据等.

  • zlend : ziplist 的结束标识

zipList存储结构示意图:

我们可以很清楚的看到, zipList比起链表, 实际上更像是一个数组,它会申请一整块内存,在这个内存上存放该链表所有数据。

1. 新增元素

因为ZipList是内存紧凑的,所以新插入一个元素就需要扩展内存,Redis会调用ziplistResize方法重新申请内存空间,然后将原先的列表一次性放入新的内存空间中。

2.级联更新

entry中有保存了前一个元素的长度(prevrawlen),它是一个变长的整数,所以如果当前元素的前一个元素发生变化(例如删除),那么,当前元素的prevrawlen字段也会发生改变。当前元素的prevrawlen发生改变,那当前元素下一个元素的prevrawlen也会发生变化,这就触发了大规模的级联更新,当元素很多时,甚至会影响到Redis是否能正常对外提供服务。所以ziplist不适合存放的元素过多。

总结:为了节省内存,采用了紧凑的连续存储。所以在修改操作下并不能像一般的链表那么容易,需要从新分配新的内存,然后复制到新的空间。不能保存过多的元素,否则查询效率就会降低

1.3 SDS

dis 没有直接使用C语言传统的字符串表示, 而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将 SDS 作为默认字符串表示.

不直接使用 C字符串的原因大致下面几种:

1)C语言的字符串不记录自身长度,想要知道一个字符串的长度就必须遍历一遍字符串,复杂度为 O(N),而Redis的字符串同样使用命令 STRLEN 的时候,复杂度为 O(1)。

2)二进制安全,可以存储非文本数据的,包括视频,音频,图片等。SDS并不是像传统的C字符串(字符数组)一样,而SDS常被称作字节数组,采用以字节为单位的形式存储数据,而最后的 \0 也是一个字节,这样数据怎么样存入的,取出来的时候还是怎么样的,因此是二进制安全的。 因为在结构中定义了 len 属性,所以及时在字符串中间出现 \0 也是可以完整存储而不会被截断。

3)可以高效地执行追加操作(append),加快追加操作的速度,并降低内存分配的次数,代价是多占用了一些内存,而且这些内存不会被主动释放。

SDS 最为 Redis 最常用的数据机构,总结有下面几种原因。

1)常数复杂度获取字符串长度:O(1)。

2)避免缓冲区溢出。

3)减少修改字符串时带来的内存重分配次数。 还通过了预分配内存减少了内存重分配次数

4)二进制安全。

1.4 字典

与 Java 中的 HashMap 类似,Redis 中的 Hash 比 Java 中的更高级一些。

Redis 本身就是 KV 服务器,除了 Redis 本身数据库之外,字典也是哈希键的底层实现。

字典的数据结构如下所示:

typedefstructdict{

dictType*type;

void*privdata;

dicththt[2]; // 数据存储的地方, 也就是hash表 ,ht是hashtable的缩写

inttrehashidx;

}

typedefstructdictht{

//哈希表数组

dectEntrt**table;

//哈希表大小

unsignedlongsize;

// 表的总容量

unsignedlongsizemask;

//哈希表已有节点数量

unsignedlongused;

}

重要的两个字段是 dictht 和 trehashidx,这两个字段与 rehash 有关,下面重点介绍 rehash。

Rehash

学过 Java 的朋友都应该知道 HashMap 是如何 rehash 的,在此处我就不过多赘述,下面介绍 Redis 中 Rehash 的过程。

由上段代码,我们可知 dict 中存储了一个 dictht 的数组,长度为 2,表明这个数据结构中实际存储着两个哈希表 ht[0] 和 ht[1],为什么要存储两张 hash 表呢?

当然是为了 Rehash,Rehash 的过程如下:

  • 为 ht[1] 分配空间。修改容量操作,ht[1] 的大小为第一个大于等于 ht[0].used*2 的 2^n, 比如used = 3, 那么ht[1]需要申请8 ;

  • 将 ht[0] 中的键值 Rehash 到 ht[1] 中。

  • 当 ht[0] 全部迁移到 ht[1] 中后,释放 ht[0],将 ht[1] 置为 ht[0],并为 ht[1] 创建一张新表,为下次 Rehash 做准备。

渐进式 Rehash

由于 Redis 的 Rehash 操作是将 ht[0] 中的键值全部迁移到 ht[1],如果数据量小,则迁移过程很快。但如果数据量很大,一个 Hash 表中存储了几万甚至几百万几千万的键值时,迁移过程很慢并会影响到其他用户的使用。

为了避免 Rehash 对服务器性能造成影响,Redis 采用了一种渐进式 Rehash 的策略,分多次、渐进的将 ht[0] 中的数据迁移到 ht[1] 中。

前一过程如下:

  • 为 ht[1] 分配空间,让字典同时拥有 ht[0] 和 ht[1] 两个哈希表。

  • 字典中维护一个 rehashidx,并将它置为 0,表示 Rehash 开始。

  • 在 Rehash 期间,每次对字典操作时,程序还顺便将 ht[0] 在 rehashidx 索引上的所有键值对 rehash 到 ht[1] 中,当 Rehash 完成后,将 rehashidx 属性+1。当全部 rehash 完成后,将 rehashidx 置为 -1,表示 rehash 完成。

注意,由于维护了两张 Hash 表,所以在 Rehash 的过程中内存会增长。另外,在 Rehash 过程中,字典会同时使用 ht[0] 和 ht[1]。

所以在删除、查找、更新时会在两张表中操作,在查询时会现在第一张表中查询,如果第一张表中没有,则会在第二张表中查询。但新增时一律会在 ht[1] 中进行,确保 ht[0] 中的数据只会减少不会增加。'

疑问: --TODO
如果ht[0]的数据一直不清空, 但是ht[1]需要扩容, 这种情况如何处理

1.4 BloomFilter(布隆过滤器)

基本概念:

一种数据结构,是由一串很长的二进制向量组成,可以将其看成一个二进制数组。既然是二进制,那么里面存放的不是0,就是1,但是初始默认值都是0。

主要作用是:判断一个元素是否在某个集合中。比如说,我想判断20亿的号码中是否存在某个号码,如果直接查询DB,那么数据量太大时间会很慢;如果将20亿数据放到缓存中,缓存也装不下。这个时候用布隆过滤器最合适.

布隆过滤器是用于判断一个元素是否在集合中。通过一个位数组和N个hash函数实现。

优点:

空间效率高,所占空间小。 查询时间短。

缺点:

元素添加到集合中后,不能被删除。 有一定的误判率

应用场景:

  • 避免缓存击穿

  • web拦截器, 防止重复攻击

1.5 常见面试题

1. 各种数据结构的时间复杂度

redis 使用场景 (其实就是数据结构应用的常见场景)

  1. 缓存——热数据

  1. 计数器

  1. 队列

  1. 位操作(大数据处理)

  1. 最新列表

2. 为什么布隆过滤器存在误判率

这个和他的实现有关, 比如有2亿的数据, 他会开一个超大的位数组, 然后假设对每个元素求三次hash计算index, 将对应index的值改为1;

当判断一个是否存在的时候, 用三个hash()计算index, 如果三次arr[index] == 1都成立, 那么这个数就有可能存在. 但不是一定存在.

具体的哈希函数的数量和位数, 布隆过滤器有一个专门的函数来处理. 根据你想要的误判率和有效元素数计算.

3. Redis 如何解决 key 冲突

Redis使用拉链法解决hash冲突

2. Redis 数据淘汰,过期

1. Redis 有几种数据“过期”策略?

Redis 的过期策略,就是指当 Redis 中缓存的 key 过期了,Redis 如何处理的.

Redis 提供了 3 种数据过期策略:

  • 被动删除:当读/写一个已经过期的 key 时,会触发惰性删除策略,直接删除掉这个过期 key。

  • 主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以 Redis 会定期主动淘汰一批已过期的 key。

  • 主动删除:当前已用内存超过 maxmemory 限定时,触发主动清理策略。

在 Redis 中,同时使用了上述 3 种策略,即它们非互斥的。

2. redis.数据较多时, 有哪些主动清理策略?参考答案:相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略:voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰no-enviction(驱逐):禁止驱逐数据

3. Redis 的过期数据会被立马删除么?

并不会立马删除。Redis 有两种删除过期数据的策略:

  • 定期选取部分数据删除;

  • 惰性删除;

4. 简单描述一下定期删除的逻辑

定期删除,也就是 Redis 默认每 1 秒运行 10 次(每 100 ms 执行一次),每次随机抽取一些设置了过期时间的 key,检查是否过期,如果发现过期了就直接删除。过期的 key 超过 25%,则继续执行

不管是定时删除,还是惰性删除。当数据删除后,master 会生成删除的指令记录到 AOF 和 slave 节点。

5. Redis 为何使用近似 LRU 算法淘汰数据,而不是真实 LRU?

由于 LRU 算法需要用链表管理所有的数据,会造成大量额外的空间消耗

除此之外,大量的节点被访问就会带来频繁的链表节点移动操作,从而降低了 Redis 性能

所以 Redis 对该算法做了简化,Redis LRU 算法并不是真正的 LRU,Redis 通过对少量的 key 采样,并淘汰采样的数据中最久没被访问过的 key

Redis LRU 算法有一个重要的点在于可以更改样本数量来调整算法的精度,使其近似接近真实的 LRU 算法,同时又避免了内存的消耗,因为每次只需要采样少量样本,而不是全部数据。

6. 写一下redis设置过期时间的指令

expire [key] [EX time seconds]

# 例如: 'expire a 5' 意思就是key = a 的键值对五秒后过期.

setex [key] [EX time seconds] [ value ]

# 例如: 'setex a 5 b' 意思就是set a b 并且5s后过期

persist [key]

# 例如: 'persist a'意思就是取消掉a的过期时间

exists [key]

# 例如 'exists a' 意思就是判断key = a的是否还存在

3. Redis 持久化

1. Redis 持久化有几种类型,区别是什么?

  • a. RDB

  • 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复时是将快照文件直接读到内存中。

  • 优点:

节省磁盘空间; 恢复速度快

  • 缺点:

如果数据庞大时,比较消耗性能。

周期备份,可能会造成一定的丢失数据。

  • b. AOF

  • 日志记录写操作

  • 优点:

  • 备份机制更稳健,丢失数据更低.

  • 可读的日志文本,通过AOF,可以处理误操作.

  • 缺点:

  • 占用更多的磁盘空间

  • 恢复备份速度更慢.

优先使用AOF. 原因: AOF有能恢复更近的数据

3.1 RDB 说明

RDB存在哪些优势呢?

1). 恢复简单, 迁移方便,

2). 性能最大化。Redis唯一需要做的只是fork出子进程,之后由子进程完成持久化,可以极大避免服务进程IO操作。

3). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

RDB存在哪些劣势呢?

1). 可用性相对不高,因为RDB是定期存储, 那么宕机时基本肯定会丢失数据.

2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,但如果当数据集较大时,会导致服务阻塞。(因为回写和覆盖的时候用的是主进程)。

RDB 底层如何实现

  1. RDB fork了一个子进程,

  1. 子进程通过子进程共享主进程的内存数据将redis内存区域的数据压缩到一个临时的rdb文件中,然后进行替换原先的rdb文件,完成对新数据的持久化,快照进程结束

  1. 在子进程执行的时候回copy出一个新的内存区域B,这时候操作的数据会存放在B内存中,直到快照结束的时候才会将变更写入到原始的内存中。

  1. 主线程完成rdb文件覆盖, 内存变更会写. 如果数据量较大, 对redis的操作会被阻塞

3.2 AOF 说明

AOF的优势有哪些呢?

1). 可用性高, 备份实时性强,可读性较强

3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创 建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。

AOF的劣势有哪些呢?

1). 文件较大, 恢复较慢

2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。

3.3 持久化面试题

1. RDB和AOF是互斥关系吗, 能同时开启或关闭吗?

不是, 可以同时开启, 也可以同时关闭, redis重启后会优先选择AOF的方案, 因为AOF的数据实时性更高. 如果同时关闭的话, redis就失去了持久化能力, 就是一个纯内存数据库了.

2. AOF 文件是尾部追加(append only file), 那么文件会越来越大, Redis是如何处理这个问题的?

redis提供了AOF文件重写(rewrite)机制,即当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。

举个例子 : 调用100次INCR指令,在AOF中要存储100条指令,我们可以把这100条指令合并成一条SET指令,这就是重写机制的原理。

3. AOF 重写的逻辑说一下

  1. 在重写即将开始之际,redis会创建(fork)一个“重写子进程”,这个子进程会首先读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。

  1. 同时, 主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。

  1. 当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中。

  1. 当追加结束后,主进程就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中了。

4. Redis 事务

1. Redis 开启,回退,提交事务的命令分别是什么?

multi -- 开启事务

discard -- 取消事务

exec -- 提交

2. redis的事务不并不是完整意义上的事务,我们称之为弱事务,为什么这么说呢?

Redis 中单条命令是原子性执行的, 事务不保证原子性 , 因为redis不支持回滚这种机制

3. 为什么Redis不支持事务回滚

Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

4. redis是的事务是不支持回滚的,但是我们一定要让它回滚怎么办呢?

使用watch命令, watch在mutil命令之前使用.

watch的作用是:监控一个值是否发生变化,如果没发生改变,它会执行事务队列中的命令,提交事务;如果发生变化,将不会执行事务中的命令,同时事务回滚。最后无论是否回滚,Redis都会取消执行事务前的WATCH命令。 逻辑如下图所示.

// 用java伪代码实现的watch逻辑

watch();

multi();

try {

// 执行事务

exec();

} catch (Exceptione) {

// 回滚

discard();

} finally {

// 取消事务执行前的watch()命令.

unwatch();

}

使用watch检测balance,事务期间balance数据未变动,事务执行成功

执行失败的案例图:

5. Redis的事务隔离级别是什么?

Redis事务没有隔离级别的概念, 批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。 Redis 事务没有隔离级别的概念.

6. 那Redis的事务能保证什么?

串行化执行事务中的命令,不允许其他命令插入到事务执行中.

Redis事务的主要作用就是串联多个命令防止别的命令插队。 主要就是支持事务的隔离性.

使用watch可以保证事务执行之前元素未被改变.

7. watch是悲观锁还是乐观锁

悲观锁就是我们常说的阻塞锁, 乐观锁则是常见的version, 在更新前判断version是否满足条件.每次变更version+1.

watch不会阻塞命令执行, 他是在执行事务的时候才判断版本是否变化. 所以是乐观锁.

8. 在并发秒杀场景下, java执行watch会导致绝大多数人操作失败(一个成功, 同时已经开启watch的所有人都失败), 如何处理?

他这个太多失败主要原因是你的watch和事务相关命令是两(多)条命令, 网络带宽的时延越大, 影响失败的人越多, 所以需要我们把多个命令一次性发给redis, 这里就需要使用lua脚本了. 使用脚本来执行秒杀逻辑, 会大大减少网络带宽的一个影响, 尽可能减少失败/成功的比例.

5. Redis 主从复制

1. 主从复制的作用有哪些?

主从复制的作用主要包括:

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

  1. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。

  1. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。

  1. Redis高可用的基础:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

2. 主从复制的原理

主从复制包括了连接建立阶段、数据同步阶段、命令传播阶段;其中数据同步阶段,有全量复制和部分复制两种数据同步方式;命令传播阶段,主从节点之间有PING和REPLCONF ACK命令互相进行心跳检测。

主从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。

主从复制主要有三个阶段

  1. 建立连接阶段, 以从节点为主, 建立socket连接,并确认socket和主节点的状态;

  1. 数据同步阶段, 以主节点为主, 生成并将rdb文件发送给从节点, 然后将复制缓冲区的内容也发送给从节点;

  1. 命令传播阶段, 这一阶段主节点将写入命令发送到从节点, 并将命令写入复制缓冲区.

2.1 建立连接阶段分为那些步骤?

  1. 从节点保存主节点的ip和port. 可以选择配置文件, 命令行两种方案.

  1. 从节点建立socket连接, 把自己作为客户端挂载到主节点上

  1. 通过ping命令校验socket连接

  1. 如果从节点设置了masterauth, 那么通过发送auth命令.

2.2 数据同步节点分为那些步骤?

  1. 主节点根据复制缓冲区判断是需要全量复制,还是部分复制, 判断来源是复制缓冲区的内容

  1. 主节点启动bgsave命令

  1. 主节点将rdb文件发送给从节点

  1. 从节点执行rdb后, 主节点会将复制缓冲区的内容也发给从节点

  1. 如果从节点有aof的话, 会执行bgrewriteaof命令, 保证aof文件的实时性.

2.3 数据同步分为全量和部分同步, 简单介绍一下如何判断采用那种逻辑

只有当从节点发起部分同步并且主节点通过复制偏移和复制缓冲区判断可以进行部分同步时, 才会采用部分同步.不然都采用全量同步;具体逻辑见下图

Redis 2.8 之后提供部分同步主要是为了解决网络超时断开的问题.

2.4 在命令传播阶段, 心跳机制的作用是什么, 是如何实现的

每隔指定的时间,主节点会向从节点发送PING命令(主要是为了让从节点进行超时判断),从节点会向主节点发送REPLCONF ACK命令. 后者主要是

  1. 实时监控网络状态;

  1. 检测命令丢失, 如果丢失则使用偏移量和复制缓存挤压区来重发命令

3. 主从复制应用中存在的问题

(1)延迟与不一致问题

有网络时延的存在, 所以延迟问题不可避免, 主要是通过优化网络带宽,机房位置来处理.

(2)数据过期问题

因为Redis的数据过期并不是实时的, 所以从服务上可能还会访问到过期的数据, 解决方案是升级版本到3.2以上.

(3)故障切换问题

不能自动处理主节点故障场景. 需要手动实现或引入Redis哨兵

4. 复制缓冲区和复制挤压缓冲区的区别?

复制缓冲区是客户端输出缓冲区的一种,主节点会为每一个从节点分别分配复制缓冲区;而复制积压缓冲区则是一个主节点只有一个,无论它有多少个从节点。

5. 为什么主从复制架构的Redis存储能力受单机限制?

6. Redis 哨兵

1. Redis 哨兵的作用是什么? 或者说为了解决什么问题?

在复制的基础上,哨兵实现了主节点的自动故障转移,保证Redis的高可用。

缺陷:写操作无法负载均衡;存储能力受到单机限制的问题; 哨兵无法对从节点进行自动故障转移,需要我们对从节点做额外的监控、切换操作。

2. 哨兵节点的工作是什么?

  1. 日常工作就是监听其他节点的心跳, 判断是否需要故障转移

  1. 如果某个节点连接不上, 该哨兵会判断其'主观下线'

  1. 主观下线后, 如果判断其是Redis 主节点, 那么会联系其他Redis节点进行协商,当主观下线比例超过某个值时, 开始故障转移

  1. 故障转移1: 哨兵投票选出leader

  1. 故障转移2: leader在从节点中选择新的主节点, 更新主从状态, 将已下线的主节点设置为从节点.

3. 哨兵是如何投票选出leader的?

采用的是先到先得, 每个节点先收到其他那个节点的leader申请,就会投票给他. 这里需要注意哨兵节点的个数应该是奇数,保证一定能选出leader.

4. 哨兵leader在故障转移时如何选择新的主节点?

  1. 首先过滤掉不健康的从节点;

  1. 然后选择优先级最高的从节点(由slave-priority指定);

  1. 如果优先级无法区分,则选择复制偏移量最大的从节点;

  1. 如果仍无法区分,则选择runid最小的从节点。

5. 哨兵节点监听其他节点的方式有哪些?

  1. 对于主从节点,使用定期ping

  1. 对于其他哨兵, 通过发布订阅功能获取其他哨兵节点的信息;

7. Redis 集群

10.1.8 是否使用过Redis集群,集群的原理是什么?参考答案:Redis Sentinel着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

主从或者集群架构中,两台机器的时钟严重不同步,会有什么问题么?

key 过期信息是用 Unix 绝对时间戳表示的。

为了让过期操作正常运行,机器之间的时间必须保证稳定同步,否则就会出现过期时间不准的情况。

比如两台时钟严重不同步的机器发生 RDB 传输, slave 的时间设置为未来的 2000 秒,假如在 master 的一个 key 设置 1000 秒存活,当 Slave 加载 RDB 的时候 key 就会认为该 key 过期(因为 slave 机器时间设置为未来的 2000 s),并不会等待 1000 s 才过期。

其他常见问题

1. 你了解Redis吗?

在单机版下的Redis就是一个大号的HashMap,拥有超时缓存功能, 自动写入磁盘等功能的一个键值对缓存.在分布式下的Redis则更像Java应用程序对操作系统的内存系统的统一调度接口.

2. redis为什么快?

  1. 纯内存操作

  1. 单线程, 使用 IO多路复用模型,非堵塞IO。多路是指多个网络连接,复用是指使用一个线程进行处理。

  1. 高效的数据结构, 合并的编码类型.

4. 使用Redis有哪些好处?

(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)(2) 支持丰富数据类型,支持string,list,set,sorted set,hash(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

4、Redis为什么使用单线程?

它在内存中执行的操作耗时很快,以至于多线程带来的收益小于其上下文切换和锁管理的消耗。

1、集群如何同步会话状态

redis集群的理解,怎么动态增加或者删除一个节点,而保证数据不丢失。(一致性哈希问题)

Redis 的一致性哈希算法

10.1.5 Redis 常见的性能问题都有哪些?如何解决?

参考答案:

  1. Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

  1. Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

  1. Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。

  1. Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

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

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

相关文章

深度估计源码详解

源码链接见文末 论文地址: Monocular Depth Estimation Using Laplacian Pyramid-Based Depth Residuals | IEEE Journals & Magazine | IEEE Xplore 1.项目环境配置 项目中所包含的库直接使用pip install就好,但是有3个地方需要处理一下: fcntl,这个需要打开anacon…

DFS(六) N皇后 II

n 皇后问题 研究的是如何将 n 个皇后放置在 n n 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。 来源:力扣(LeetCode) 链接:https://leetcode.cn/pr…

浮动 应用场景 浮动的基本特点 高度坍塌 解决浮动时盒子冲突问题

目录浮动应用场景浮动的基本特点盒子尺寸盒子排列文字环绕高度坍塌浮动 视觉格式化模型,大体上将页面中盒子的排列分为三种方式: 常规流浮动定位 应用场景 文字环绕横向排列 浮动的基本特点 修改float属性值为: left:左浮动…

【HBase入门】6. 常用 Shell 操作(3)

前言 我们可以以shell的方式来维护和管理HBase。例如:执行建表语句、执行增删改查操作等等。 过滤器的用法 过滤器一般结合scan命令来使用。打开HBase的JAVA API文档。找到RowFilter的构造器说明,我们来看以下,HBase的过滤器该如何使用。 …

快速排序的实现和优化~

相比于冒泡排序的改进点: 在前面学过的冒泡排序中,由于扫描过程只对相邻的两个元素进行比较,因此在互换两个相邻元素时,只能消除一个逆序,如果能通过两个(不相邻的)元素的交换,消除待排序记录 中的多个逆序…

docker desktop window10家庭版踩坑实录

安装 桌面版:https://www.docker.com/products/docker-desktop 这里我就安装的是桌面版 选择windows 前置工作 1.按下 wins(找到这个) 将下面的这个勾选中,如果你是家庭版很可能没有这个东西,那么请看我的这篇文章…

5-5中央处理器-指令流水线

文章目录一.基本概念1.多条指令在处理器中的执行方式(1)顺序执行方式/串行执行方式(2)流水线执行方式①一次重叠执行方式②二次重叠执行方式2.流水线的表示方法(时空图)3.超标量流水线二.分类1.部件功能级、…

第四十五章 动态规划——背包问题模型(二)

一、概述 我们在上一章中已经对背包模型做了一定地讲解,但是我们发现其实在上一章节中我们所介绍的例题大部分是给背包问题套上一个背景,当我们识破了背后的模型后,我们就可以直接套用模板,基本不需要对代码做改变。 那么在这一…

SpringBoot读写Redis客户端并实现技术切换(Jedis)

SpringBoot整合Redishttps://blog.csdn.net/weixin_51882166/article/details/128759780?spm1001.2014.3001.5501 读写客户端 首先应该打开redis服务; cd命令进入Redis安装目录下: 进入Redis客户端: redis-cli.exe -h 127.0.0.1 -p 6379…

梯度下降算法有哪些?有什么区别?【背景、原理、公式、代码】

一、梯度下降算法背景 梯度下降是迭代法的一种,可以用于求解最小二乘问题(线性和非线性都可以)。在求解机器学习算法的模型参数,即无约束优化问题时,梯度下降(Gradient Descent)是最常采用的方法之一,另一种常用的方法是最小二乘法。在求解损失函数的最小值时,可以通过梯…

行为型模式-职责链模式

1.概述 在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同…

记一段相亲反思

记一段相亲反思项目系统启动项目相亲需求的细分高净值人群特定类型的高预期结婚结婚前的彩礼引流系统启动流量,从哪里来?作弊避险,什么钱不能赚?这不是一篇找对象的文章,而是帮别人找对象来赚钱的文章。 项目系统 启…

洛谷-P2114 [NOI2014] 起床困难综合症

题目链接: P2114 [NOI2014] 起床困难综合症 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述: 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳。作为一名青春阳光好少…

Bayesian Personalized Ranking from Implicit Feedback 阅读笔记

Abstract BPR主要用于基于隐式反馈(implicit feedback)的Item Recommendation。 尽管有很多做同样事情的算法比如matrix factorization, knearest-neighbor。但他们并不是直接对于物品排名本身进行预测的。 而BPR则是通过贝叶斯分析得到最大的后验估计量来预测排…

基于蜣螂算法优化概率神经网络PNN的分类预测-附代码

基于蜣螂算法优化概率神经网络PNN的分类预测 - 附代码 文章目录基于蜣螂算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立3.基于蜣螂优化的PNN网络5.测试结果6.参考文献7.Matlab代码摘要:针对PNN神经网络的光滑因…

[GYCTF2020]EasyThinking (ThinkPHP V6.0.0)

[GYCTF2020]EasyThinking 打开以后就注册一些功能,注册admin admin,成功然后尝试search这个方法是否有任意文件读取漏洞,试了试没有任何的回显。 然后个人中心,显示的是自己的历史命令 接下来,呃呃呃就没思路了&…

DFS(五)N皇后

51. N 皇后 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案…

★ 我的世界各类奇葩武器实现!(命令方块1.13+)

新版execute一出很多玩家都不会了。开头先给大家说一下怎么以旧换新: e.g. 旧版: /execute e[typearrow] ~ ~ ~ summon tnt 新版就改为: /execute at e[typearrow] run summon tnt 非常简单! 注记 以下代码块里的命令未经表明一…

Mysql入门技能树-数据类型

数值的隐式类型转换 Joe 需要使用下列表做一项数值计算 create table points(id int primary key auto_increment,x int,y int );计算查询为: select id, (x^2 y^2)/2 as result from points; 得到的结果集中,result 列的类型应该是: 答…

剑指Offer 第1天 第2天

第 1 天 栈与队列(简单) 剑指 Offer 09. 用两个栈实现队列 class CQueue { public: CQueue() {} void appendTail(int value) { s1.push(value); } int deleteHead() { while(!s1.empty()) { …