做网站的相关规定,杭州品牌网站建设推广,在搜狐快站上做网站怎么跳转,沈阳网站建设58同城引言
Redis是个单线程程序#xff01;这点必须铭记。除了Redis之外#xff0c;Node.js也是单线程#xff0c;Nginx也是单线程#xff0c;但是他们都是服务器高性能的典范。
Redis单线程为什么能够这么快#xff01; 因为他所有的数据都在内存中#xff0c;所有的运算都…引言
Redis是个单线程程序这点必须铭记。除了Redis之外Node.js也是单线程Nginx也是单线程但是他们都是服务器高性能的典范。
Redis单线程为什么能够这么快 因为他所有的数据都在内存中所有的运算都是内存级别的运算。正因为Redis是单线程所以要小心使用Redis指令对于那些时间复杂度为O(n)级别的指令一定要谨慎使用一不小心可能就会导致Redis卡顿。
Redis单线程如何处理那么多的并发客户端连接 其答案就是多路复用。
非阻塞IO
Redis使用基于事件的非阻塞IO模型这种模型使得Redis能够在不阻塞主线程的情况下同时处理多个客户端连接。Redis使用IO多路复用技术通常是select、epoll、kqueue这取决于运行Redis的操作系统。这些技术允许单个线程监视多个文件描述符以检测是否有IO操作成为可能例如数据可读或者可写。
读写过程
读操作当客户端发送命令到Redis服务器时服务器使用非阻塞socket读取命令。命令读取完成后单线程执行命令并处理数据写操作处理完客户端命令后生成的输出将通过非阻塞socket发送回客户端如果数据无法一次性发送完毕例如输出缓冲区已满剩余的数据会被缓存并在socket可写时继续发送。
事件轮询多路复用
非阻塞IO有个问题那就是线程要读数据结果读了一部分就返回了线程如何知道何时才应该继续读。也就是当数据到来时线程如何得到通知写也是一样如果缓冲区满了写不完剩下的数据何时才能继续写线程也应该得到通知。
事件轮询API就是用来解决这个问题的最简单的事件轮询API是select函数他是操作系统提供给用户程序的API。输入是读写描述符列表read_fdswrite_fds, 输出是与之对应的可读可写事件。同时还提供了一个timeout参数如果没有任何事件到来那么就最多等待timeout时间线程处于阻塞状态。一旦期间有任何事件到来就可以立即返回。时间过了之后还是没有任何事件到来也会立即返回。拿到事件后线程就可以继续挨个处理相应的事件。处理完了继续过来轮询。于是线程就进入了一个死循环我们把这个死循环称为事件循环一个循环为一个周期。
每个客户端套接字socket都有对应的读写文件描述符。
read_events, write_events select(read_fds, write_fds, timeout)
for event in read_events:handle_read(event.fd)
for event in write_events:handle_write(event.fd)
handle_others() # 处理其它事情如定时任务等因为我们通过select系统调用同时处理多个通道描述符的读写事件因此我们将这类系统调用称为多路复用API。现代操作系统的多路复用API已经不再使用select系统调用而改用epoll(linux)和kqueue(freebsdmacosx)因为select系统调用的性能在描述符特别多时性能会非常差。他们使用起来可能在形式上略有差异但是本质上差不多都可以使用上面的伪代码进行理解。
服务器套接字serversocket对象的读操作指调用accept接受客户端新连接何时有新连接到来也是通过select系统调用的读事件来得到通知。
指令队列
Redis会将每个客户端套接字都关联一个指令队列客户端的指令通过队列来排队进行顺序处理先到先服务。
响应队列
Redis同样也为每个客户端套接字关联一个响应队列。Redis服务器通过响应队列来将指令的返回结果返回给客户端。如果队列为空那么意味着连接暂时处于空闲状态不需要去获取写事件也就是可以将当前的客户端描述符从write_fds里面移除等到队列有数据了再将描述符放进去避免select系统调用立即返回写事件如果发现没什么数据可以写。出这种情况的线程会飙高CPU。
定时任务
服务器除了要响应IO事件外还要处理其他事情。比如定时任务就是非常重要的一件事如果线程阻塞在select系统调用上定时任务将无法得到准时调度。那么Redis是如何解决的呢。
Redis的定时任务会记录在一个称为最小堆的数据结构中这个堆中最快要执行的任务排在堆的最上方在每个循环周期Redis都会将最小堆里面已经到点的任务立即进行处理。处理完毕后将最快要执行的任务还需要的时间记录下来这个时间就是select系统调用的timeout参数。因为Redis知道未来timeout时间内没有其他定时任务需要处理所以可以安心睡眠timeout时间。
总结
Redis单线程利用IO多路复用技术单线程监听多个文件描述符并进行事件轮询单线程循环轮询期间如果发生可读事件从缓冲区中读取事件并进行处理处理完后再将数据发送到写缓冲区写回给客户端。轮询通过select(read_fds, write_fds, timeout) 函数进行其中timeout为轮询阻塞时间。