最新 Redis 知识点梳理汇总

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战面试

Redis 做为一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类keyvalue存储的不足,在部分场合能够对关系数据库起到很好的补充做用。redis

在此抽时间整理了下 Redis 相关知识点,便于你们查漏补缺,不断优化完善。算法

应用场景

  1. 缓存sql

  2. 共享 Session数据库

  3. 消息队列系统后端

  4. 分布式锁缓存

单线程的 Redis 为何快

  1. 纯内存操做服务器

  2. 单线程操做,避免了频繁的上下文切换markdown

  3. 合理高效的数据结构数据结构

  4. 采用了非阻塞 I/O 多路复用机制(有一个文件描述符同时监听多个文件描述符是否有数据到来)

Redis 的数据结构及使用场景

  1. String 字符串:字符串类型是 Redis 最基础的数据结构,首先键都是字符串类型,并且 其余几种数据结构都是在字符串类型基础上构建的,咱们常使用的 set key value 命令就是字符串。经常使用在缓存、计数、共享 Session、限速等。

  2. Hash 哈希:在 Redis 中,哈希类型是指键值自己又是一个键值对结构,哈希能够用来存放用户信息,好比实现购物车。

  3. List 列表(双向链表):列表(list)类型是用来存储多个有序的字符串。能够作简单的消息队列的功能。

  4. Set 集合:集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一 样的是,集合中不容许有重复元素,而且集合中的元素是无序的,不能经过索引下标获取元素。利用 Set 的交集、并集、差集等操做,能够计算共同喜爱,所有的喜爱,本身独有的喜爱等功能。

  5. Sorted Set 有序集合(跳表实现):Sorted Set 多了一个权重参数 Score,集合中的元素可以按 Score 进行排列。能够作排行榜应用,取 TOP N 操做。

Redis 的数据过时策略

Redis 中数据过时策略采用按期删除+惰性删除策略

  • 按期删除策略:Redis 启用一个定时器定时监视全部的 key,判断 key 是否过时,过时的话就删除。这种策略能够保证过时的 key 最终都会被删除,可是也存在严重的缺点:每次都遍历内存中全部的数据,很是消耗 CPU 资源,而且当 key 已过时,可是定时器还处于未唤起状态,这段时间内 key 仍然能够用。

  • 惰性删除策略:在获取 key 时,先判断 key 是否过时,若是过时则删除。这种方式存在一个缺点:若是这个 key 一直未被使用,那么它一直在内存中,其实它已通过期了,会浪费大量的空间。

  • 这两种策略自然的互补,结合起来以后,定时删除策略就发生了一些改变,再也不是每次扫描所有的 key 了,而是随机抽取一部分 key 进行检查,这样就下降了对 CPU 资源的损耗,惰性删除策略互补了未检查到的 key,基本上知足了全部要求。可是有时候就是那么的巧,既没有被定时器抽取到,又没有被使用,这些数据又如何从内存中消失?不要紧,还有内存淘汰机制,当内存不够用时,内存淘汰机制就会上场。淘汰策略分为:当内存不足以容纳新写入数据时,新写入操做会报错。(Redis 默认策略)当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 Key。(LRU 推荐使用)当内存不足以容纳新写入数据时,在键空间中,随机移除某个 Key。当内存不足以容纳新写入数据时,在设置了过时时间的键空间中,移除最近最少使用的 Key。这种状况通常是把 Redis 既当缓存,又作持久化存储的时候才用。当内存不足以容纳新写入数据时,在设置了过时时间的键空间中,随机移除某个 Key。当内存不足以容纳新写入数据时,在设置了过时时间的键空间中,有更早过时时间的 Key 优先移除。

Redis 的 set 和 setnx

Redis 中 setnx 不支持设置过时时间,作分布式锁时要想避免某一客户端中断致使死锁,需设置 lock 过时时间,在高并发时 setnx 与 expire 不能实现原子操做,若是要用,得在程序代码上显示的加锁。使用 SET 代替 SETNX ,至关于 SETNX+EXPIRE 实现了原子性,没必要担忧 SETNX 成功,EXPIRE 失败的问题。

Redis 的 LRU 具体实现:

