Redis为何如此之快?


Redis基本是内存操作,因此速度很快。

内存:

  1. 寻址时间:纳秒级别ns
  2. 带宽:很大

磁盘:

  1. 寻址时间:毫秒级别ms
  2. 带宽:G/M

磁盘比内存寻址慢了10w倍以上,因此单机Redis能支持10w以上的请求


  • Redis通信采用非阻塞IO,内部实现采用epoll+自己实现简单的事件框架。epoll中的读、写、关闭、连接都转换成了事件,然后利用epoll的多路复用特性,绝不会在IO上浪费一点时间。
  • 单机Redis采用单进程、单线程、单实例,避免了不必要的上下文切换和竞争条件。 

可能很多人会认为要想系统的处理速度快不是应该使用多线程技术。但是,Redis的数据都是放在内存中,查询存储延时非常小,是纳秒级别的,因此若使用多线程,就需要加锁,系统资源还需要在线程之间进行上下文切换,反而会影响性能。单进程、单线程天生就保证了请求的顺序执行,不需要加锁,也没有了不必要的上下文切换的环节,因此可以将硬件的性能发挥到极致。

Redis快的根源 

  1. 绝大部分请求(读写等操作)是纯粹的内存操作(非常快速,ns级别);
  2. 采用单线程,避免了不必要的上下文切换和竞争条件;
  3. 非阻塞IO-IO多路复用(epoll);

总之,这三个条件不是相互独立的,特别是第一条,如果请求都是耗时的,采用单线程吞吐量以及性能可想而知了。应该说Redis为特殊的场景选择了合适的技术方案。

 Redis高性能与epoll多路复用

Epoll的高性能如何成就了Redis?

IO模型BIO、NIO、多路复用I/O、AIO

1.阻塞I/O(Blocking I/O BIO)

  • 应用程序进程/线程如果发起1k个请求,则开启1k个socket文件描述符号,socket在等待内核返回数据时是阻塞的,数据未准备好就一直阻塞等待,一次只会返回一个socket结果,直到返回数据后才等待下一个socket的返回。

Redis高性能与epoll多路复用

 

2.轮询非阻塞I/O(Non-Blocking I/O NIO)

  • 应用程序如果发起1k个请求,则在用户空间不停轮询这1k个socket文件描述符,查看是否有结果返回。这种方法虽然不会发生阻塞,但是效率太低,有大量无效的循环。

Redis高性能与epoll多路复用

3.多路复用I/O(Multiplexing I/O)

  • select:能打开的文件描述符个数有限(最多1024个),如果有1k请求,用户进程每次要把1k个文件描述符发送给内核,内核在内部轮询后将可读描述符返回,用户进程再依次读取。因为文件描述符(fd)相关数据需要在用户态和内核态之间拷来拷去,所以性能还是比较低;
  • poll:可打开的文件描述符数量提高,因为用链表存储,但性能仍然不够,和select一样数据需要在用户态和内核态拷来拷去;
  • epoll(Linux下多为技术):用户态和内核态之间不用文件描述符(fd)的拷贝,而是通过mmap技术实现开辟共享空间,所有fd用红黑树存储,有返回结果的fd放在链接中,用户进程通过链表读取返回结果,伪异步I/O,性能较高。epoll分为水平触发和边缘触发这两种模式,ET是边缘触发,LT是水平触发,一个表示只有在变化的边际触发,一个表示在某个阶段都会触发;

 Redis高性能与epoll多路复用

Redis高性能与epoll多路复用

4.异步I/O AIO

AIO:

  • 异步I/O,性能最高,但是使用非常复杂,不是很常用,Linux还是选用epoll实现;

 Redis高性能与epoll多路复用

相关文章: