走进 Redis,让你重新认识 redis。绝不是表面
说到 Redis 我们不禁的会联想到:缓存。提到缓存我们要聊的就有很多了。
为什么要使用缓存?
描述的官方一点就是使用缓存是为了提升系统的读写性能,可是在实际场景下,绝大数都是为了提高读性能,从而带来更高的并发。因为我们都知道在一个系统中最后一道防线就是 MySQL,同时呢 Redis 的读写性能又比 MySQL 高很多,所以我们就可以将 MySQL 中的热点数据放到 Redis 中从而减轻 MySQL 的压力;也可以更好的提升系统的整体性能。
为什么 Redis 那么快
我们都知道 Redis 是单线程模型。那么它为什么那么快呢?主要有以下几点:
C 语言实现,效率高(因为 C 是面向过程的编程语言,并且更接近底层)
单线程避免了多线程情况下频繁的上下文切换
基于非阻塞的 IO 复用模型机制(这有兴趣的小伙伴可以了解一下 IO 多路复用的机制)
纯内存操作
丰富的数据结构(hash 结构、跳跃表等)
还有一点是:偏向 计算向数据移动
如何去理解 Redis 的线程模型
上面我们有说到 Redis 是单线程模型,那么它为什么是单线程模型呢?
首先第一点 Redis 内部使用的是file event handler
文件事件处理器,这个文件事件处理器是单线程的。所以 Redis 才说是单线程模型,同时它又是采用非阻塞 IO 多路复用去监听多个 socket,根据 socket 上的事件来选择对应的事件处理器来处理。
聊到了文件事件处理器,那么它又包含什么呢?
多个 socket
IO 多路复用程序
文件事件分派器
事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
重点来了:我刚刚提到了会监听多个 socket,那么就一定会有多个 socket 可能会产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用会监听多个 socket,并且会将 socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,然后把该事件交给对应的事件处理器进行处理。
上重点看图说话:Redis 与客户端的一次通信过程
针对上图进行一个简单的解析
首先:客户端 socket 01 向 redis 的 server socket 请求建立连接,此时 Server Socket 会产生一个
AE_READABLE
事件,IO 多路复用程序监听到 server socket 产生的事件后,将该事件压入到队列中,文件事件分派器从队列中获取该事件交给连接应答处理器。连接应答处理器会创建一个能与客户端通信的 socket 01,并将 socket 01 的 AE_READABLE 事件与命令请求处理器关联。假设此时客户端发送了一个 set key value 的请求,此时 Redis 中的 socket 01 会产生一个 AE_READABLE 事件,IO 多路复用程序会将该事件压入队列中,此时事件分派器从队列中获取该事件,由于前面 socke 01 的 AE_READABLE 已经与命令请求处理器关联,因此事件分派器将事件交给命令请求处理器来处理。命令请求处理器读取 socket 01 的 set key value 并在自己的内存中完成设置,操作完成后,它会将 socket 01 的 AE_WRITABLE 事件与命令回复处理器关联
如果此时客户端已经做好了接收返回结果的准备,那么 Redis 中的 socket 01 会产生一个
AE_WRITABLE
事件,同样压入队列中,事件分派器找到相关联的命令回复处理器,由命令回复处理器对 socket 01 输入本次操作的一个结果,比如:ok。之后就会解除 socket 01 的AE_WIRTABLE
事件与命令回复处理器的关联。以上就是完成了一次客户端与 redis 的通信
我们上面简单对 Redis 的线程模型、以及通信进行了一个分析。这也是 redis 为什么快的原因之一,其中还有一个重要的原因就是 redis 是基于内存操作的,也是它速度快的一个重要因素,接下来我们就大概讲解一下 redis 为什么会基于内存去操作。
Redis 问什么要基于内存去操作数据?
最重要的原因就是快。首先我们应该有一个常识就是:
硬盘:
寻址速度:
寻址--毫秒 ms 级别的。
带宽:单位时间内能传输的字节流能有多少,几个 G 或几 M
高传输带宽在传输大块连续数据时具有优势
高 IOPS 在传输小块不连续的数据时具有优势
tips:
IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS 是指单位时间内系统能处理的 I/O 请求数量,I/O 请求通常为读或写数据操作请求。随机读写频繁的应用,如 OLTP(Online Transaction Processing),IOPS 是关键衡量指标。另一个重要指标是数据吞吐量(Throughput),指单位时间内可以成功传输的数据数量。对于大量顺序读写的应用,如 VOD(Video On Demand),则更关注吞吐量指标。
简而言之:
磁盘的 IOPS,也就是在一秒内,磁盘进行多少次 I/O 读写。
磁盘的吞吐量(指的是硬盘或设备(路由器/交换机)在传输数据的时候数据流的速度即使同一块硬盘在写入不同大小的数据时、表现出来的带宽也是不同的),也就是每秒磁盘 I/O 的流量,即磁盘写入加上读出的数据的大小。
内存
寻址速度
纳秒 ns 级别的。秒=1000 毫秒=1000*1000 微妙=1000*1000*1000 纳秒。在寻址上,磁盘比内存慢了 10 万倍。
听了上述的分析是不是大概知道了 redis 为什么这么快了呢。
以上就是 Redis 为什么会那么快,可是 Redis 没有弊端吗?
Reids 缺点:
由于是内存数据库,所以单台机器存储的数据量跟机器本身的内存大小有关。虽然 redis 本身有 key 过期策略,但是还是需要提前预估和节约内存。如果内存增长过快,需要定期删除数据
定时删除和定期删除为主动删除,Redis 会定期主动淘汰一批已过去的 key
惰性删除为被动删除,用到的时候才会去检验 key 是不是已过期,过期就删除过期的 key
惰性删除是 redis 服务器内置策略(过期的 key 对 aof 文件没有任何影响,删除过期的 key 时系统会向 aof 文件追加一条 del;如果 key 过期了但是没有删除,此时进行持久化操作这个 key 不会进入 aof 文件,因为没有发生修改指令)
如果进行完整重同步,由于需要生成 rdb 文件,并进行传输,会占用主机的 CPU,并会消耗现网的带宽。不过 redis2.8 版本以后,已经有部分重同步的功能,但是还是有可能有完整重同步的。比如,新上线的从库
修改配置文件,进行重启,将硬盘中的数据加载进内存,时间比较久。在这个过程中,redis 不能提供服务。
文章已开始讲的是缓存,从而引出了 Redis,可是作为缓存来讲不仅仅有 Redis,还有 Memcache 呢?
为什么使用 Redis 而不选择 Memcache 呢?
Redis 和 Memcache 都是将数据存放在内存中,都是内存数据库。不过 Memcache 还可用于缓存其他东西,例如图片、视频等等
Memcache 仅支持 key-value 结构的数据类型,Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,hash 等数据结构的存储。
虚拟内存– Redis 当物理内存用完时,可以将一些很久没用到的 value 交换到磁盘
分布式–设定 Memcache 集群,利用 magent 做一主多从; Redis 可以做一主多从。都可以一主多从
存储数据安全– Memcache 挂掉后,数据没了; Redis 可以定期保存到磁盘(持久化)
Memcache 的单个value最大 1m , Redis 的单个value最大 512m
。灾难恢复– Memcache 挂掉后,数据不可恢复; Redis 数据丢失后可以通过 aof 恢复
Redis 原生就支持集群模式, Redis3.0 版本中,官方便能支持Cluster模式了, Memcached 没有原生的集群模式,需要依赖客户端来实现,然后往集群中分片写入数据。
Memcached 网络 IO 模型是多线程,非阻塞 IO 复用的网络模型,原型上接近于 nignx 。而 Redis 使用单线程的 IO 复用模型,自己封装了一个简单的 AeEvent 事件处理框架,主要实现类 epoll,kqueue 和 select ,更接近于 Apache 早期的模式。
好了本次关于 Redis 的文章就讲到这里了,希望对屏幕前的你能有所帮助。欢迎点赞关注。后续会出更多精彩内容。
说到 Redis 我们不禁的会联想到:缓存。提到缓存我们要聊的就有很多了。
为什么要使用缓存?
描述的官方一点就是使用缓存是为了提升系统的读写性能,可是在实际场景下,绝大数都是为了提高读性能,从而带来更高的并发。因为我们都知道在一个系统中最后一道防线就是 MySQL,同时呢 Redis 的读写性能又比 MySQL 高很多,所以我们就可以将 MySQL 中的热点数据放到 Redis 中从而减轻 MySQL 的压力;也可以更好的提升系统的整体性能。
为什么 Redis 那么快
我们都知道 Redis 是单线程模型。那么它为什么那么快呢?主要有以下几点:
C 语言实现,效率高(因为 C 是面向过程的编程语言,并且更接近底层)
单线程避免了多线程情况下频繁的上下文切换
基于非阻塞的 IO 复用模型机制(这有兴趣的小伙伴可以了解一下 IO 多路复用的机制)
纯内存操作
丰富的数据结构(hash 结构、跳跃表等)
还有一点是:偏向 计算向数据移动
如何去理解 Redis 的线程模型
上面我们有说到 Redis 是单线程模型,那么它为什么是单线程模型呢?
首先第一点 Redis 内部使用的是file event handler
文件事件处理器,这个文件事件处理器是单线程的。所以 Redis 才说是单线程模型,同时它又是采用非阻塞 IO 多路复用去监听多个 socket,根据 socket 上的事件来选择对应的事件处理器来处理。
聊到了文件事件处理器,那么它又包含什么呢?
多个 socket
IO 多路复用程序
文件事件分派器
事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
重点来了:我刚刚提到了会监听多个 socket,那么就一定会有多个 socket 可能会产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用会监听多个 socket,并且会将 socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,然后把该事件交给对应的事件处理器进行处理。
上重点看图说话:Redis 与客户端的一次通信过程
针对上图进行一个简单的解析
首先:客户端 socket 01 向 redis 的 server socket 请求建立连接,此时 Server Socket 会产生一个
AE_READABLE
事件,IO 多路复用程序监听到 server socket 产生的事件后,将该事件压入到队列中,文件事件分派器从队列中获取该事件交给连接应答处理器。连接应答处理器会创建一个能与客户端通信的 socket 01,并将 socket 01 的 AE_READABLE 事件与命令请求处理器关联。假设此时客户端发送了一个 set key value 的请求,此时 Redis 中的 socket 01 会产生一个 AE_READABLE 事件,IO 多路复用程序会将该事件压入队列中,此时事件分派器从队列中获取该事件,由于前面 socke 01 的 AE_READABLE 已经与命令请求处理器关联,因此事件分派器将事件交给命令请求处理器来处理。命令请求处理器读取 socket 01 的 set key value 并在自己的内存中完成设置,操作完成后,它会将 socket 01 的 AE_WRITABLE 事件与命令回复处理器关联
如果此时客户端已经做好了接收返回结果的准备,那么 Redis 中的 socket 01 会产生一个
AE_WRITABLE
事件,同样压入队列中,事件分派器找到相关联的命令回复处理器,由命令回复处理器对 socket 01 输入本次操作的一个结果,比如:ok。之后就会解除 socket 01 的AE_WIRTABLE
事件与命令回复处理器的关联。以上就是完成了一次客户端与 redis 的通信
我们上面简单对 Redis 的线程模型、以及通信进行了一个分析。这也是 redis 为什么快的原因之一,其中还有一个重要的原因就是 redis 是基于内存操作的,也是它速度快的一个重要因素,接下来我们就大概讲解一下 redis 为什么会基于内存去操作。
Redis 问什么要基于内存去操作数据?
最重要的原因就是快。首先我们应该有一个常识就是:
硬盘:
寻址速度:
寻址--毫秒 ms 级别的。
带宽:单位时间内能传输的字节流能有多少,几个 G 或几 M
高传输带宽在传输大块连续数据时具有优势
高 IOPS 在传输小块不连续的数据时具有优势
tips:
IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS 是指单位时间内系统能处理的 I/O 请求数量,I/O 请求通常为读或写数据操作请求。随机读写频繁的应用,如 OLTP(Online Transaction Processing),IOPS 是关键衡量指标。另一个重要指标是数据吞吐量(Throughput),指单位时间内可以成功传输的数据数量。对于大量顺序读写的应用,如 VOD(Video On Demand),则更关注吞吐量指标。
简而言之:
磁盘的 IOPS,也就是在一秒内,磁盘进行多少次 I/O 读写。
磁盘的吞吐量(指的是硬盘或设备(路由器/交换机)在传输数据的时候数据流的速度即使同一块硬盘在写入不同大小的数据时、表现出来的带宽也是不同的),也就是每秒磁盘 I/O 的流量,即磁盘写入加上读出的数据的大小。
内存
寻址速度
纳秒 ns 级别的。秒=1000 毫秒=1000*1000 微妙=1000*1000*1000 纳秒。在寻址上,磁盘比内存慢了 10 万倍。
听了上述的分析是不是大概知道了 redis 为什么这么快了呢。
以上就是 Redis 为什么会那么快,可是 Redis 没有弊端吗?
Reids 缺点:
由于是内存数据库,所以单台机器存储的数据量跟机器本身的内存大小有关。虽然 redis 本身有 key 过期策略,但是还是需要提前预估和节约内存。如果内存增长过快,需要定期删除数据
定时删除和定期删除为主动删除,Redis 会定期主动淘汰一批已过去的 key
惰性删除为被动删除,用到的时候才会去检验 key 是不是已过期,过期就删除过期的 key
惰性删除是 redis 服务器内置策略(过期的 key 对 aof 文件没有任何影响,删除过期的 key 时系统会向 aof 文件追加一条 del;如果 key 过期了但是没有删除,此时进行持久化操作这个 key 不会进入 aof 文件,因为没有发生修改指令)
如果进行完整重同步,由于需要生成 rdb 文件,并进行传输,会占用主机的 CPU,并会消耗现网的带宽。不过 redis2.8 版本以后,已经有部分重同步的功能,但是还是有可能有完整重同步的。比如,新上线的从库
修改配置文件,进行重启,将硬盘中的数据加载进内存,时间比较久。在这个过程中,redis 不能提供服务。
文章已开始讲的是缓存,从而引出了 Redis,可是作为缓存来讲不仅仅有 Redis,还有 Memcache 呢?
为什么使用 Redis 而不选择 Memcache 呢?
Redis 和 Memcache 都是将数据存放在内存中,都是内存数据库。不过 Memcache 还可用于缓存其他东西,例如图片、视频等等
Memcache 仅支持 key-value 结构的数据类型,Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,hash 等数据结构的存储。
虚拟内存– Redis 当物理内存用完时,可以将一些很久没用到的 value 交换到磁盘
分布式–设定 Memcache 集群,利用 magent 做一主多从; Redis 可以做一主多从。都可以一主多从
存储数据安全– Memcache 挂掉后,数据没了; Redis 可以定期保存到磁盘(持久化)
Memcache 的单个value最大 1m , Redis 的单个value最大 512m
。灾难恢复– Memcache 挂掉后,数据不可恢复; Redis 数据丢失后可以通过 aof 恢复
Redis 原生就支持集群模式, Redis3.0 版本中,官方便能支持Cluster模式了, Memcached 没有原生的集群模式,需要依赖客户端来实现,然后往集群中分片写入数据。
Memcached 网络 IO 模型是多线程,非阻塞 IO 复用的网络模型,原型上接近于 nignx 。而 Redis 使用单线程的 IO 复用模型,自己封装了一个简单的 AeEvent 事件处理框架,主要实现类 epoll,kqueue 和 select ,更接近于 Apache 早期的模式。
好了本次关于 Redis 的文章就讲到这里了,希望对屏幕前的你能有所帮助。欢迎点赞关注。后续会出更多精彩内容
# 签约计划第三季 #
版权声明: 本文为 InfoQ 作者【派大星】的原创文章。
原文链接:【http://xie.infoq.cn/article/fd422211e603c2d5679f737d3】。文章转载请联系作者。
评论