传统的 LRU 是使用栈的形式,每次都将最新使用的移入栈顶,可是用栈的形式会致使执行 select *的时候大量非热点数据占领头部数据,因此须要改进。Redis 每次按 key 获取一个值的时候,都会更新 value 中的 lru 字段为当前秒级别的时间戳。Redis 初始的实现算法很简单,随机从 dict 中取出五个 key,淘汰一个 lru 字段值最小的。在 3.0 的时候,又改进了一版算法,首先第一次随机选取的 key 都会放入一个 pool 中(pool 的大小为 16),pool 中的 key 是按 lru 大小顺序排列的。接下来每次随机选取的 keylru 值必须小于 pool 中最小的 lru 才会继续放入,直到将 pool 放满。放满以后,每次若是有新的 key 须要放入,须要将 pool 中 lru 最大的一个 key 取出。淘汰的时候,直接从 pool 中选取一个 lru 最小的值而后将其淘汰。

Redis 如何发现热点 key

  1. 凭借经验,进行预估:例如提早知道了某个活动的开启,那么就将此 Key 做为热点 Key。

  2. 服务端收集:在操做 redis 以前,加入一行代码进行数据统计。

  3. 抓包进行评估:Redis 使用 TCP 协议与客户端进行通讯,通讯协议采用的是 RESP,因此本身写程序监听端口也能进行拦截包进行解析。

  4. 在 proxy 层,对每个 redis 请求进行收集上报。

  5. Redis 自带命令查询:Redis4.0.4 版本提供了 redis-cli –hotkeys 就能找出热点 Key。(若是要用 Redis 自带命令查询时,要注意须要先把内存逐出策略设置为 allkeys-lfu 或者 volatile-lfu,不然会返回错误。进入 Redis 中使用 config set maxmemory-policy allkeys-lfu 便可。)

Redis 的热点 key 解决方案

  1. 服务端缓存:即将热点数据缓存至服务端的内存中.(利用 Redis 自带的消息通知机制来保证 Redis 和服务端热点 Key 的数据一致性,对于热点 Key 客户端创建一个监听,当热点 Key 有更新操做的时候,服务端也随之更新。)

  2. 备份热点 Key:即将热点 Key+随机数,随机分配至 Redis 其余节点中。这样访问热点 key 的时候就不会所有命中到一台机器上了。

如何解决 Redis 缓存雪崩问题

  1. 使用 Redis 高可用架构:使用 Redis 集群来保证 Redis 服务不会挂掉

  2. 缓存时间不一致,给缓存的失效时间,加上一个随机值,避免集体失效

  3. 限流降级策略:有必定的备案,好比个性推荐服务不可用了,换成热点数据推荐服务

如何解决 Redis 缓存穿透问题

  1. 在接口作校验

  2. 存 null 值(缓存击穿加锁,或设置不过时)

  3. 布隆过滤器拦截: 将全部可能的查询 key 先映射到布隆过滤器中,查询时先判断 key 是否存在布隆过滤器中,存在才继续向下执行,若是不存在,则直接返回。布隆过滤器将值进行屡次哈希 bit 存储,布隆过滤器说某个元素在,可能会被误判。布隆过滤器说某个元素不在,那么必定不在。

Redis 的持久化机制

Redis 为了保证效率,数据缓存在了内存中,可是会周期性地把更新的数据写入磁盘或者把修改操做写入追加的记录文件中,以保证数据的持久化。Redis 的持久化策略有两种:

  1. RDB:快照形式是直接把内存中的数据保存到一个 dump 的文件中,定时保存,保存策略。当 Redis 须要作持久化时,Redis 会 fork 一个子进程,子进程将数据写到磁盘上一个临时 RDB 文件中。当子进程完成写临时文件后,将原来的 RDB 替换掉。

  2. AOF:把全部的对 Redis 的服务器进行修改的命令都存到一个文件里,命令的集合。

使用 AOF 作持久化,每个写命令都经过 write 函数追加到 appendonly.aof 中。aof 的默认策略是每秒钟 fsync 一次,在这种配置下,就算发生故障停机,也最多丢失一秒钟的数据。 缺点是对于相同的数据集来讲,AOF 的文件体积一般要大于 RDB 文件的体积。根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB。 Redis 默认是快照 RDB 的持久化方式。对于主从同步来讲,主从刚刚链接的时候,进行全量同步(RDB);全同步结束后,进行增量同步(AOF)。

Redis 的事务

  1. Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中全部命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其余客户端提交的命令请求不会插入到事务执行命令序列中。总结说:redis 事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

  2. Redis 事务没有隔离级别的概念,批量操做在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。

  3. Redis 中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其他的命令仍会被执行。

Redis 事务相关命令

  1. watch key1 key2 ... : 监视一或多个 key,若是在事务执行以前,被监视的 key 被其余命令改动,则事务被打断(相似乐观锁)

  2. multi : 标记一个事务块的开始(queued)

  3. exec : 执行全部事务块的命令(一旦执行 exec 后,以前加的监控锁都会被取消掉)

  4. discard : 取消事务,放弃事务块中的全部命令

  5. unwatch : 取消 watch 对全部 key 的监控

