1.Redis
1.1 为什么要用Redis,特点是什么
- what:基于键值对的数据库,
- why:
速度快[基于内存、单线程]、简单稳定、功能丰富【键过期、发布订阅、事务、流水线】、持久化、主从复制、高可用和分布式转移、客户端语言多【lua】
单线程:无锁,避免了多线程获取释放锁开销,免去可能的死锁所造成的性能问题;节省线程切换的cpu消耗
- how:
基本通讯模型:
客户端发送消息----消息放入队列----执行命令----返回结果给客户端
1.2 Redis支持的数据类型,使用场景以及底层数据结构
- String : 计数器,定时器 简单动态字符串,最大长度512M
- Hash : 存储对象,用作缓存 哈希、压缩列表
- List : 队列 双向链表、压缩列表
- Set : 朋友圈 哈希表、整数数组
- ZSet : 排行榜 跳表、压缩列表
1.3 Redis中String 的底层结构
SDS: [LEN长度,ALLOC剩余空间,char[]数据,flag数据类型大小] 简单动态字符串类型
好处:
- 获取长度简单
- 二进制安全 【字符以\0结尾】
- 动态扩容,避免频繁的内存分配【alloc扩容时】
- 防止内存溢出
- 兼容c语言
1.3.1 Redis中的bitmap
- what:位图,一个bit表示一个状态,只有两种状态【0/1】
- why:占用内存空间低;排序、查找、去重效率高
缺点:结果本身不能重复且只有0/1;数据量小时浪费空间
适用场景:统计在线人数、签到统计 - how :
setbit key offset value; //offset为偏移量 value取值0/1
getbit key offset //获取值
bitcount key [start,end]//获取区间内值为1的个数
BITOP AND destkey key [key …] //对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
BITOP OR destkey key [key …] //对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
BITOP XOR destkey key [key …] //对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
BITOP NOT destkey key//对给定 key 求逻辑非,并将结果保存到 destkey 。
1.4 Redis中ZSet 的底层结构
- 压缩列表:【列表长度、尾步偏移量、列表个数---数据---列表结束标志】
有序集合元素个数<128或者长度<64字节时采用列表 - 跳表:增加了多级索引,通过多级索引的位置跳转,实现快速查找元素
时间复杂度O(log)
不采用树形结构的原因:范围查找效率更高;跳表实现更加简单易懂。
1.5 Redis支持的数据类型持久化【基于fork-join进行】
RDB:某一时刻点的数据生成快照存储在磁盘介质上;
手动触发: save阻塞线程;bgSave使用fork子线程完成持久化,阻塞时间短
自动触发:未开启aof时,自动执行bgSave
优点:恢复数据快;全量复制用于灾备;
缺点:无法做到实时持久化,每次都要创建子线程,频繁操作成本高;各版本文件不兼容AOF:记录所有写操作,数据完整度更高。
所有写入命令append追加到aof_buff中--缓冲区同步sync到硬盘--定期rewrite-- 重启时load
三种同步机制appendSync:
always:即时同步,性能差,不推荐
everysec:每秒强制写入,性能和持久化都做了折中,推荐
no:完全依赖os,性能最好
重启时两文件同时存在,如何加载:优先aof
1.6 缓存雪崩、缓存穿透、缓存击穿以及对应解决方案
- 缓存雪崩:大量key失效;错峰失效、二级缓存、访问限流
- 缓存穿透:大量访问不存在的key;缓存预知空值、布隆过滤器【说不存在比不存在,但说存在不一定为真】
- 缓存击穿:热key失效
1.7主从复制和哨兵
- 主从集群: master节点负责数据读写,slave节点负责数据读取,master同步数据到slave;
实现读写分离,提升查询效率;但不提供容错和恢复功能 - 哨兵:主节点出现问题时,哨兵选举出新的主节点;在线扩容的问题依然未得到解决
1.8 集群
- cluster:通过slot槽[16383]实现数据分片,根据key计算数据放哪个节点,每个Master节点实现主从复制;若出现故障,从从节点中选出一个主节点。
- 优点 实现了扩容和故障转移的能力;
- 缺点:客户端实现复杂;slave只是个冷备节点,不提供分担读写的能力;批量操作指令存在限制
1.8.1两种集群方式的区别【哨兵集群、cluster】
一个侧重高可用,一个侧重扩展性
- 读写访问:哨兵集群基于主从复制,可实现读写分离,分担读操作访问压力;cluster的slave只实现了冷备功能,只有master宕机后才工作
- 扩容:主从无法在线扩容,受制于单个服务器配置限制;cluster基于slot槽的数据分片实现,支持在线扩容
- 架构:哨兵是一主多从,cluster是多主多从
1.9如何保证缓存与数据库的数据一致性
- 延迟双删:先删除缓存,更新数据库,停顿几秒后再次删除缓存。
- 队列异步: 消息放入队列,消费者异步删除redis。可达到解耦
1.10Redis分布式锁和看门狗机制
- setnx加锁,设置过期时间
- 看门狗:watch-dog 每隔10s看下,如果还持有锁,则延长生存时间
- 防死锁,高性能,可重入锁
1.11 Redis的淘汰策略
当Redis内存超过MaxMemory限定时,触发主动清理策略
算法:
LRU:最近使用;底层哈希表+双向链表
LFU:频率最高使用,底层为两个链表
random:随机
ttl:快要过期的先淘汰keys: volatile allkeys
redis淘汰策略
1.12 RedissionRedLock
- 解决问题:主节点挂掉,从节点升级成为主节点时,分布式锁失效。
- 步骤:记录当前时间;设置锁有效时间;去各个master节点获取锁,半数获取到的话计算获取时间是否超过锁有效时间;超时则返回失败,解锁。
1.13Redis删除策略
- 惰性/被动删除:访问key时删除;遗留问题:冷数据一直不会删除占用内存
- 定时/主动删除:每隔10s去轮询取得一定量key,删除其中过期的
定时不生效时注意修改的时候是否未标注过期时间
1.14 你的项目出现过oOM嘛?怎么解决的?
OOM原因:maxMemory设置不合理,且未设置合适的maxMemory-policy
解决方案:
- 调整maxMemory:分配大一些
- 设置maxMemory-policy:默认为lru算法
- 增加物理机内存,或者分布式存储
1.15 redis的pipeline
好处:减少网络传输开销
1.16 拓展
工业级分桶算法实现分位数
P99算法=100个数字从小到大排列后第99位的值=数组99%<该值=位置取整后的值+(取整后一位值-取整值)*(位置取证后一位-位置取整)
- 数据集群会丢数据吗?怎么防止丢数据?
- redis性能怎么样?你们的数据量多少【qps:】,key【几十个字节,小于1kb】 value【几kb吧】值大概又是多少?
- 出现过什么问题?又是如何解决的?
- 一个redis的写入大概多久10ms;key集中过期会怎么样【过期的时间会出现访问延迟】?
- 内存优化
1.17 书籍推荐
《Redis设计与实现》《Reids深度历险:核心原理和应用实践》《Redis开发与运维》
1.18 附录
可搭配食用文章:面试 Redis 没底?这 40 道面试题让你不再慌(附答案)

Redis延迟问题全面排障指南