咱们常常听到说Redis是单线程的,也会有疑问:为何单线程的Redis能那么快?网络
这里要明白一点:Redis是单线程,主要是指Redis的网络IO和键值对读写是由一个线程来完成的,这也是Redis对外提供键值存储服务的主要流程。但Redis的其余功能,好比持久化、异步删除、集群数据同步等,都是由额外的线程执行的。数据结构
咱们知道多线程可以提高并发性能,那为何Redis会采用单线程,而非多线程?为何单线程能那么快?多线程
下面咱们就来学习一下Redis采用单线程的缘由。并发
使用多线程,虽然能够增长系统吞吐率,或是增长系统扩展性,但一样会产生开销。异步
Redis的数据是在内存里的,是共享的,若是使用多线程就会引起共享资源的竞争,须要引入互斥锁来解决,使得并行变串行。最终系统吞吐率并无随着线程的增长而增长。socket
另外,多线程开发须要精细的设计,会增长系统的复杂度,下降代码的易调试性和可维护性。为了不这些问题,Redis采用单线程模式。函数
一般来讲,单线程的处理能力比多线程要差不少,那Redis却能使用单线程模型达到每秒数十万级别的处理能力,这是为何呢?高并发
一方面,Redis大多数操做是在内存上完成的,而且采用高效的数据结构,例如哈希表和跳表。另外一方面,Redis采用了多路复用机制,使其在网络IO操做中能并发处理大量的客户端请求,实现高吞吐率。性能
在学习多路复用机制前,咱们要弄明白网络操做的基于IO模型和潜在的阻塞点。学习
以Get请求为例,为了处理一个Get请求:
下图显示了这一过程,其中,bind/listen、accept、recv、parse和send属于网络IO处理,而get属性键值数据操做。
可是在这里的网络IO操做中,有潜在的阻塞点,分别是accept()和recv()。
这就致使Redis整个线程阻塞,没法处理其余客户端请求,效率很低。不过,幸运的是,socket网络模型自己支持非阻塞模式。
Socket网络模型能够设置非阻塞模式。
这样能保证Redis线程既不会像基本IO模型中一直在阻塞点等待,也不会致使Redis没法处理实际到达的链接请求或数据。
下面就到多路复用机制登场了。
Linux的IO多路复用机制是指一个线程处理多个IO流,也就是select/epoll机制。
在Redis运行单线程下,该机制容许内核中,同时存在多个监听套接字和已链接套接字。
为了在请求到达时能通知到Redis线程,select/epoll提供了基于事件的回调机制,即针对不一样事件的发生,调用相应的处理函数。
回调机制的工做流程:
由于Redis一直在对事件队列进行处理,因此能及时响应客户端请求,提高Redis的响应性能。
不过,须要注意的是,在不一样的操做系统上,多路复用机制也是适用的。
在“Redis基本IO模型”图中,有哪些潜在的性能瓶颈?
Redis单线程处理IO请求性能瓶颈主要包括2个方面:
一、任意一个请求在server中一旦发生耗时,都会影响整个server的性能 也就是说后面的请求都要等前面这个耗时请求处理完成,本身才能被处理到。
耗时的操做包括:
解决办法:
二、并发量很是大时,单线程读写客户端IO数据存在性能瓶颈,虽然采用IO多路复用机制,可是读写客户端数据依旧是同步IO,只能单线程依次读取客户端的数据,没法利用到CPU多核。
解决办法: