前言
我们继续写第一篇文章没写完的。其实我也不想将我写的一篇 Redis 文章分成几篇中短文来写,但是没办法,我一次写个1万字,会限流,所以将就一下吧。
上篇文章我用了 Redis 的6大模块这个思路来描绘我脑子中的 Redis。其实这6大模块已经包含了我知道的所有知识了。只不过上篇文章,我对 Redis 的5种数据类型和底层的6种数据结构详细描述了很多字,但是对于一些知识就一笔带过,所以这篇文章,我会详细的讲一下上篇文章讲的比较简略的地方。
Redis的三“高”
我感觉 Redis 的三高就是学习 Redis 的主线。因为 Redis 是一个庞大的、功能极其丰富的键值对数据库,关于 Redis 的知识实在是太多了,我之前学的时候就是学的很散,这里学一点,那里学一点。学一下持久化,又学一下缓存。学一下线程模型,又学一下主从复制。学确实是学了,而且感觉掌握的也还行,但是老是记不住。后来我想一下,因为我学的太散了,对这些知识形成不了一个体系,说白了就是构建不了一副属于 Redis 的知识全景图。关于这个三高,其实并不是我想的,是我看了一本书,里面那个作者用三高这条主线来讲述 Redis 的知识点的。我觉得他对于 Redis 的整个大框架的理解很清晰,我就借鉴了一下他的三高的思路,结合我自己的理解,构建了一个属于我自己的三高。
当然,Redis 肯定不止这么点知识,但是我就只会这么点哈哈哈哈。
高性能
Redis 之所以高性能,之所以快,离不开它的线程模型和数据结构。
线程模型
对于线程模型,我们刚刚已经分析了,Redis 在访问模块(网络IO线程模型)是单线程的,在操作模块,对每个读写键值对的请求,它的处理也是单线程的。为什么处理读写请求也要单线程呢?这是因为避免多线程带来的并发问题,而且说实话,你用多线程要加锁吧,要加各种乱七八糟的锁才能保证不会有并发问题出现,那样性价比不高啊,那还不如用单线程呢。插一句题外话,平时我们说的 Redis 是单线程,其实指的是网络IO和操作键值对是单线程,其它都是多线程,比如说数据持久化的时候,AOF 和 RDB 技术,一般用主线程来处理网络IO和操作键值对,而子线程用来记录日志或者内存快照。
数据结构
对于数据结构,那就更加 不用说了,Redis 中的索引模块用哈希表来保存所有键值对,使得 Redis可以很快的定位到某个键值对,从而对这个键值对进行操作。同时,对于 value 中,也提供了4种数据类型来保存数据,这5种数据类型的底层是6种数据结构:哈希表、整数数组、双向链表、压缩列表、动态字符串、跳跃表。正是因为这6种数据结构,才使得 Redis 又快又省。
高可靠性
其实 Redis 对于实现高可靠性的思路也就两种:要么尽量少丢数据,要么尽量服务少中断。这两种思路也很好理解,因为丢数据会导致 Redis 没那么可靠,而服务中断也会导致 Redis 没那么可靠。让数据尽量少丢也就是我们经常听到的数据持久化,数据持久化方式就两种:AOF日志和RDB快照。让服务尽量少中断的办法就是主从复制+哨兵机制。
数据尽量少丢(数据持久化)
Redis 如果宕机了,那 Redis 中的键值对数据就没了,所以必须要经常对 Redis 做持久化,也就是用一些技术将 Redis 中的数据用文件记录下来,如果 Redis 宕机了,通过这些文件就可以快速的恢复数据。其实同步并不一定就是将数据一条一条复制,这是最简单的同步,这样比较麻烦,关于数据持久化这里,Redis 用了两种不一样的同步方式:AOF日志和RDB快照。AOF就是 Redis 每处理一次数据,都将数据以命令的方式记录在一个日志里,一旦 Redis 挂了,直接拿着这个日志一条一条命令执行,就恢复了。但是这样子很慢啊,所以我们就引入了另一种技术:RDB快照。RDB快照就是每隔一段时间就给 Redis 的数据拍张照,然后 Redis 一旦宕机了,拿着这张照片恢复就好了。我刚刚说了,不知道是刚刚还是上篇文章,我忘了,我说 RDB 体现了 Redis 的多线程。为什么这么说呢?因为对于 Redis 而言,它的主线程是处理网络IO和操作键值对数据的,除了这两个要用主线程之外,其余的都是用子线程来完成的。比如说这里的RDB,通过 bgsave 创建一个子线程,在主线程一边处理网络IO和操作键值对的时候,子线程会复制 Redis 中的数据(以快照的方式复制),我们用一个专业的术语,写时复制。所以RDB采用 bgsave + 写时复制 的方式对 Redis 中的数据进行同步。问题是,快照的频率根本不好把握,频率太高浪费子线程资源,频率太低又怕数据丢失,所以一般都是采用 AOF+RDB 混合使用。
服务尽量少中断
这个感觉和 kafka 消息队列有点像。主从复制就是将一份数据保存在多个 Redis 副本上。听名字就知道了,“主”就是主 Redis,“从”就是副本 Redis。当主 Redis 挂了的时候,副本 Redis 随时顶上来,这个过程背后就用到了哨兵。哨兵的作用就是6个字:监控、选主、通知。具体是怎么搞的,细节我倒是没太理解,所以就不细说了,等我了解了再完善这里。
高可扩展
高可扩展主线就两个知识点:数据分片和负载均衡。其实严格意义上讲根本都算不上两个知识点,算一个知识:用数据分片的方式实现了负载均衡的思想。这是不是和 SpringIOC 很像:用依赖注入的方式实现了控制反转的设计思想。
数据分片
与其拘泥于数据分片的具体细节,倒不如讲讲为什么要进行数据分片。我们知道,在持久化的过程中,如果 Redis 的数据量很大的话,你用 Redis 是很难进行数据同步的,比如说你的 Redis 有 25G 的数据,你对这 25G 的数据进行数据持久化,那岂不是废了。所以我们就想着把 Redis 中的数据分成好几等份,然后通过 RDB+AOF 技术对每份数据进行同步,那这样同步就很快了,就像这样:
至于数据分片的一些具体细节,我就不细讲了,因为我还没学会哈哈哈哈,等我学会了我再来完善这里。
小结
在这一篇文章中,我讲了 Redis 的三高:高性能、高可靠、高可扩展。 Redis 之所以有高性能,是因为 Redis 的网络IO线程模型以及它底层的6种数据结构。Redis 之所以高可靠,是因为 Redis 中有 AOF和RDB,主从复制+哨兵机制这些技术。AOF 和 RDB 使得 Redis 宕机了客户以快速恢复,主从复制+哨兵机制是为了提高 Redis 的容错性,减少宕机时间。Redis 之所以可以扩展,是因为它采用数据分片的方式,使得 Redis 只需要添加分片既可获得扩展。
下篇文章,我们会讲 Redis 应用于缓存,也是最后一篇文章了!