1.Redis的基本数据类型

  1. String
  2. List
  3. Set
  4. Hash
  5. ZSet
  6. Bitmap
  7. Hyperloglog
  8. Geospatial

    2.Redis底层数据结构

  9. String类型

    1. 底层数据结构:SDS
    2. 最大存储大小:512M
    3. SDS数据结构:len、free、buf[]
    4. 优点:二进制安全、计算长度快
  10. Hash类型
    1. 底层数据结构:Hash表、压缩列表(未来可能被listpack代替)
  11. Set类型
    1. 底层数据结构:整数集合、Hash表
    2. 整数集合数据结构:encoding、contents[]、length
  12. List类型
    1. 底层数据结构:压缩列表、双向链表(3.2后使用 quicklist)
    2. 压缩列表数据结构:每段数据记录前一个记录的大小
    3. 双向链表数据结构:略
    4. quicklist数据结构:多个压缩列表的链式化
  13. ZSet类型

    1. 底层数据结构:压缩表(未来可能被listpack代替)、跳表、也用到了Hash表
    2. listpack的数据结构:每个元素只记录自己的长度
    3. 跳表:多层链表

      3.Redis各类数据类型的应用场景

  14. String:共享session、分布式锁,计数器、限流

  15. Hash:缓存用户信息
  16. List:消息队列,文章列表
  17. Set:用户标签,生成随机数抽奖、社交需求
  18. ZSet:排行榜,社交需求(如用户点赞)
  19. HyperLogLog:基数统计算法统计网站的UV
  20. Bitmap:用一个比特位来映射某个元素的状态,底层基于字符串实现
  21. Geo:存储地理位置

    4.Redis为什么这么快

    基于内存存储

    Redis基于内存,省去了磁盘IO操作。

    高效的底层数据结构

    image.png

  22. SDS

    1. 获取字符串长度仅需O(1)时间复杂度
    2. 二进制安全
    3. 空间预分配,防止字符串频繁修改导致内存的频繁分配
    4. 惰性空间释放,不回收多余空间而是使用free记录空闲空间
  23. 字典
    1. O(1)的时间复杂度获取key-value
  24. 跳表
    1. 平均O(logn)的时间复杂度,最坏O(n)

      合理的编码

      这个盲区啦

      合理的线程模型

      image.png

多路I/O复用技术可以让单个线程高效的处理多个连接请求,而Redis使用用epoll作为I/O多路复用技术的实现。并且,Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。
Redis是单线程模型的,而单线程避免了CPU不必要的上下文切换和竞争锁的消耗。但是存在阻塞的风险
Redis6引入多线程提速,但是执行命令仍然是单线程的

虚拟内存机制

虚拟内存机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。

5.缓存穿透、击穿、雪崩

缓存穿透

  1. 定义:查询一个数据库中不存在的值
  2. 产生原因:
    1. 黑客攻击
    2. 数据误删
  3. 解决方式

    1. 加强API对非法值的校验
    2. 数据库为空值,在缓存中也设置一个空值
    3. 使用布隆过滤器判断

      缓存击穿

  4. 定义:某个key在某个时间点过期,但是这一时间点大量的请求过来请求这个key

  5. 解决方式:

    1. 使用互斥锁:同一时间只有一个请求去更新缓存,其他请求等待更新好后从缓存中取
    2. 永不过期:真的永不过期或者定时去为key加时间

      缓存雪崩

  6. 定义:同一时间大量key过期或者Redis直接崩啦

  7. 解决方式:

    1. 均匀的设置过期时间
    2. Redis高可用集群搭建

      6.什么是热key问题?如何解决

      什么是热key

      访问频率较高的key

      热key问题

      大量的热key请求压到某台Redis上,导致Redis宕机

      热key的识别

  8. 服务端统计热key

  9. 根据业务判断

    解决方式

  10. Redis增加分片副本,均衡读流量

  11. 热key要均匀分散到不同的Redis服务器中
  12. JVM本地对热key进行缓存

    7.Redis的过期策略

    过期策略即对达到过期条件key,Redis的处理策略,是立刻删除、还是下次请求时删除?主要有以下几种方式:

  13. 定时过期:一旦到达过期时间,立刻CPU执行删除操作(影响性能)

  14. 惰性过期:当访问key时判断是否过期,过期后删除,极端情况下可能永远删除不掉,导致内存占有
  15. 定期过期:定时器每隔一段时间扫描expire字典(key->过期时间)中一定量的key进行判断清除

最优解:定期过期+惰性删除,虽然仍然有部分过期key无法删除的风险但是结合内存淘汰策略即可

8.Redis的内存淘汰策略

内存不足时淘汰key的策略:

  1. allkeys-lru:针对所有key进行最近最久未使用的清理方式
  2. allkeys-lfu:针对所有key进行最不常用的清理方式
  3. allkeys-random:所有key随机删除
  4. volatile-lru:针对有过期时间的key进行最近最久未使用的清理方式
  5. volatile-lfu:针对有过期时间的key进行最不常用的清理方式
  6. volatile-random:过期key随机删除
  7. volatile-ttl:过期key,最先要过期的删除
  8. noeviction:不淘汰

    9.Redis常用场景

  9. 缓存

  10. 分布式锁
  11. 排行榜
  12. 计数器

    10.Redis的持久化机制

    RDB

  13. 流程

