[Redis]redis为什么这么快?

目录

1. Redis为什么这么快?

1.1 阻塞I/O

1.2 非阻塞I/O

1.3 I/O多路复用

2  redis中的多路复用模型?

2.1 什么是事件驱动

2.2 为什么redis不使用Libevent?

2.3 总结


1. Redis为什么这么快?

1)纯内存操作

2)单线程,无锁竞争损耗(但是redis即将迎来多线程版本?!!)

3)C语言实现,更接近底层操作

4)多路I/O复用模型,非阻塞IO

5)数据结构简单,底层又做了优化

6)源码精湛、简短

1.1 阻塞I/O

通常的IO操作都是阻塞I/O,也就是调用read的时候,如果数据没有收到,那么线程或者进程会挂起,直到收到数据。

阻塞的意思,就是一直等着。应用的函数长时间处于等待结果的状态,我们就称为阻塞I/O。

1.2 非阻塞I/O

调用read时,如果有数据收到,就返回数据,如果没有数据收到,就立刻返回一个错误,如EWOULDBLOCK。

但是应用设计必须持续过来找服务提供者,知道能够得到数据。

1.3 I/O多路复用

多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符(FileDescription,简称FD),如果有一个文件描述符(FileDescription)就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)。

就是派一个代表,同时监听多个文件描述符是否有数据到来。等着等着,如有有数据,就告诉某某你的数据来啦!赶紧来处理吧。

2  redis中的多路复用模型?

同样基于内存的别的数据库Memcached,单进程多线程的;

但是redis并不比它差。

redis主要是完全依赖于内存,数据结构简单。而且使用多路复用I/O。

跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务,而 I/O 多路复用就是为了解决这个问题而出现的。

Redis,为了将所有的IO复用统一,Redis 为所有 IO 复用统一了类型名 aeApiState。

select, poll, epoll 都是I/O多路复用的具体的实现。epoll性能比其他几者要好。redis中的I/O多路复用的所有功能通过包装常见的select、epoll、evport和kqueue这些I/O多路复用函数库来实现的。

划重点,那么redis是包装常见的I/O多路服用库来实现的。

以epoll举例:

对epoll接口的封装了,包括创建 epoll(epoll_create),注册事件(epoll_ctl),删除事件(epoll_ctl),阻塞监听(epoll_wait)等
创建 epoll 就是简单的为 aeApiState 申请内存空间,然后将返回的指针保存在事件驱动循环中
注册事件和删除事件就是对 epoll_ctl 的封装,根据操作不同选择不同的参数
阻塞监听是对 epoll_wait 的封装,在返回后将激活的事件保存在事件驱动中

2.1 什么是事件驱动

IO 复用的封装实现完成,那么 Redis 是何时调用 IO 复用函数的呢,这就需要从 server.c/main 函数入手,可以猜测到当 main 函数初始化工作完成后,就需要进行事件驱动循环,而在循环中,会调用 IO 复用函数进行监听
在初始化完成后,main 函数调用了 aeMain 函数,传入的参数就是服务器的事件驱动

Redis 对于时间事件是采用链表的形式记录的,这导致每次寻找最早超时的那个事件都需要遍历整个链表,容易造成性能瓶颈。而 libevent 是采用最小堆记录时间事件,寻找最早超时事件只需要 O(1) 的复杂度

Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要是用于事件驱动。

2.2 为什么redis不使用Libevent?

Redis 为何不使用 libevent 和 libev 事件库,而是要实现自己的事件库

1. libevent 太大了,比 Redis 的代码库还大 3 倍左右。

2.Redis 作为一个 NOSQL 数据库,不想引入太大的外部依赖

3.第三方库如果出现一些意想不到的 bug,会影响到 Redis。

4.方便 Redis 做定制化开发。

5. libev 虽然小,但是它没有提供 HTTP 之类的高级功能。

 

2.3 总结

I/O 多路复用模型是利用select、poll、epoll可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll是只轮询那些真正发出了事件的流),依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。这里“多路”指的是多个网络连接“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。

redis内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性。

epoll读音有点类似apple 

参考:https://www.jianshu.com/p/603de8774734

           https://www.xttblog.com/?p=4594

           https://blog.csdn.net/diweikang/article/details/90346020

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值