type
status
date
slug
summary
tags
category
icon
password
Redis面试题
Redis常用数据结构类型及其应用场景
数据类型 | 底层数据结构 | 应用场景 |
字符串String | 简单动态字符串(SDS) | 缓存Session、Token、图片地址、序列化后的对象、计数器、分布式锁 |
哈希Hash | 压缩列表(ziplist)、哈希表(hashtable) | 存储用户信息、配置项管理 |
列表List | 双向链表(quicklist)、压缩列表(ziplist) | 消息队列、任务调度、日志记录 |
集合Set | 整数集合(intset)、哈希表(hashtable) | 点赞系统、收藏夹、去重功能、聚合计算 |
有序集合Sorted Set | 跳表(skiplist)、哈希表(hashtable) | 排行榜、延迟任务 |
位图Bitmap | 简单动态字符串(SDS) | 用户签到系统、活跃用户统计 |
HyperLogLog | 基数估计算法 | 独立访客统计、大规模数据去重计数 |
地理空间Geospatia | 有序集合(sorted set) | LBS 应用、附近商家搜索 |
流Stream | 压缩列表(ziplist)、链表 | 消息系统、日志系统 |
为什么Redis是单线程效率也能这么高
- 纯内存操作
- 采用了非阻塞I/O多路复用机制
- 单线程避免了多线程频繁的上下文切换问题
Redis内存淘汰策略
Redis 的内存淘汰策略只有在运行内存达到了配置的最大内存阈值时才会触发,这个阈值是通过redis.conf的maxmemory参数来定义的
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
- allkeys-lru(least recently used):从数据集中移除最近最少使用的数据淘汰
- allkeys-random:从数据集中任意选择数据淘汰
- no-eviction(默认内存淘汰策略):禁止驱逐数据,当内存不足以容纳新写入数据时,新写入操作会报错
- volatile-lfu(least frequently used):从已设置过期时间的数据集中挑选最不经常使用的数据淘汰
- allkeys-lfu(least frequently used):从数据集中移除最不经常使用的数据淘汰。
Redis BigKey(大Key)
单个键值对占用大量内存或包含大量数据(一个key的value占用内存较大)
原因
- 程序设计不当:直接使用String类型存储较大的文件或二进制数据。
- 业务规划不足:在设计数据结构时没有考虑到数据量的快速增长,导致某些集合类型的数据量过大。
- 未及时清理无效数据:哈希表中存在大量冗余的键值对,未能及时清理。
- 代码故障:使用List类型时,消费侧代码出现问题,导致列表中的元素只增不减
危害
- 客户端超时阻塞:操作大key时候会导致Redis阻塞,从而导致客户端响应超时
- 网络流量增加:每次获取大key都会产生大量网络流量
- 内存消耗过多:大key会占用大量的内存,导致内存使用率增加,可能出发内存淘汰机制,甚至导致内存耗尽
发现
- 使用 Redis自带的--bigkeys参数来查找。redis-cli -p 6379 —bigkeys -i 3 -i表示延迟几秒
- 使用MEMORY USAGE命令查看特定key的内存使用。redis-cli MEMORY USAGE mykey
- 使用Redis自带的SCAN命令
- 借助开源工具分析RDB文件,前提是Redis采用的是RDB持久化
解决
- 分割bigkey:将一个bigkey分割为多个小key
- 异步删除:使用UNLINK命令来异步代替同步删除
- 采用合适的数据结构:文件二进制数据不使用String保存、使用HyperLogLog统计页面UV、Bitmap 保存状态信息
- 开启 lazy-free(惰性删除/延迟释放):让Redis采用异步方式延迟释放key使用的内存,将该操作交给单独的子线程处理,避免阻塞主线程
Redis Hotkey(热Key)
一个key的访问次数比较多且明显多于其他key
危害
- 会占用大量的CPU和带宽,可能会影响Redis实例对其他请求的正常处理
- 如果突然访问hotkey的请求超出了Redis的处理能力Redis就会直接宕机
- 大量请求将落到后面的数据库上,可能会导致数据库崩溃
发现
- 使用Redis自带的--hotkeys参数来查找,前提是Redis Server的maxmemory-policy参数设置为LFU(volatile-lfu/allkeys-lfu)。redis-cli -p 6379 --hotkeys
- 使用MONITOR命令,实时查看Redis的所有操作的方式。(影响性能)redis-cli MONITOR
解决
- 读写分离:主节点处理写请求,从节点处理读请求。
- 使用Redis Cluster:将热点数据分散存储在多个 Redis 节点上。
- 二级缓存:hotkey采用二级缓存的方式进行处理,将hotkey存放一份到JVM本地内存中(可以用 Caffeine)
Redis慢查询
指执行时间超过预设阈值的命令,如:
- KEYS *:会返回所有符合规则的key
- HGETALL:会返回一个Hash中所有的键值对
- LRANGE:会返回List中指定范围内的元素
- SMEMBERS:返回Set中的所有元素
- 等
发现
- 在redis.conf文件中(也可通过CONFIG命令设置),我们可以使用slowlog-log-slower-than参数设置耗时命令的阈值,并使用slowlog-max-len参数设置耗时命令的最大记录条数,当慢查询日志超过设定的最大记录条数之后,Redis会把最早的执行命令依次舍弃
- 通过SLOWLOG GET N(可指定查询数量默认10)命令获取慢查询日志
每个条目组成
- 唯一渐进的日志标识符。
- 处理记录命令的Unix时间戳。
- 执行所需的时间量,以微秒为单位。
- 组成命令参数的数组。
- 客户端IP地址和端口。
- 客户端名称
Redis哨兵机制
通过在独立的哨兵节点上运行哨兵进程来实现对主从数据库状态的监控,当发现故障时,能自动完成主从数据库的切换,并通知应用方,实现高可用性。
哨兵选举
在启用时,每个哨兵节点会执行选举过程,选举其中一个哨兵节点为领导者(Leader),负责协调其他哨兵节点,主导故障转移的具体执行,负责选出新的主节点并更新集群配置。
每个哨兵节点都会向其他节点发送is-master-down-by-addr命令,征求自己成为领导者,其他哨兵节点接收到此命令会进行同意和拒绝的投票,如果哨兵节点发现自己的票数大于或等于哨兵节点数的一半多(哨兵节点数/2+1)时,将成为领导者,没有则继续进行投票
监控主从节点
哨兵节点会周期性的检查主从节点的健康情况,包括主节点是否在线,从节点是否同步,如果哨兵节点发现主节点不可用,则会触发一次故障转移
故障转移
哨兵节点会向主节点发送心跳PING来确认主节点是否存活,如果主节点没有回应或回应错误信息,则哨兵节点主观认为这个主节点已经不可用。这时由领导者负责主节点的选用,先过滤掉没有心跳回应的从节点,再根据从节点的优先级和从节点数据复制的完整性来确认
客户端重定向
哨兵节点会通知客户端新的主节点位置,使得客户端能够与新的主节点建立连接并发送请求
从节点状态更新
此外哨兵节点还会监控从节点的状态,如果从节点出现故障会将其进行下线,等待其恢复后再将其加入集群
客观下线
当哨兵节点主观判断主节点需要下线时,该哨兵节点会发起sentinel-is-masterdown-by-addr指令给其他哨兵节点,其他哨兵节点也对主节点下线进行判断,并进行投票,当大部分投票数都同意下线操作时,则说明客观下线
- 作者:JackJame
- 链接:https://notion.qjit1314.eu.org/article/example-11
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章