image.png

  1. 触发机制
    1. 手动触发:save/bgsave
    2. 自动触发:配置文件中的 save m秒 n次
  2. 生成文件:dump.rdb
  3. 适用场景:大规模的数据备份
  4. 优点:占用空间小

    AOF

  5. 工作流程

image.png

  1. 触发机制
    1. 开启aof
  2. 生成文件:*.aof文件
  3. 优点:数据一致性程度高

    11.Redis主从复制原理

    image.png

  4. slave发送sync(2.8以后psync)请求到master

  5. master执行bgsave命令,生成rdb文件并发送到slave
  6. master将RDB生成期间的命令缓存到replication buffer,也发送到slave
  7. slave载入rdb完成数据同步,对replication buffer中的命令进行执行完成数据的同步
  8. 同步完成后,master上的新命令会增量复制给从服务器
  9. 主从网络断开后,主库会将命令同时写入replication buffer和repl_backlog_buffer。从节点恢复后通过repl_backlog_buffer对数据进行恢复

    12.哨兵模式

  10. 哨兵的作用

    1. 监控Redis主从节点的状态
    2. 主从切换
    3. 监控自己
  11. 哨兵工作模式
    1. sentinel每秒向master和slave发送ping命令
    2. 若距上次有效回复时间超过阈值down-after-milliseconds,sentinel标记节点为主观下线
    3. 监控主观下线节点的其他sentinel每秒ping一下该节点
    4. 足够数量的sentinel认为节点下线时,标记为客观下线
    5. 正常时,sentinel每10秒向master和slave发送INFO命令
    6. master客观下线后,每秒向slave发送INFO命令
  12. 选主流程

    1. 哨兵会投票选举出执行主从切换的哨兵(多票者胜出)
    2. 执行主从切换的哨兵先过滤掉表现不好的从节点
    3. 再按照slave-priority、复制进度、从库id大小(小的优先)

      13.集群模式

  13. 16384个hash槽

  14. Gossip协议:节点间通信
  15. 客观下线
    1. 主节点客观下线:持有槽的主节点投票进行客观下线
    2. 从节点客观下线:主从节点都可以投票
  16. 选主:由存活的主节点校验从节点状态、并投票选举
  17. 分片方式:CRC16后%16384

    14.Redis实现分布式锁的问题分析

  18. setnx+expire

    1. setnx和expire非原子的,所以可能锁永远解不开->Lua脚本可以解决原子性
    2. 锁的误解,A加锁超时后B加锁,A执行完解锁。->value值中打标记
    3. 业务执行超时,锁超时后其他线程进入导致的并发。->守护线程为锁续命
    4. 不可重入->ThreadLocal记录、Redis Map记录
    5. 无法等待锁释放->客户端轮询或者发布订阅方式

小结:即使这样,在主从下,主节点加锁,从节点未同步的情况也有问题。红锁的引入解决这个问题

15.Redission锁的实现原理

image.png

  1. 可重入性:加锁通过Hash结构,uuid:次数
  2. 看门狗:这里不是观察线程的存活,而是整个服务的存活,只要服务存活,没10s就会为锁续命

    16. 红锁

    主从下,主节点的锁未同步到从节点,因此会产生问题
    红锁实现步骤:

  3. 获取当前时间(毫秒)

  4. 顺序向5个master请求加锁,客户端超时时间小于锁超时时间,超时未响应跳过此master
  5. 客户端轮询完后,计算轮询所费时间,当轮询时长小于锁有效时间,且过半master成功响应则成功上锁
  6. 成功的话,key的真正过期时间要减去获取锁时间
  7. 失败的话,加锁成功的master解锁

    17.MySQL和Redis的数据一致性

  8. 缓存延时双删

  9. 删除缓存重试机制
  10. 读取biglog异步删除缓存

    缓存延时双删

    image.png

  11. 先删除老缓存

  12. 更新数据库
  13. 再延时一会儿,再删缓存

    删除缓存重试机制

    就是第二次删失败后重试

    读取biglog异步删除缓存

    通过canal,将更新数据发往rocketmq,然后异步的更新缓存

    18.Redis的事务

  14. 关键命令:MULTI、EXEC、DISCARD 、WATCH、UNWATCH

  15. EXEC:提交事务
  16. DISCARD:回滚事务、放弃事务
  17. MULTI:启动事务
  18. WATCH:观察某个key,通过结束事务或UNWATCH取消观察
  19. UNWATCH:取消观察某个key

    事务几点:

    1. 入队过程中有命令错误,整个事务无效
    2. 入队过程无误,执行中某个命令有错,其他命令执行成功
    3. 事务结束会将WATCH释放
    4. 客户端WATCH的key被改掉,事务执行EXEC直接失败
    5. WATCH在事务开启前进行

参考资料