1 数据类型及底层数据结构
1.1 string、hash、list、set、zset
1.2 GEO
redis GEO 类型原理及命令详解
Redis系列9:Geo 类型赋能亿级地图位置计算
1.3 HyperLogLog
1.4 命令scan
redis系列——scan机制:高位进位加法
redis使用scan count 返回数量不准确
1.5 其它常用命令
2 Redis的应用场景
3 穿透、击穿、雪崩
3.1 穿
3.2 击穿
3.3 雪崩
解决方案:
- 给不同的Key的TTL添加随机值,将缓存失效时间分散开
- 永不过期
- 利用Redis集群提高服务的可用性,Redis的哨兵模式和集群模式,为防止Redis集群单节点故障,可以通过这两种模式实现高可用
- 给业务添加多级缓存,比如:使用nginx缓存+redis缓存+其他缓存,不同层使用不同的缓存,可靠性更强
- 缓存预热:不要等到请求到来再去查询数据库存入缓存,可以提前将数据存入缓存。使用缓存预热机制通常有专门的后台程序(例如定时任务)去将数据库的数据同步到缓存。
- 熔断降级:熔断(服务异常后,阻止上游服务调用该服务)和降级(上游服务远程调用发现下游熔断后,执行后备方法)计算机编程杂识–9–限流、熔断、降级
4 过期删除策略
Redis–基础知识点–26–过期删除策略 与 淘汰策略 中1
5 淘汰删除策略
即 Redis回收策略 有哪些
Redis–基础知识点–26–过期删除策略 与 淘汰策略 中2
6.1 淘汰策略其它问题
6.1.1 数据库有1000万数据,Redis只能缓存20w数据,如何保证Redis中的数据都是热点数据 ?
高并发下千万数据量的Mysql中热点数据如何持续保留在Redis中
6.1.2 Redis的内存用完了会发生什么
主要要看淘汰策略配置的什么。对于写操作来说,如果没有配置淘汰策略或 maxmemory=0[无内存限制],导致内存溢出,redis进程会崩掉;如果配置了noeviction,会直接写失败;如果配置了其它策略会根据相应策略淘汰数据,并将新数据写进去。对于读操作的话如果读取的数据在内存中会成功,不在内存中的数据也需要业务程序从mysql中获取相应的数据,并更新到redis内存中,此时的情况就跟写操作情况是一样的。
7 Reids持久化机制
该部分 的 问题目录与Redis–基础知识点–17–rdb_aof 一样
7.1 RDB
7.1.1 RDB 是什么
7.1.2 开启关闭RDB
7.1.3 RDB 触发机制
7.1.4 RDB 执行原理7
7.1.5 RDB记的快照内容
7.2 AOF
7.2.1 AOF 是什么
7.2.2 开启关闭AOF
7.2.3 AOF 触发机制[刷盘机制]
7.2.4 AOF 重写机制
7.3 RDB 与 AOF 对比
7.4 混合模式
7.5 适用场景
7 Redis性能
7.1 Redis 为什么采用单线程不采用多线程
往往采用多线程的原因是性能瓶颈在I/O,导致不能更好的利用cpu,而redis 是基于内存的,不存在I/O瓶颈;
使用了多线程反而存在锁的获取、释放 与 上下文切换 反而会消耗更多的资源影响性能。
7.2 Redis 单线程为什么还这么快
即:Redis为什么能扛住百万QPS?
- 基于内存:Redis是基于内存的,内存的读写速度非常快;
- 上下文切换:单线程避免了不必要的上下文切换和竞争条件;
- IO多路复用:底层采用NIO(非阻塞IO),NIO采用IO多路复用技术,一个线程通过多路复用器处理多个连接。
- 高效数据结构:比如跳表查询复杂度O(logN)
7.3 Redis 的瓶颈
- 内存:因为读写在内存中进行,内存大小会影响Redis性能。可以通过加内存、读写分离优化性能。
- 网络带宽:网络 IO是Redis最大瓶颈,也就是客户端和服务端之间的网络传输延迟。Redis6.0引入了网络IO多线程模型,提高了性能瓶颈。
Redis6.0 引入多线程?
7.4 Redis是单线程的,如何提高多核CPU的利用率?
可以在同一个服务器部署多个 Redis 的实例,并把他们当作不同的服 务器来使用,在某些时候,无论如何一个服务器是不够的, 所以, 如果你想使用多个 CPU,你可以考虑一下分片(shard)。
7.5 如何优化Redis性能和内存使用
https://cloud.tencent.com/developer/techpedia/1572
7.6 Redis为什么性能比Mysql快那么多
- 基于内存的操作:Redis将所有数据存储在内存中,而MySQL主要依赖于磁盘存储。内存的读写速度远高于磁盘。
- 数据结构与访问模式:Redis支持多种简洁的数据结构,对于键值对类型的数据访问来说,时间复杂度通常是O(1)。而MySQL使用B+树作为索引结构,查找操作的时间复杂度通常是O(logn)。
- 单线程模型与多路复用:Redis使用单线程模型处理客户端请求,通过I/O多路复用技术高效地管理多个连接,避免了多线程切换带来的开销。
- 无事务和SQL解析开销:Redis没有复杂的SQL解析、优化及事务处理逻辑,使得数据操作更为直接快速。
8 锁
8.1 分布式锁
8.1 分布式锁原理
8.1.2 看门狗实现原理
自动续期:
- 当一个线程成功获取锁后,会为该锁设置一个初始的有效期(例如 30 秒)。
- 看门狗会启动一个后台线程,定期(通常是锁有效期的一半时间)发送命令给 Redis,以自动延长锁的过期时间。只要持有锁的线程仍在运行且未显式释放锁,锁的有效期将被持续延长。
锁释放:
- 当持有锁的线程完成任务后,显式调用 unlock 方法释放锁。
- 释放锁后,看门狗停止续期操作。
异常处理:
- 如果持有锁的线程因异常终止,看门狗将不再续期锁的有效期,锁会在其原始过期时间后自动释放,避免死锁。
8.1.3 Redis 锁保证原子性为什么用lua脚本,不用事务
原因:lua脚本可以写复杂的逻辑,而事务不行。一个线程在释放锁时需要有判断逻辑[if 语句],判断是不是自己获取到的锁,lua脚本可以,事务就不可以。
8.2 红锁
了解即可,一般不会用
【redis】redis实现红锁
8.3 可重入锁
9 双写一致
目的:保证缓存和数据库中数据的最终一致性
9.1 对于缓存应该使用删除还是更新
- 1 更新缓存比删除缓存更耗费性能,尤其对于复杂的结构的数据
- 2 站在懒加载的角度,更新的数据不一定会马上被访问,既然如此,不如不做,等待其它读操作在需要的时候再来进行缓存重建即可,这样既提高性能,还提高了程序的运行效率。
9.2 方案一:延时双删
9.2.1 原理
- 1 先删除缓存
- 2 更新数据库
- 3 等待一段时间删除缓存
9.2.2 步骤1 第一次删除缓存的意义是什么
Redis 延时双删的第一个删除操作是不可省略的,它是为了保证数据一致性,让老数据尽快失效,避免用户拿到过期数据。延时再删是为了进一步确保缓存里没有脏数据。这两个操作相辅相成,缺一不可。
9.2.3 步骤3 为什么需要等待一段时间删除缓存
避免以下场景:线程1删除缓存,接着去请求更新数据库,但该请求发生了网络延迟;此时线程2去从缓存读数据,发现缓存中没有数据,然后去数据库中读数据,读的是旧数据,完了之后请求将读到的数据写到缓存中,但此时又发生了网络延迟;此时线程1 请求更新数据库的请求到达并更新数据库后,并请求拿到更新后的数据,然后不等待直接删除缓存并将最新数据添加到缓存;此时线程2 请求到达缓存将读到旧数据又写到了缓存。
这种情况导致 缓存与数据库中的数据不一致。所以延时双删第三步需要等待一段时间再去删除缓存并添加到缓存,即线程1等待线程2先将旧数据到更新到缓存后,线程1再去删除缓存并将新数据添加到缓存。这样就能最大程度保持缓存与数据库最终一致。
为什么说最大程度保持缓存与数据库一致?因为如果缓存和数据库负载很高,主从同步很慢,很有可能不能在延时的时间内实现同步。
9.2.4 步骤3 等待一段时间删除缓存的休眠等待时间应该设置多久
太短了,可能并发写操作还没完,老数据还会被写回缓存;太长了,影响系统性能,用户体验不好。所以,得找个平衡点。
这个休眠时间 = 读业务逻辑数据[从数据库读数据]的耗时 + 回写缓存时间 + 几百毫秒。
9.3 方案二:先更新数据库 再删除缓存
9.3.1 原理
- 1 先更新数据库
- 2 删除缓存并将新的数据添加到缓存中
9.4 两种方案中删除缓存失败时怎么处理
延时双删第一次删除缓存失败:即停止继续执行,可以直接给客户端返回相应的报错
延时双删 第二次删除缓存失败 和 先更新数据库再删除缓存 删除缓存失败 可以采用重试的方案。
具体删除及重试删除方案缓存:浅谈双写导致的数据一致性问题 中四,这两种方案其实都是异步删除。即 延时双删方案中也就不要考虑延时的问题了。
9.5 两种方案的适用场景
| 方案 | 优点 | 缺点 | 实现复杂度 | 适用场景 |
|---|---|---|---|---|
| 先更新数据库后删除缓存 | 减少了一次缓存删除的开销 | 在数据库更新期间,读取请求可能读取到失效的缓存数据 | 简单 | 数据一致性要求较低、对性能要求较高的场景 |
| 延时双删 | 保证了数据一致性,读取请求不会读取到失效的缓存数据 | 需要进行两次缓存删除操作,增加了一定的资源开销 | 复杂 | 数据一致性要求较高的场景,同时对性能影响有一定容忍度的场景 |
10 Redis 事务
10.1 事务特点
- 批量操作在发送 EXEC 命令前被放入队列缓存。
- 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
- 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
10.2 事务相关命令
MULTI: 开始事务,命令入队(批量操作 Redis 的命令,先进先出(FIFO)的顺序执行)
EXEC:执行所有事务块内的命令
WATCH: 监视一个(或多个) key ,如果在事务EXEC执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断,不会执行
UNWATCH: 取消 WATCH 命令对所有 key 的监视。
DISCARD: 取消事务,放弃执行事务块内的所有命令。
10.3 事务是否满足ACID
原子性(Atomicity): 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- 不支持,1 事务中的某一条命令执行失败时其它命令仍会继续执行;2 没有回滚机制。也就是说有的命令起作用了有的命令不起作用,所以不支持原子性。
隔离性(Isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
- 支持,事务的操作不被其他用户操作所打断;watch 保证事务命令的隔离性;lua脚本满足隔离性;
持久性(Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
- redis只有在 aof 持久化策略的时候,并且需要在 redis.conf 中 appendfsync=always 才具备持久性;实际项目中几乎不会使用 aof 持久化策略;
一致性(Consistency): 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
- 不支持,事务使数据库从一个一致性状态到另外一个一致性状态;这里的一致性是指预期的一致性而不是异常后的一致性;当redis 执行事务时有一条命令执行失败,其它命令仍会执行,因此不能保证一致性
11 慢查询
线上阻塞如何排查 及 慢查询如何排查
Redis–基础知识点–28–慢查询相关中有以下几个问题的详细介绍
11.1 慢查询的原因
11.2 慢查询排查方案
11.3 慢查询解决方案
12 pipline
13 大Key
Redis 大 Key:别让你的 Redis 变成“胖子”! 中以下几个问题都有,目录一致
13.1 什么是大Key
13.2 什么情况下会导致大 Key
13.3 大 Key 问题会带来什么危害
13.4 如何识别大 Key
13.5 解决大 Key 问题的方案
14 Redis是AP还是CP
15 Redis内存溢出场景及解决策略有哪些
15.1 Redis内存泄漏的场景有哪些
- 1 键的过期时间设置不合理
16 部署方案
16.1 主从模式
16.1.1 优点
Redis–基础知识点–22–实战:docker 搭建 redis 的单机模式/主从模式/哨兵模式/集群模式 中2.1.2
16.1.2 缺点
Redis–基础知识点–22–实战:docker 搭建 redis 的单机模式/主从模式/哨兵模式/集群模式 中 2.1.3
16.1.3 原理
即 主从全量复制的流程
Redis主从复制原理 中
16.1.4 增量复制
16.1.5 断点续传
断点续传是什么?
断点续传原理是什么?
Redis主从复制原理 中
16.1.6 无磁盘化复制
16.1.7 主从复制的特点
16.1.8 master开启持久化对主从架构的安全意义
16.1.9 过期key的处理
16.1.10 主从数据一致性怎么保证
- 1 主从复制的流程[首次全量、增量复制]
- 2 断点续传的原理
- 3 主从异步复制
16.2 哨兵模式
16.2.1 优点
Redis–基础知识点–22–实战:docker 搭建 redis 的单机模式/主从模式/哨兵模式/集群模式 中3.1.2
16.2.2 缺点
Redis–基础知识点–22–实战:docker 搭建 redis 的单机模式/主从模式/哨兵模式/集群模式 中3.1.3
16.2.3 原理
即哨兵模式故障恢复流程
Redis–基础知识点–22–实战:docker 搭建 redis 的单机模式/主从模式/哨兵模式/集群模式 中3.1.4
16.2.4 哨兵模式脑裂问题如何解决
16.3 集群模式
16.3.1 优点
Redis–基础知识点–22–实战:docker 搭建 redis 的单机模式/主从模式/哨兵模式/集群模式 中4.1.2
16.3.2 缺点
Redis–基础知识点–22–实战:docker 搭建 redis 的单机模式/主从模式/哨兵模式/集群模式 中4.1.3
16.3.3 原理
其实就是讲解一下普通哈希、一致性哈希、哈希槽,然后为什么用哈希槽不用一致性哈希
Redis–基础知识点–22–实战:docker 搭建 redis 的单机模式/主从模式/哨兵模式/集群模式 中4.1.4 的 [普通哈希、一致性哈希、哈希槽]
16.3.4 哈希槽数量为什么是16384
即:CRC16 算法,产生的hash值有 16 bit 位,可以产生 65536(2^16)个值 ,也就是说值分布在 0 ~ 65535 之间,这时候,疑问来了,槽位总数为什么是 16384 ?65536 不可以吗?
原因:
- 1 心跳数据包大小以及网络带宽
在Redis的集群中,每个槽位的状态信息需要进行记录以维护槽位的分配情况。这些状态信息通常使用位图来表示,其中每个槽对应一个位,用于表示该槽的状态。每个位只占用一个比特(bit),因此需要将插槽数除以8,将位的数量转换为字节(byte)的数量,以计算所需的空间大小。
因此,如果有16384个插槽,每个插槽的状态需要占用16384个比特,即16384 / 8 = 2048字节,即2KB的空间。同理,如果有65536个插槽,则需要65536 / 8 = 8192字节,即8KB的空间
因为Redis每秒都会发送一定数量的心跳包,如果消息头是8k,未免有些太大了,浪费网络资源。 - 2 redis集群的节点个数,基本不会超过1000
集群节点越多,心跳包的消息体携带的数据越多,如果节点超过1000个,也会造成网络的拥堵,对于节点数在1000个以内的redis集群,16384个槽位足够用了
16.3.5 Redis为什么使用哈希槽而非一致性哈希算法?
Redis 哈希槽(Hash Slot)与一致性哈希环(Consistent Hashing)核心对比中 5
16.5 Redis高可用的机制有哪些
- 持久化:持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
- 复制:复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
- 哨兵:哨兵实现了主从复制中故障的自动化恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。
- 集群:通过集群,解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。
17 Redis 分区
17.1 Redis为什么要分区
Redis面试题 中 44
17.1 Reids分区方案有哪些
面试官问Redis分区,要明确是问分区方案有哪些,还是问集群模式分区为什么用哈希槽而不用普通哈希和一致性哈希
Redis面试题 中 45
17.2 分区的缺点有哪些
Redis面试题 中 46
该缺点也是redis集群模式的缺点,集群模式是redis自身的一种分区机制 即 本文16.3.2的答案
18 Redis 其它问题补充
可以参考 Redis面试题 ,这篇文章中的大部分问题跟此博客是重复的,也有一些其它问题。可以互相补充。
1424






