Redis缓存那些事

Redis有哪些特性?

  • 性能高,读的速度是100000次/s,写的速度是80000次/s
  • 数据持久化,支持RDB、AOF
  • 支持事务。通过MULTIEXEC指令包起来
  • 多数据结构类型
  • 主从复制
  • 其他特性:发布/订阅、通知、key过期等

Redis为什么这么快?

  • 完全基于内存,没有磁盘IO的开销,异步持久化除外
  • 单线程,避免多线程切换造成的性能损耗
  • 非阻塞的IO多路复用机制
  • 底层的数据存储结构优化、使用原生的数据结构提升性能

Redis底层的基础数据结构有哪些?

  • 字符串:没有采用C语言的传统字符串,而是自己实现的一个简单动态字符串SDS的抽象类,并保存了长度信息。
  • 链表(linkedlist):双向无环链表结构,每个链表的结点由一个listNode结构来表示,每个节点都有前置和后置节点的指针。
  • 字典(hashtable):保存键值对的抽象数据结构,底层使用hash表,每个字典带有两个hash表,供平时使用和rehash时使用。
  • 跳跃表(skiplist):跳跃表是有序集合的底层实现之一。redis跳跃表由zskiplist和zskiplistNode组成,zskiplist用于保存跳跃表信息(表头、表尾节点、长度等),zskiplistNode用于表示条约节点,每个跳跃表的层高都是1~32的随机数,在同一个跳跃表中,多个节点可以包含相同的分值,但是每个节点的成员对象都必须是唯一的,节点按照分值大小排序,如果分值相同,则按照成员对象的大小排序。
  • 整数集合(intset):用于保存整数值的集合抽象数据结构,不会出现重复元素,底层实现为数组。
  • 压缩列表(ziplist):为了节约内存而开发的顺序性数据结构,可以包含多个节点,每一个节点可以保存一个字节数组或整数值。

Redis支持哪些数据类型?

五种常用数据类型:StringHashSetListSortedSet。三种特殊的数据类型:BitmapHyperLogLogGeoSpatial,其中Bitmap、HyperLogLog的底层都是String数据类型,Geospatial底层是Sorted Set数据类型。

  • 字符串对象String:int整数、embstr编码的简单动态字符串、raw简单动态字符串
  • 列表对象list:ziplist、linkedlist
  • 哈希对象hash:hashtable、ziplist
  • 集合对象set:hashtable、intset
  • 有序集合对象zset:ziplist、skiplist

Redis常用的5种数据结构和应用场景?

  • String:缓存、计数器、分布式锁等
  • List:链表、队列、微博关注人时间轴列表等
  • Hash:用户信息、Hash表等
  • Set:去重、赞、踩、共同好友等
  • Zset:访问量排行榜、点击量排行榜等

为什么采用的单线程?

官方回复,CPU不会成为Redis的制约瓶颈,Redis主要受制于内存、网络限制。例如,在一个普通的Linux系统上,使用pipelining可以每秒传递100万个请求,所以如果您的应用程序主要使用O(N)或O(logN)命令,则几乎不会使用太多的CPU,属于IO密集型系统。

Redis 6.0 之后又改用多线程呢?

Redis的多线程主要是用来处理数据的读写、协议解析。执行命令还是采用单线程顺序执行。

主要是因为redis的性能瓶颈在于网络IO而非CPU,使用多线程进行一些周边预处理,提升IO的读写效率,从而提升了整体的吞吐量。antirez在RedisConf 2019分享时提到,Redis 6 引入的多线程IO对性能提升至少在一倍以上。

过期Key的删除策略有哪些?

有三种过期删除策略。惰性删除、定期删除、定时删除

  • 惰性删除:使用key时才进行检测,如果已经过期,则删除。缺点:过期key如果一直没有被访问到,一直无法删除,一直占用内存,造成空间浪费。
  • 定期删除:每隔一段时间做一次检查,删除过期的key,每次只是随机去一些key去检查
  • 定时删除:为每个key设置过期时间,同时创建一个定时器。一旦到期,立即执行删除。缺点:如果过期键比较多时,占用CPU比较多,对服务的性能影响很大。

