一张图带你搞懂 Redis

最近,为了能够更系统地学习 Redis,我自己通过脑图的方式对 Redis 的基础内容进行了梳理,在这里分享给大家,感兴趣的小伙伴可以收藏保存。

65398c7d331842ee87dcf652d7dcd4df.png

数据结构

对于数据结构部分,作者主要从三个方面进行了介绍,其中包括 Redis 值的数据结构、底层数据结构,以及 Redis 是如何保存所有键值对的。

值的数据结构

对于值的数据结构,主要分为两种,一种是简单动态字符串(String),另外一种是集合类型,其中包括 List、Hash、Set、Sorted Set。

底层数据结构

对于底层数据结构来说,Redis 为了提升性能,主要采用了双向链表、压缩列表、哈希表、跳表以及整数数组五种,相应数据结构的时间复杂度大家也可以在脑图中查看。

哈希表存储键值对

那 Redis 又是如何保存所有键值对的呢?

其实是采用哈希表的方式。

对于哈希表,其实就类似一个数组,每个元素是一个哈希桶,哈希桶中保存的是指向具体值的指针。

而在使用哈希表进行存储的时候,又会出现哈希冲突的问题,所以 Redis 采用 rehash 和渐进式 rehash 的方式进行了处理。这两种方式在这里就不展开介绍了,感兴趣的小伙伴可以去了解一下。

高性能IO模型

对于高性能 IO 模型,作者主要从 Redis 是不是单线程、Redis 单线程的设计机制以及多路复用机制这三部分进行了讨论。

单线程设计机制

首先,Redis 对于网络 IO 和键值对读写都是采用单线程的,而对于持久化、异步删除、集群数据同步等功能是由额外的线程执行的。

至于单线程 Redis 为什么快,主要有三个原因:

  1. 大部分操作是在内存上执行的;
  2. 使用了高效的数据结构,例如哈希表和跳表;
  3. 采用了多路复用机制,可以在网络 IO 操作中能够并发处理大量的客户端请求;

多路复用机制

而对于多路复用机制,主要指的是 select/epoll 机制,这个机制允许内核中同时存在多个监听套接字和已连接套接字,内核会一直监听套接字上的连接请求和数据请求。

此外,为了能在请求到达时通知 Redis 线程,select/epoll 机制提供了基于事件的回调机制,对于不同事件的发生,调用相应的处理函数。对于操作系统以及 IO 感兴趣的小伙伴,可以重点学习一下这部分内容。

持久化 

对于持久化,Redis 主要提供了两种持久化方式,一种是 AOF(Append Only File)日志,另外一种是 RDB(Redis Database)内存快照。

AOF

首先,我们来说说 AOF。

为了实现 Redis 数据持久化以及防止服务器宕机造成的数据丢失,Redis 会将写操作命令以写后日志的方式记录在磁盘上。

写后日志指的就是执行完一条命令,往日志中记录一条。这样做的好处有两点:

  1. 能够避免额外的检查开销,不会将错误命令记录到日志中;
  2. 不会阻塞当前的写操作;

但同样也存在一些风险:

  1. 宕机会导致相关数据的丢失;
  2. 阻塞下一个操作;

因此,为了避免上述风险,控制 AOF 日志写回磁盘的时机,Redis 采用了三种写回策略,我们可以通过 AOF 配置项 appendfsync 进行配置:

  1. Always(同步写回):执行一次操作,就立马写回磁盘;
  2. Everysec(每秒写回):每隔一秒把 AOF 文件内存缓冲区中的内容写回磁盘;
  3. No(操作系统控制写回):由操作系统决定何时将缓冲区内容写回磁盘;

虽然我们控制了写回磁盘的时机,但是随着接收写命令越来越多,AOF 文件越来越大也会带来性能问题。因此,就有了 AOF 的重写机制。

重写机制实际上就是“多变一”的过程。将旧日志中的多条命令,通过重写,优化成新日志中的一条命令。而且 Redis 也利用了 fork 函数以及 Copy-On-Write 机制避免了 AOF 重写的阻塞。

RDB

其次,我们再来说说 RDB。

RDB 内存快照的方式有点类似于拍照片,把某一个时刻内存中的数据以文件的形式写到磁盘上。与 AOF 相比,在做数据恢复的时候,我们可以直接把 RDB 文件读入内存,很快地完成恢复。

Redis 主要是通过 save 和 bgsave 这两个命令生成 RDB文件的,区别在于 bgsave 不会阻塞线程,而是创建一个子进程,专门用于写入 RDB 文件。

Redis 4.0 开始混合使用 AOF 日志和内存快照

简单来说就是,以一定频率执行内存快照,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

AOF 和 RDB 该如何选择