Redis 和 memcached 的区别

  1. 存储方式上:memcache 会把数据所有存在内存之中,断电后会挂掉,数据不能超过内存大小。redis 有部分数据存在硬盘上,这样能保证数据的持久性。

  2. 数据支持类型上:memcache 对数据类型的支持简单,只支持简单的 key-value,,而 redis 支持五种数据类型。

  3. 用底层模型不一样:它们之间底层实现方式以及与客户端之间通讯的应用协议不同。redis 直接本身构建了 VM 机制,由于通常的系统调用系统函数的话,会浪费必定的时间去移动和请求。

  4. value 的大小:redis 能够达到 1GB,而 memcache 只有 1MB。

Redis 的几种集群模式

  1. 主从复制

  2. 哨兵模式

  3. cluster 模式

Redis 的哨兵模式

哨兵是一个分布式系统,在主从复制的基础上你能够在一个架构中运行多个哨兵进程,这些进程使用流言协议来接收关于 Master 是否下线的信息,并使用投票协议来决定是否执行自动故障迁移,以及选择哪一个 Slave 做为新的 Master。

每一个哨兵会向其它哨兵、master、slave 定时发送消息,以确认对方是否活着,若是发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的”主观认为宕机”)。

若“哨兵群“中的多数 sentinel,都报告某一 master 没响应,系统才认为该 master"完全死亡"(即:客观上的真正 down 机),经过必定的 vote 算法,从剩下的 slave 节点中,选一台提高为 master,而后自动修改相关配置。

Redis 的 rehash

Redis 的 rehash 操做并非一次性、集中式完成的,而是分屡次、渐进式地完成的,redis 会维护维持一个索引计数器变量 rehashidx 来表示 rehash 的进度。

这种渐进式的 rehash 避免了集中式 rehash 带来的庞大计算量和内存操做,可是须要注意的是 redis 在进行 rehash 的时候,正常的访问请求可能须要作多要访问两次 hashtable(ht[0], ht[1]),例如键值被 rehash 到新 ht1,则须要先访问 ht0,若是 ht0 中找不到,则去 ht1 中找。

Redis 的 hash 表被扩展的条件

  1. 哈希表中保存的 key 数量超过了哈希表的大小.

  2. Redis 服务器目前没有在执行 BGSAVE 命令(rdb)或 BGREWRITEAOF 命令,而且哈希表的负载因子大于等于 1.

  3. Redis 服务器目前在执行 BGSAVE 命令(rdb)或 BGREWRITEAOF 命令,而且哈希表的负载因子大于等于 5.(负载因子=哈希表已保存节点数量 / 哈希表大小,当哈希表的负载因子小于 0.1 时,对哈希表执行收缩操做。)

Redis 并发竞争 key 的解决方案

  1. 分布式锁+时间戳

  2. 利用消息队列

Redis 与 Mysql 双写一致性方案

先更新数据库,再删缓存。数据库的读操做的速度远快于写操做的,因此脏数据很难出现。能够对异步延时删除策略,保证读请求完成之后,再进行删除操做。

Redis 的管道 pipeline

对于单线程阻塞式的 Redis,Pipeline 能够知足批量的操做,把多个命令连续的发送给 Redis Server,而后一一解析响应结果。Pipelining 能够提升批量处理性能,提高的缘由主要是 TCP 链接中减小了“交互往返”的时间。pipeline 底层是经过把全部的操做封装成流,redis 有定义本身的出入输出流。在 sync() 方法执行操做,每次请求放在队列里面,解析响应包。

🎉 关注公众号 | 架构精进之路,即时获取更新

  • 本人十年后端研发经验,任职架构师,曾“混迹”多个互联网大厂,专一软件架构技术研究学习,但愿可以不断沉淀、学习以及分享,将本身工做中的问题和技术总结输出,分享影响到更多的人;

  • 公众号专一:软件架构研究,技术学习与职业成长。内容涵盖:系统架构应用汇总、消息中间件、MySQL 实用探秘、职业认知升级 四大模块,你们能够在公众号底部菜单“精选专题”里随时查阅;

  • 你们看个人公众号头像图片像是一个陀螺,实际上是寓意螺旋式上升,让技术和自我可以不断精进。

文章首发于我的同名公众号《架构精进之路》,原文连接:2021年最新Redis面试题汇总,值得收藏

Thanks for reading!

相关文章
相关标签/搜索