如果Redis的内存空间不足,淘汰机制?

  • volatile-lru:从已设置的过期时间的key中,移除最近最少使用的key进行淘汰
  • allkeys-lru:当内存不足以容纳新写入的数据时,再键空间中,移除最近最少使用的key(这个是最常用的)
  • volatile-ttl:从已设置过期时间的key中,移除即将要过期的key
  • volatile-random:从已设置过期时间的key中,随机选择key淘汰
  • allkeys-random:从key中随机选择key进行淘汰
  • no-eviction:禁止淘汰数据,当内存达到阈值的时候,新写入操作报错
  • volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰(LFU(Least Frequently Used)算法,也就是最频繁被访问的数据将来最可能被访问到)
  • allkeys-lfu:当内存不足以容纳新写入的数据时,在键空间中,移除最不经常使用的key

Redis突然挂了怎么解决?

  1. 从系统可用性角度思考,Redis Cluster引入主备机制,当主节点挂了后,自动切换到备用节点,继续提供服务。
  2. Client端引入本地缓存,通过开关切换,避免Redis突然挂掉,高并发流量把数据库打垮。

Redis持久化有哪些方式?

  1. 快照RDB。将某个时间点上的数据库状态保存到RDB文件中,RDB文件是一个压缩的二进制文件,保存在磁盘上。当Redis崩溃时,可用于恢复数据。通过SAVEBGSAVE来来生成RDB文件。
    • SAVE:会阻塞redis进程,直到RDB文件创建完成,在进程阻塞期间,redis不能处理任何命令请求。
    • BGSAVE:会fork出一个子进程,然后由子进程负责生成RDB文件,父进程还可以继续处理命令请求,不会阻塞进程。
  2. 只追加文件AOF。以日志的形式记录每个写操作(非读操作)。当不同的节点同步数据时,读取日志文件中的内容将写指令从前到后执行一次,既可以完成数据的恢复。

Redis常用场景

  1. 缓存
  2. 分布式锁,利用Redis的setnx
  3. 分布式session
  4. 计数器,通过incr命令
  5. 排行榜,Redis的有序集合
  6. 其他

Redis缓存要注意的七大经典问题?

列举了亿级系统,高访问量情况下Redis缓存可能遇到哪些问题?以及对应的解决方案。

  1. 缓存集中失效
  2. 缓存穿透
  3. 缓存雪崩
  4. 缓存热点
  5. 缓存大key
  6. 缓存数据一直性
  7. 数据并发竞争预热

每个问题的详细解决方案可以参考Redis缓冲穿透Redis缓存失效和缓存雪崩以及热点缓存key重建优化亿级系统的Redis缓存如何设计??

Redis集群方案有哪几种?

  • 主从复制模式
  • Sentinel(哨兵)模式
  • Redis Cluster模式

Redis主从数据同步(主从复制)的过程?

  1. slave启动后,会向master发送sync同步命令
  2. master收到sync之后,执行bgsave保存快照,生成RDB全量文件
  3. 如果在生成RDB全量快照的过程中,有写命令请求,则将写命令请求记录到临时缓存中
  4. bgsave执行完毕之后,将RDB全量文件发送到slave节点
  5. slave清除缓存中的数据,并将RDB中的二进制数据加载到缓存中,
  6. master发送临时缓存区中写命令给slave,slave接收到写命令并依次顺序执行写命令,将数据加载到缓存中,完成数据初始化
  7. 此后,master会和slave保持长连接,master每次执行一个写命令都会发送给slave,保持master与slave之间数据的一致性

主从复制的优缺点?

优点

  • master能自动将数据同步到slave,可以进行读写分离,分担master的读压力
  • master、slave之间的同步是以非阻塞的方式进行的,同步期间,客户端仍然可以提交查询或更新请求

缺点

  • 不具备自动容错与恢复功能,master节点宕机后,需要手动指定新的master
  • master宕机,如果宕机前数据没有同步完,则切换IP后会存在数据不一致的问题
  • 难以支持在线扩容,Redis容量受限与单机配置

Sentinel(哨兵)模式的优缺点?

哨兵模式基于主从复制模式,增加了哨兵来监控自动处理故障

优点

  • 哨兵模式基于主从复制模式,所以主从模式有的优点,哨兵模式也有
  • master节点挂掉之后可以自动进行切换,系统可用性更高

缺点

  • Redis的容量受限于单机配置
  • 需要额外的资源来启动Sentinel进程

Redis Cluster模式的优缺点?

实现了Redis的分布式存储,即每台节点都存储不同的内容,来解决在线扩容的问题。

优点

  • 无中心架构,数据按照slot分布在多个节点
  • 集群中的每个节点都是平等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。
  • 可在线扩容到1000多个节点,节点可以动态添加或删除
  • 能够实现自动故障转移,节点之间通过gossip协议交换状态信息,用投票机制完成slave到master的角色转换