那对于 AOF 日志和 RDB 内存快照这两种方式,我们又该如何选择呢?

以下有三点建议:

  1. 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;
  2. 如果允许分钟级别的数据丢失,可以只使用RDB;
  3. 如果只用 AOF,优先使用 Everysec 配置选项,因为它在可靠性和性能之间取了一个平衡;

数据同步

Redis 除了使用数据持久化 AOF 和 RDB 这两种方式保证高可靠性外,为了保证服务尽量少中断,还采用了主从库的模式,支持读写分离以及主从库之间的数据同步。

主从同步

对于主从同步,主要可以分为三个阶段:

  1. 主从库之间建立连接,协商同步;
  2. 主库执行 bgsave 命令,生成 RDB 文件,发送给从库;
  3. 主库将 replication buffer 中的新写命令发送给从库;

主从级联模式

而为了分担全量复制时主库压力,Redis 也支持主从级联模式。

主从库网络断开怎么办

那么,你可能会问,如果主从库之间的网络断开了怎么办,连接恢复后该如何同步数据?

Redis 2.8 开始支持了主从库之间的增量复制,主要依赖于 repl_backlog_buffer 环形缓冲区和 replication_buffer 进行实现。这部分比较复杂,在这篇文章里就不展开讲了。

哨兵机制和哨兵集群

为了能更好的监控主库和从库的状态,提升高可靠性,Redis 还推出了哨兵机制。(感觉有点类似于监工哈哈)

哨兵机制主要分为三部分,其中包括监控选主以及通知

监控

哨兵会通过周期性 PING 的方式来判断主从库的在线状态,如果响应超时,就会被哨兵判定为“主观下线”。

那 Redis 又是如何解决哨兵误判主库下线问题的呢?

那么这里就引出了一个概念,哨兵集群。Redis 使用多个哨兵一起监控主库状态,一旦多数哨兵判断主库为下线状态,那这个主库就会被判定为“客观下线”。

选主

那主库被判定为“客观下线”后,又是怎样选择新主库的呢?

首先,Redis 会从是否在线以及之前的网络状态情况两个方面对从库进行筛选。

筛选之后就会对从库进行打分,打分主要有三个原则:

  1. 优先级最高的从库得分高;
  2. 和旧主库同步程度最接近的从库得分高;
  3. 从库ID号小的得分高;

那选择好了新的主库,由哪个哨兵来执行主从切换呢?这里就需要讲一下 Leader 选举的过程了。

哨兵在判定主库为“主观下线”状态后,就会给其他哨兵发送投票请求,告诉其他哨兵希望由自己来执行主从切换,并让所有哨兵进行投票。在投票过程中,任何一个想成为 Leader 的哨兵,都需要满足以下两个条件:

  1. 拿到半数以上的赞成票;
  2. 拿到的票数同时还要大于等于哨兵配置文件中的 quorum 值。

通知

切换好新主库之后,哨兵就需要通知客户端新主库的相关信息了。

这里主要基于 Redis 的 pub/sub 消息订阅机制。客户端可以通过哨兵提供的消息订阅频道获取一些事件的通知,包括主库下线事件、从库重新配置事件、新主库切换事件等。

切片集群

讲完了 Redis 的高可靠性之后,Redis 又是怎样实现高可扩展性的呢?

为了能够保存更多的数据,实现横向扩展,官方从 3.0 开始提供了 Redis Cluster 的方案,用于实现切片集群。

哈希槽

切片集群使用哈希槽来处理数据和实例之间的映射关系。一个切片集群共有 16384 个哈希槽,在创建集群的时候,Redis 会自动将这些哈希槽平均分配到集群实例上。我们也可以手动调整每个实例上的哈希槽个数,从而解决不同实例配置差异造成的影响。 

如何定位数据

那将数据存储在多个实例上,客户端又是如何定位数据的呢?

首先,客户端和集群实例建立连接之后,实例会将哈希槽的分配信息发给客户端。客户端会在本地缓存中缓存哈希槽的信息。

但是,在集群中,实例和哈希槽的对应关系并不是一成不变的,比如,实例有新增或删除。

对于这种情况,Redis 就需要重新分配哈希槽了。

那么,为了解决数据定位的问题,Redis Cluster 提供了一种重定向机制,也就是说如果客户端给一个实例发送数据读写操作时,这个实例上并没有相应的数据,那么客户端就需要再给一个新实例发送操作命令。

总结

以上就是基础篇的全部内容了,有些地方可能讲的不够细或是有问题的地方欢迎大家指正。也希望大家能够通过这篇文章,对 Redis 有一个整体的了解,从这篇文章开始,更加深入的学习 Redis。

 

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值