• 结合Thrift示例详解网络服务模型(多线程阻塞IO、多线程非阻塞IO、多Reactor模型)


    组件介绍

    Thrift是一个轻量级、跨语言的RPC框架,主要用于各个服务之间的RPC通信,它通过自身的IDL中间语言, 并借助代码生成引擎生成各种主流语言的RPC服务端/客户端模板代码。Thrift支持多种不同的编程语言,包括C++, Java, Python, PHP等。

    RPC 全称 Remote Procedure Call——远程过程调用。RPC技术简单说就是为了解决远程调用服务的一种技术,使得调用者像调用本地服务一样方便透明。

    IDL:Thrift是一个典型的CS(客户端/服务端)结构,客户端和服务端可以使用不同的语言开发。既然客户端和服务端能使用不同的语言开发,那么一定就要有一种中间语言来关联客户端和服务端的语言。

    网络服务模型

    Thrift提供的网络服务模型:单线程、多线程、事件驱动,从另一个角度划分为:阻塞服务模型、非阻塞服务模型。

    单线程阻塞IO

    Thrift的TSimpleServer就是单线程阻塞IO。

    TSimpleServer的工作模式采用最简单的阻塞IO,实现方法简洁明了,便于理解,但是一次只能接收和处理一个socket连接,效率比较低。

    在这里插入图片描述
    启动一个服务监听socket,由于是单线程处理而且是阻塞IO,所以要等完成业务处理后,才能重新accept等待一个新的连接。

    多线程阻塞IO

    Thrift的TThreadPoolServer模式采用阻塞socket方式工作,主线程负责阻塞式监听是否有新socket到来,具体的业务处理交由一个线程池来处理。
    在这里插入图片描述
    ThreadPoolServer解决了TSimpleServer不支持并发和多连接的问题,引入了线程池。在accept一个业务socket之后,立马把业务socket封装成一个任务交给线程池处理。

    TThreadPoolServer模式的优点:
    拆分了监听线程(Accept Thread)和处理客户端连接的工作线程(Worker Thread),数据读取和业务处理都交给线程池处理。因此在并发量较大时新连接也能够被及时接受。

    线程池模式比较适合服务器端能预知最多有多少个客户端并发的情况,这时每个请求都能被业务线程池及时处理,性能也非常高。

    TThreadPoolServer模式的缺点:
    线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。
    默认线程池允许创建的最大线程数量为Integer.MAX_VALUE,可能会创建出大量线程,导致OOM(内存溢出)

    单线程非阻塞IO

    Thrift的TNonblockingServer模式也是单线程工作,但是采用NIO的模式,利用io多路复用模型(select、epoll)处理socket就绪事件,对于有数据到来的socket进行数据读取操作,对于有数据发送的socket则进行数据发送操作,对于监听socket则处理连接并产生一个新业务socket并将其注册到selector上。selector当没有就绪事件为阻塞的,有就绪事件为非阻塞,会往下执行。

    在这里插入图片描述
    TNonblockingServer模式优点:
    相比于TSimpleServer效率提升主要体现在IO多路复用上,TNonblockingServer采用非阻塞IO,对accept/read/write等IO事件进行监控和处理,同时监控多个socket的状态变化。
    TNonblockingServer模式缺点:
    TNonblockingServer模式在业务处理上还是采用单线程顺序来完成。在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,会导致整个服务被阻塞住,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。

    多线程非阻塞IO

    鉴于TNonblockingServer的缺点,Thrift的THsHaServer继承于TNonblockingServer,引入了线程池提高了任务处理的并发能力。针对读操作,单独引入线程池处理。也是Reactor的实现。
    在这里插入图片描述
    THsHaServer的优点:
    THsHaServer与TNonblockingServer模式相比,THsHaServer在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升。
    THsHaServer的缺点:
    主线程仍然需要完成所有socket的监听接收、数据读取和数据写入操作。当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。

    多Reactor模型

    Thrift的TThreadedSelectorServer是对THsHaServer的一种扩充,它将selector中的读写IO事件(read/write)从主线程中分离出来。同时引入worker工作线程池。
    TThreadedSelectorServer模式是目前Thrift提供的最高级的线程服务模型,它内部有如果几个部分构成:

    1. 一个AcceptThread(相当于多Reactor的mainReactor)专门用于处理监听socket上的新连接。
    2. 若干个SelectorThread(相当于多Reactor的subReactor)专门用于处理业务socket的网络I/O读写操作,所有网络数据的读写均是有这些线程来完成。
    3. 一个负载均衡器SelectorThreadLoadBalancer对象,主要用于AcceptThread线程接收到一个新socket连接请求时,决定将这个新连接请求分配给哪个SelectorThread线程。
    4. 一个ExecutorService类型的工作线程池,在SelectorThread线程中,监听到有业务socket中有调用请求过来,则将请求数据读取之后,交给ExecutorService线程池中的线程完成此次调用的具体执行。主要用于处理每个rpc请求的handler回调处理。即具体业务处理线程。
      在这里插入图片描述
  • 相关阅读:
    python飞书群机器人通过webhook发送消息
    scrapy的安装和使用
    poi+ResultSet+线程池导出数据库表结构
    复制对象耗时比较(PO2Response)
    4.typescript循环
    Linux C基础(9)
    YBTOJ 贪心算法合集
    自动化任务调度,轻松管理海量数据采集项目
    基于STM32的实时操作系统FreeRTOS移植教程(手动移植)
    网络安全(黑客)自学笔记
  • 原文地址:https://blog.csdn.net/qq_33873431/article/details/125428903