缺点

  • 数据通过异步复制,不保证数据的强一致性
  • slave充当“冷备”,不对外提供读、写服务,只作为故障转移使用
  • 批量操作限制,目前只支持具有相同slot值的key执行批量操作,对mset、mget、sunion等操作支持不友好
  • key事务操作支持有限,只支持多key在同一个节点的事务操作,多个key分布在不同的节点是无法使用事务功能
  • 不支持多数据库空间,一台Redis可以支持16个db,集群模式下只能使用一个,即db 0。Redis Cluster模式不建议使用pipeline和multi-keys操作,减少max redirect产生的场景

Redis如何做扩容?

为了避免数据迁移失败,通常使用一致性哈希实现动态扩容缩容,有效减少需要迁移的key数量。

但是Cluster模式,采用固定Slot槽位方式(16384个),对每个key计算CRC16值,然后对16384取模,然后根据slot值找到目标机器,扩容时,我们只需要迁移一部分的slot到新节点即可。

Redis的集群原理?

一个redis集群由多个node节点组成,而多个node节点之间通过cluster meet命令来进行连接,组成一个集群。

数据存储通过分片的形式,整个集群分成16384个slot,每个节点负责一部分槽位。整个槽位的信息会同步到所有节点中。

key与slot的映射关系:

  • 键值对key,进行CRC16计算,计算出一个16 bit 的值
  • 将16 bit 的值对16384取模,得到0~16384的数字表示key对应的哈希槽

Redis如何做到高可用的?

哨兵机制。具有自动故障转移、集群监控、消息通知等功能。

哨兵可以同时监控所有的主、从服务器,当某个master下线时,自动提升对应的slave为master,然后由新的master对外提供服务。

什么时Redis事务?

Redis事务是一组命令的集合,将多个命令打包,然后把这些命令按顺序添加到队列中,并且顺序执行这些命令。

Redis事务中没有像Mysql关系型数据库中事务隔离级别的概念,不能保证原子性操作,也没有像Mysql那样执行事务失败会进行事务回滚操作。

Redis事务执行流程?

通过MULTIEXECWATCH等命令来实现事务机制,事务执行过程将一系列多个命令按照顺序一次性执行,在执行期间,事务不会被中断,也不会执行客户端的其他请求,直到所有命令执行完毕。

具体过程:

  • 服务端收到客户端请求,事务以MULTI开始
  • 如果正处于事务状态时,则会把后续命令放入队列同时返回给客户端QUEUED,反之直接执行这个命令
  • 当收到客户端的EXEC命令时,才会将队列里的命令取出、顺序执行、执行完将当前事务状态改为非事务状态
  • 如果收到DISCARD命令,放弃执行队列中的命令,可以理解为Mysql中的回滚操作,并且将当前的事务状态改为非事务状态

WATCH监视某个key,该命令只能在MULTI命令之前执行。如果监视的key被其他客户端修改,EXEC将会放弃执行队列中的所有命令。UNWATCH取消监视之前通过WATCH命令监视的key。通过执行EXEC、DISCARD两个命令之前监视的key也会被取消监视。

Redis与Guava、Caffeine 有什么区别?

缓存分为本地缓存和分布式缓存。

1、Caffeine、Guava,属于本地缓存,特点:

  • 直接访问内存,速度快,受内存限制,无法进行大数据存储。
  • 无网络通讯开销,性能更高。
  • 只支持本地应用进程访问,同步更新所有节点的本地缓存数据成本较高。
  • 应用进程重启,数据会丢失。

所以,本地缓存适合存储一些不易改变或者低频改变的高热点数据。

2、Redis属于分布式缓存,特点:

  • 集群模式,支持大数据量存储
  • 数据集中存储,保证数据的一致性
  • 数据跨网络传输,性能低于本地缓存。但同一个机房,两台服务器之间请求跑一个来回也就500微秒,比起其优势,这点损耗完全可以忽略,这也是分布式缓存受欢迎的原因。
  • 支持副本机制,有效保证高可用性

如何实现一个分布式锁?

  1. 数据库表,性能比较差
  2. 使用Lua脚本(包括 Setnx + expire 两条指令)
  3. set的扩展命令(set key value [ex][px] [NX|XX])
  4. Redlock框架
  5. Zookeeper Curator框架提供了现成的分布式锁。
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信