美文网首页
3. 高性能IO模型,探究Redis单线程为何很快

3. 高性能IO模型,探究Redis单线程为何很快

作者: one_8274 | 来源:发表于2020-09-27 00:20 被阅读0次

    1. Redis单线程

    • 通常说Redis单线程是指Redis的网络IO和键值对读写是由一个线程完成的
    但Redis的其他功能,比如持久化,异步删除,集群数据同步等都是由额外的线程完成的
    

    2. 为什么Redis使用单线程


    2.1 多线程的开销

    • 问题:
      • 通常情况,假如没有良好的设计,在刚开始增加线程数时,吞吐率会有所增加,但进一步增加线程时,吞吐率就会增长迟缓甚至会出现下降情况
    • 原因:
      • 系统中常会存在被多线程同时访问的共享资源,比如一个共享的数据结构,当多个线程要修改共享资源时,就要有额外的机制来保证共享资源准确性,就会带来额外的开销
      • 比如,redis中的lpush和lpop操作,假如两个线程同时对list分别做lpush和lpop操作,就会遇到这个问题
    • 问题就是多线程编程面临的共享资源的并发访问控制问题

    2.2 其他原因

    • 多线程开发一般会引入同步原语来保护共享资源并发访问,会降低系统的调试和维护性

    3. 为什么那么快

    • 大部分操作内存中完成
    • 高效的数据结构设计(如哈希表和跳表)
    • 采用多路复用机制

    4. 基本IO模型和阻塞点

    4.1 SimpleKV处理GET请求,IO示例如下图,依次执行如下操作:

    Redis基本IO模型
    • 潜在阻塞点如下:
      • accept()
        • 当 Redis 监听到一个客户端有连接请求,但一直未能成功建立起连接时,会阻塞在 accept() 函数这里,导致其他客户端无法和 Redis 建立连接
      • recv()
        • 当 Redis 通过 recv() 从一个客户端读取数据时,如果数据一直没有到达,Redis 也会一直阻塞在 recv()。

    4.2 socket的非阻塞模式

    socket 模型,不同操作调用后会返回不同的套接字类型。
    
    image.png
      1. socket() 方法会返回主动套接字,
      1. 调用 listen() 方法,将主动套接字转化为监听套接字,此时,可以监听来自客户端的连接请求。
      1. 调用 accept() 方法接收到达的客户端连接,并返回已连接套接字。
    1. 针对监听套接字,可以设置非阻塞模式:当Redis调用accept()但一直未有连接请求到达时,Redis线程可以返回处理其他操作,不用一直等待。但调用accept()时,已经存在监听套接字了
    2. 同理,也可以对已连接套接字设置非阻塞模式,如数据没有到达,可以返回处理其他操作
    3. 问题:需要有机制,在监听套接字等待后续连接(有请求时通知Redis),继续监听已连接套接字,在有数据到达时通知Redis
    

    Redis机制:基于多路复用的高性能I/O模型

    引言:

    • linux中IO多路复用:指一个线程处理多个IO流,也就是select/epoll机制
    • Redis中:在一个内核中,同时存在多个监听套接字和已连接套接字。内核会一直监听这些套接字上的连接请求或数据请求。有请求到达,就交给redis线程处理

    基于多路复用的Redis高性能IO模型

    Redis高性能IO模型
      1. 图中的多个FD指多个套接字。Redis网络框架调用epoll机制,让内核监听这些套接字。这样,Redis线程不会阻塞在某个特定的监听或已连接套接字(不会阻塞在某一个特定的客户端请求处理)。所以,Redis可以同时和多个客户端连接并处理请求,提升并发性
      1. 为了在请求到达时通知到Redis,select/epoll提供了基于事件的回调机制(针对不同事件发生,调用相应处理函数)

    回调机制

    • select/epoll一旦监测到FD上有请求,出发相应事件将事件放进一个队列,Redis单线程对该事件队列不断进行处理
    • 以连接请求和读数据请求为例:
      • 两个请求分别对应Accept事件和Read事件,Redis分别对这两个事件注册accept和get回调函数。当linux内核监听到有连接请求或读数据请求时,就会触发Accept事件和Read事件,此时,内核就会回调Redis相应的accept和get函数进行处理

    总结:

    • Redis单线程是指它对网络IO和数据读写的操作采用了一个单线程,核心原因是避免多线程开发的并发控制问题
    • Redis单线程获得高性能的原因在:
      • 多路复用的IO模型:避免了accept()和send()/recv()潜在的网络IO操作点

    相关文章

      网友评论

          本文标题:3. 高性能IO模型,探究Redis单线程为何很快

          本文链接:https://www.haomeiwen.com/subject/bntkuktx.html