说到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的文章就讲到这里了,希望对屏幕前的你能有所帮助。欢迎点赞关注。后续会出更多精彩内容