1. Redis 是做什么的?即在哪些场景下使用?
核心概念: Redis 是一个基于内存的、键值对存储的 NoSQL 数据库,以其极高的性能、丰富的数据结构和强大的功能而闻名。
主要应用场景:
- 缓存:这是最核心、最广泛的使用场景。将热点数据存放在 Redis 中,减少对后端数据库(如 MySQL)的直接访问,极大提升应用响应速度和承载能力。
- 会话存储:将 Web 应用的分布式会话(Session)集中存储在 Redis 中,解决了单服务器会话无法共享的问题,是实现应用水平扩展的常用手段。
- 消息队列:利用 Redis 的
List(阻塞操作)、Pub/Sub(发布/订阅)或Stream(5.0版本后,最专业)数据结构,实现简单的异步任务队列、消息广播等。 - 排行榜/计数器:利用
ZSet(有序集合)可以轻松实现实时排行榜。利用String类型的INCR/DECR命令实现高并发下的计数器(如微博阅读量、点赞数)。 - 实时系统:如实时监控、实时数据分析、实时反作弊系统,利用 Redis 的高吞吐和低延迟特性进行实时数据处理。
- 社交关系:利用
Set(集合)的交并差操作,可以方便地实现共同关注、共同好友等功能。 - 分布式锁:利用
SET key value NX PX timeout命令可以实现一个简单的分布式锁,用于控制分布式系统对共享资源的并发访问。
2. 如果监控 Redis 是否出现故障?
一个全面的 Redis 监控体系应包括:
- 基础资源监控:
- CPU 使用率:持续过高可能表示存在复杂查询或 RDB/AOF 持久化。
- 内存使用率:监控
used_memory和maxmemory,防止内存耗尽触发 OOM 或逐出策略。 - 网络带宽:监控输入/输出流量,判断是否存在瓶颈。
- 磁盘 I/O:特别是开启 AOF 时,磁盘性能会影响 Redis 的写入性能。
- Redis 关键指标监控:
- 连接数 (
connected_clients):连接数突增可能意味着客户端连接泄漏。 - 阻塞客户端数 (
blocked_clients):数量大于 0 表示有客户端因BLPOP等命令被阻塞,需检查。 - Key 空间信息 (
keyspace_hits,keyspace_misses):命中率低可能表示缓存失效或设计不合理。 - 持久化状态:
rdb_last_bgsave_status/aof_last_bgrewrite_status:检查上次 RDB/AOF 重写是否成功。aof_last_write_status:检查上次 AOF 写入是否成功。
- 复制状态 (
master_link_status,slave_repl_offset):在主从架构中,监控主从连接状态和复制延迟。 - Keyspace 命中率:
keyspace_hits / (keyspace_hits + keyspace_misses),命中率过低需要考虑缓存有效性。
- 连接数 (
- 服务可用性监控:
- 定期 PING:通过向 Redis 实例发送
PING命令,检查其是否响应PONG,这是最基本的存活检查。 - 慢查询监控:通过
slowlog get命令获取慢查询日志,分析性能瓶颈。
- 定期 PING:通过向 Redis 实例发送
3. Redis客户端timeout报错突然增加,排查思路是怎样的?
这是一个典型的性能问题,排查思路应由浅入深:
- 检查 Redis 服务端状态:
- 资源瓶颈:使用
info命令查看 CPU、内存使用率是否达到瓶颈。 - 慢查询:使用
slowlog get检查是否有大 Key 或复杂命令阻塞了服务端,导致后续命令排队超时。 - 持久化影响:检查是否正在执行
BGSAVE或BGREWRITEAOF,这两个操作会 fork 子进程,可能导致主进程短暂阻塞(尤其内存越大,fork 耗时越长)。
- 资源瓶颈:使用
- 检查网络:
- 网络延迟/丢包:使用
ping/traceroute检查客户端与 Redis 服务器之间的网络状况。 - 连接数:检查
connected_clients是否达到maxclients上限,导致新连接被拒绝。
- 网络延迟/丢包:使用
- 检查客户端:
- 客户端资源:检查客户端应用服务器本身的 CPU、内存、网络是否正常。
- 连接池:检查客户端连接池配置是否合理(如最大连接数过小),或者是否存在连接泄漏(获取连接后未释放)。
- 业务逻辑:检查是否有突发的高并发请求,或者是否执行了
KEYS *等危险命令。
4. 请简单描述pipeline功能,为什么pipeline功能会提升redis性能?
- 是什么:Pipeline 是一种客户端技术。它将多个 Redis 命令打包,一次性发送给服务器,然后再将服务器返回的所有响应一次性读取回来。
- 为什么能提升性能:
- 减少网络往返时间:在不使用 Pipeline 时,每条命令都需要经历“发送->等待->接收”的循环,RTT 占了大部分时间。Pipeline 将 N 条命令的 N 次 RTT 缩减为 1 次。
- 降低系统调用开销:减少了
read()和write()系统调用的次数。
注意:Pipeline 中的命令在服务器端仍然是串行执行的,并非原子操作。如果需要原子性,应使用事务(MULTI/EXEC)。
5. 本地redis-client访问远程Redis服务出错,说出几种常见的错误?
- 连接被拒绝
Connection refused:远程 Redis 服务未启动,或防火墙/安全组阻止了访问。 - 认证失败
NOAUTH Authentication required:配置了密码,但客户端未提供或提供了错误的密码。 - 超过最大连接数
ERR max number of clients reached:Redis 服务器的客户端连接数已达到maxclients配置的上限。 - 命令不存在
ERR unknown command:客户端发送的命令在该 Redis 版本中不支持。 - 内存不足
OOM command not allowed when used memory > 'maxmemory':Redis 内存已满,且配置的逐出策略无法释放更多内存。 - 网络超时
Read timed out/Connection timed out:网络延迟高或丢包严重,或服务端因持久化等原因阻塞。
6. key-value的大小超大或单key的qps超高,会对Redis本身造成什么样的影响、会对访问Redis的其他客户端造成什么样的影响?
- 大 Key 的影响:
- 对 Redis 本身:
- 内存不均:可能导致集群中某个节点内存使用率远高于其他节点。
- 持久化阻塞:在
bgsavefork 子进程时,操作大 Key 会导致内存拷贝耗时剧增,主进程阻塞。 - 网络拥堵:获取或删除一个大 Key 会占用大量带宽。
- 对其他客户端:
- 因为上述操作(特别是持久化 fork 和网络传输)会消耗大量资源和时间,导致其他客户端的请求被延迟处理,出现超时。
- 对 Redis 本身:
- 热 Key 的影响:
- 对 Redis 本身:
- CPU 压力:所有请求集中到一个节点的一个分片,导致该节点 CPU 负载极高。
- 物理网卡瓶颈:流量打满单个机器网卡。
- 对其他客户端:
- 因为热 Key 所在的 Redis 节点/线程资源被耗尽,部署在该节点上的其他 Key 的访问也会受到严重影响,响应变慢。
- 对 Redis 本身:
7. Zabbix 监控 Redis 哪些监控项?
Zabbix 通过自定义模板或脚本采集 Redis 的指标,主要包括:
- 性能指标:
instantaneous_ops_per_sec(每秒操作数),hit rate(命中率)。 - 内存指标:
used_memory,used_memory_rss,mem_fragmentation_ratio(内存碎片率)。 - 连接指标:
connected_clients,rejected_connections(拒绝的连接数)。 - 持久化指标:
rdb_last_bgsave_status,aof_last_bgrewrite_status,aof_current_size。 - 复制指标(主从):
master_link_status,slave_lag(复制延迟)。 - Keyspace 指标:
keyspace_hits,keyspace_misses,expired_keys。
8. RDB和AOF持久化区别
| 特性 | RDB | AOF |
|---|---|---|
| 持久化方式 | 生成某个时间点的数据快照 | 记录所有写命令,以日志形式追加 |
| 数据完整性 | 可能丢失最后一次快照后的数据 | 根据 fsync 策略(每秒/每次/无),数据丢失更少 |
| 文件大小 | 小(二进制压缩) | 大(日志文本,但可重写优化) |
| 恢复速度 | 快(直接加载数据到内存) | 慢(需要逐条执行命令) |
| 对性能影响 | bgsave 时 fork 子进程,内存开销大,可能阻塞 | 主要取决于 fsync 策略,everysec 是性能和安全性的折中 |
| 优先级 | 如果同时开启,Redis 重启时 AOF 优先,因为数据更完整 |
生产环境建议:通常两者都开启,用 AOF 保证数据安全,用 RDB 做冷备份和快速恢复。
9. docker拉取一个Redis如何实现数据持久化保存?
Docker 容器本身是易失的,必须将 Redis 的数据目录映射到宿主机。
bash复制下载
# 方法一:使用 Volume(推荐,由Docker管理) docker run -d --name my-redis -v redis_data:/data redis # 方法二:使用 Bind Mount(直接映射到宿主机目录) docker run -d --name my-redis -v /host/path/to/data:/data redis # 同时,可以自定义配置文件,确保 RDB 或 AOF 被启用并指向 /data 目录 docker run -d --name my-redis -v /host/path/redis.conf:/etc/redis/redis.conf -v redis_data:/data redis redis-server /etc/redis/redis.conf
关键是将容器内的 /data(默认持久化文件存储路径)持久化到宿主机。
10. Redis 支持哪些数据类型
- String:字符串,可以是文本、数字或二进制数据。
- List:字符串列表,按插入顺序排序,支持两端插入/弹出。
- Set:无序、唯一的字符串集合。
- Hash:键值对集合,适合存储对象。
- ZSet:有序集合,每个成员关联一个分数,按分数排序。
- Bitmaps:位图,本质是 String,可进行位操作。
- HyperLogLog:用于基数统计(估算唯一元素数量)。
- Stream:用于实现消息队列,支持多消费者组。
11. Redis 如何实现消息队列
- List +
BLPOP/BRPOP:- 生产者用
LPUSH将任务放入列表。 - 消费者用
BRPOP阻塞地等待并获取任务。支持多个消费者。 - 缺点:消息只能被一个消费者消费,无法广播。
- 生产者用
- Pub/Sub:
- 生产者向频道发布消息,所有订阅了该频道的消费者都会收到。
- 缺点:消息是非持久化的,消费者离线期间的消息会丢失。
- Stream(推荐,5.0版本后):
- 类似 Kafka,消息是持久化的。
- 支持消费者组,同一个组内的消费者竞争消费,实现负载均衡。
- 支持消息确认机制,确保消息至少被处理一次。
12. 常见的redis集群架构有哪些,他们之间的优缺点对比
| 架构 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 主从复制 | 1. 数据备份 2. 读写分离,扩展读能力 | 1. 主节点故障需手动切换 2. 写能力/容量无法扩展 | 读多写少,容灾备份 |
| 哨兵模式 | 1. 主从自动故障转移,高可用 2. 部署简单 | 1. 写能力/容量无法扩展 2. 存储容量受单机限制 | 对高可用有要求,但数据量不大 |
| 官方集群 | 1. 数据分片,扩展写能力和容量 2. 高可用,内置主从和故障转移 | 1. 架构复杂,部署维护稍麻烦 2. 客户端需要支持集群协议 3. 不支持跨节点事务 | 大数据量、高并发、高可用的标准生产方案 |
13. 主从复制工作原理
- 同步:
- 从节点启动后,向主节点发送
PSYNC命令。 - 主节点执行
BGSAVE生成 RDB 快照,并将其发送给从节点。从节点清空旧数据,加载 RDB。 - 在主节点生成和发送 RDB 期间的新写命令,会缓存在内存的 复制缓冲区 中。
- 从节点启动后,向主节点发送
- 命令传播:
- RDB 加载完成后,主节点将复制缓冲区中积压的命令发送给从节点执行。
- 之后,主节点每收到一个写命令,就异步地发送给所有从节点,保持数据最终一致。
14. Redis 如何实现高可用
核心是 自动故障转移,主要依靠两种架构:
- Redis Sentinel:
- 哨兵是一个独立的进程,监控主从节点的健康状态。
- 当主节点被判定为故障时,哨兵集群会自动协商,将一个从节点提升为新的主节点,并让其他从节点和客户端指向新的主节点。
- Redis Cluster:
- 集群模式本身内置了高可用能力。每个数据分片都是一个主从单元。
- 当某个主节点故障时,其下属的从节点会被集群自动提升为主节点,继续提供服务。
15. 哨兵工作原理
- 监控:每个哨兵每秒向所有主、从节点和其他哨兵发送
PING命令,以检测它们是否“主观下线”。 - 判定主观下线:如果一个节点在配置时间内未有效回复
PING,哨兵会将其标记为“主观下线”。 - 判定客观下线:当一个哨兵认为主节点主观下线后,它会询问其他哨兵是否也认为该主节点下线。当达到法定数量(通常为哨兵数/2 + 1)时,该主节点被标记为“客观下线”。
- 选举领导者哨兵:需要故障转移时,哨兵们会通过 Raft 算法选举出一个领导者哨兵来执行故障转移操作。
- 故障转移:领导者哨兵在已下线的原主节点的从节点中,选择一个最优的(如复制偏移量最新)将其提升为新的主节点,并让其他从节点复制新的主节点,最后通知客户端配置更新。
16. Redis 集群的工作原理
- 数据分片:采用之前介绍的 槽位 机制。将 16384 个槽位分配给集群中的所有主节点。
- 去中心化:客户端可以直接连接到任意节点。如果该节点没有所需数据,会返回
MOVED重定向错误,指引客户端连接到正确的节点。 - 高可用:每个主节点都有 N 个(N>=1)从节点。主节点故障时,其从节点会接管它负责的槽位,成为新的主节点。
17. Redis 集群如何避免脑裂?
脑裂指一个集群中出现了多个主节点。Redis 主要通过以下配置来降低脑裂风险:
min-replicas-to-write:主节点必须至少有 N 个从节点连接,才允许接受写请求。这确保了在主节点与大多数从节点失联时,它会停止写入,防止旧主节点在分区中接收脏数据。min-replicas-max-lag:从节点的复制延迟必须小于 N 秒,才被计入min-replicas-to-write。
通过这两个配置,可以保证在主节点网络分区时,如果它无法连接到足够多且健康的从节点,它会自我降级,停止写入,从而避免出现“双主”和数据冲突。
18. Redis 集群最少几个节点?为什么?
- 最少 3 个主节点。
- 为什么:这是由集群的故障检测和主节点选举机制决定的。集群节点间使用 Gossip 协议通信,需要超过半数的节点认为某个主节点下线,才能将其判定为真正故障并触发故障转移。2 个节点时,如果 1 个节点故障,剩下的 1 个节点无法形成多数派(1 < 2/2+1? 1<1.5? 不成立),无法做出决策。3 个节点时,即使 1 个节点故障,剩下的 2 个节点也能形成多数派(2 > 1.5),可以完成故障转移。
19. Redis 的集群槽位多少个?
16384 个(2^14)。
20. Redis集群中某个节点缺少一个槽位是否能使用?
不能。 在 Redis 集群的正常模式下,所有 16384 个槽位都必须被分配给集群中的主节点,集群才会提供完整的服务。如果有任何一个槽位未被分配(比如负责它的节点宕机了,且没有可用的从节点接替),那么集群会进入 FAIL 状态,并停止服务。
21. Redis数据写入的时候是怎么在各个节点槽位分配数据的?
- 客户端对某个 Key 执行写操作。
- 客户端本地计算该 Key 的槽位号:
CRC16(key) % 16384。 - 客户端根据本地缓存的“槽位-节点”映射表,直接连接负责该槽位的节点进行写入。
- 如果客户端连错了节点,该节点会返回
MOVED <slot> <correct-node-ip:port>错误,引导客户端连接到正确的节点。
22. Redis的数据存储是以什么样的方式存储?
在内存中,Redis 使用自定义的哈希表、跳跃表、压缩列表等高效数据结构来存储不同类型的键值,这也是其性能极高的原因之一。
23. Redis集群的各槽位和总槽位之间什么关系?
部分与整体的关系。
- 总槽位:一个固定的、完整的集合,大小为 16384。它代表了整个集群的数据空间。
- 各槽位:总槽位被划分给集群中的各个主节点。每个主节点负责总槽位的一个子集。所有主节点负责的槽位子集之和,必须等于总槽位。
24. Redis集群中有一个节点内存使用明显偏大,可能是原因是什么?
- 数据倾斜:该节点分配的槽位中包含了大 Key,或者包含了热 Key 导致数据量本身比其他节点多。
- Hash Tag 使用不当:使用
{}将不同的 Key 强制路由到同一个槽位,如果这个策略设计不当,会导致大量数据集中到同一个节点。 - 该节点为主节点,且从节点复制延迟大:如果从节点长时间断开连接或复制延迟很大,主节点的复制积压缓冲区会占用较多内存。
25. Redis部署有几种模式
- 单机模式:单个 Redis 实例,简单易用,无高可用和扩展性。
- 主从复制模式:一主多从,实现数据备份和读写分离。
- 哨兵模式:在主从基础上增加了哨兵进程,实现自动故障转移,达到高可用。
- 集群模式:多主多从,实现数据分片、高可用和高并发,是应对大数据量和高流量的终极方案。
发表回复