Apache Thrift系列详解(二)-网络服务模型

前言

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

阻塞服务模型: 、 。

非阻塞服务模型:、和。

类的层次关系:

正文

TServer

定义了静态内部类 , 继承自抽象类 。 采用了建造者模式,向 提供各种工厂:

下面是 的部分核心代码:

的三个方法: 、 和 。 用于启动服务, 用于关闭服务, 用于检测服务的起停状态。

不同实现类的启动方式不一样,因此 定义为抽象方法。不是所有的服务都需要优雅的退出, 因此 方法没有被定义为抽象。

TSimpleServer

工作模式采用最简单的阻塞IO,实现方法简洁明了,便于理解,但是一次只能接收和处理一个 连接,效率比较低。它主要用于演示 的工作过程,在实际开发过程中很少用到它。

(一) 工作流程

(二) 使用入门

服务端:

客户端:

(三) 源码分析

查看上述流程的源代码,即 中的 方法如下:

方法的操作:

设置 的 方法启动连接监听

阻塞的方式接受客户端地连接请求,每进入一个连接即为其创建一个通道 对象。

为客户端创建处理器对象输入传输通道对象输出传输通道对象输入协议对象输出协议对象

通过 对象处理具体的业务请求。

ThreadPoolServer

模式采用阻塞方式工作,主线程负责阻塞式监听是否有新 到来,具体的业务处理交由一个线程池来处理。

(一) 工作流程

(二) 使用入门

服务端:

客户端:

(三) 源码分析

解决了 不支持并发多连接的问题,引入了线程池。实现的模型是 。查看上述流程的源代码,先查看线程池的代码片段:

中的 方法如下:

方法的操作:

设置 的 方法启动连接监听

阻塞的方式接受客户端连接请求,每进入一个连接,将通道对象封装成一个 对象( 实现了 接口),并提交到线程池

的 方法负责业务处理,为客户端创建了处理器对象输入传输通道对象输出传输通道对象输入协议对象输出协议对象

通过 对象处理具体的业务请求。

的 方法:

(四) 优缺点

TThreadPoolServer模式的优点

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

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

TThreadPoolServer模式的缺点

线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待

TNonblockingServer

模式也是单线程工作,但是采用 的模式,借助 机制, 采用事件模型来处理。

所有的 都被注册到 中,在一个线程中通过循环监控所有的 。

每次 循环结束时,处理所有的处于就绪状态的 ,对于有数据到来的 进行数据读取操作,对于有数据发送的socket则进行数据发送操作,对于监听 则产生一个新业务 并将其注册到 上。

注意:TNonblockingServer要求底层的传输通道必须使用TFramedTransport。

(一) 工作流程

(二) 使用入门

服务端:

客户端:

(三) 源码分析

继承于 ,这里我们更关心基于 的 部分的关键代码。

(四) 优缺点

TNonblockingServer模式优点

相比于 效率提升主要体现在多路复用上, 采用非阻塞,对 等 事件进行监控处理,同时监控多个 的状态变化。

TNonblockingServer模式缺点

模式在业务处理上还是采用单线程顺序来完成。在业务处理比较复杂耗时的时候,例如某些接口函数需要读取数据库执行时间较长,会导致整个服务阻塞住,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。

THsHaServer

鉴于 的缺点, 继承于 ,引入了线程池提高了任务处理的并发能力。 是半同步半异步( )的处理模式, 用于事件处理( ), 用于业务 对 的同步处理上。

注意:THsHaServer和TNonblockingServer一样,要求底层的传输通道必须使用TFramedTransport。

(一) 工作流程

(二) 使用入门

服务端:

客户端:

(三) 源码分析

继承于 ,新增了线程池并发处理工作任务的功能,查看线程池的相关代码:

任务线程池的创建过程:

下文的TThreadedSelectorServer囊括了THsHaServer的大部分特性,源码分析可参考TThreadedSelectorServer。

(四) 优缺点

THsHaServer的优点

与 模式相比, 在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升。

THsHaServer的缺点

主线程仍然需要完成所有 的监听接收数据读取数据写入操作。当并发请求数较大时,且发送数据量较多时,监听 上新连接请求不能被及时接受。

TThreadedSelectorServer

是对 的一种扩充,它将 中的读写事件( )从主线程中分离出来。同时引入工作线程池,它也是种 的服务模型。

模式是目前 提供的最高级的线程服务模型,它内部有如果几个部分构成:

一个线程对象,专门用于处理监听 上的新连接。

若干个对象专门用于处理业务 的网络读写操作,所有网络数据的读写均是有这些线程来完成。

一个负载均衡器对象,主要用于线程接收到一个新 连接请求时,决定将这个新连接请求分配给哪个线程

一个 类型的工作线程池,在 线程中,监听到有业务 中有调用请求过来,则将请求数据读取之后,交给线程池中的线程完成此次调用的具体执行。主要用于处理每个 请求的回调处理(这部分是同步的)。

(一) 工作流程

(二) 使用入门

服务端:

客户端:

(三) 核心代码

以上工作流程的三个组件 、 和 在源码中的定义如下:

模式中有一个专门的线程 用于处理新连接请求,因此能够及时响应大量并发连接请求;另外它将网络I/O操作分散到多个线程中来完成,因此能够快速对网络进行读写操作,能够很好地应对网络较多的情况。

默认参数定义如下:

负责网络IO读写的selector默认线程数(selectorThreads):2

负责业务处理的默认工作线程数(workerThreads):5

工作线程池单个线程的任务队列大小(acceptQueueSizePerThread):4

创建、初始化并启动 和 ,同时启动 线程的负载均衡器( )。

AcceptThread源码

继承于 ,可以看出包含三个重要的属性:非阻塞式传输通道( )、选择器( )和选择器线程负载均衡器( )。

查看 的 方法,可以看出 线程一旦启动,就会不停地调用 方法:

查看 方法,选择器等待 事件的到来,拿到 即检查是不是 事件。如果是,通过 方法接收一个新来的连接;否则,如果是读写事件, 不作任何处理,交由 完成。

在 方法中,先通过 去拿连接通道,然后线程负载均衡器选择一个 线程,完成接下来的读写事件

接下来继续查看 方法的实现,毫无悬念,它进一步调用了 的 方法,把非阻塞传输通道对象传递给选择器线程做进一步的读写操作

SelectorThreadLoadBalancer源码

如何创建?

是一个基于轮询算法线程选择器,通过线程迭代器为新进来的连接顺序分配 。

SelectorThread源码

和 一样,是 的一个成员内部类,每个线程对象内部都有一个阻塞式的队列,用于存放该线程被接收连接通道

阻塞队列的大小可由构造函数指定:

上面看到,在 的 方法中调用了 的 方法。

这个方法做了两件事:

将被此 线程接收的连接通道放入阻塞队列中。

通过 方法唤醒 中的选择器

既然 也是继承于 ,查看其 方法的实现:

方法的 监听 事件,仅仅用于处理数据读取数据写入。如果连接有数据可读,读取并以 的方式缓存;如果需要向连接中写入数据,缓存并发送客户端的数据。且在数据读写处理完成后,需要向 的清空注销自身的 。

数据写操作完成以后,整个 调用过程也就结束了, 方法如下:

数据读操作完成以后, 会利用已读数据执行目标方法, 方法如下:

方法在执行 方法,将数据读取完成后,会调用 方法调用目标方法完成具体业务处理。 方法将请求数据封装为一个 对象,提交到工作任务线程池( )进行处理。

方法完成后,线程继续运行 方法处理下一个连接的 事件。

这里比较核心的几个操作:

尝试从 的阻塞队列中获取一个连接的传输通道。如果获取成功,调用 方法;否则,进入下一次循环。

方法将传输通道底层的连接注册到 的选择器上面,获取到一个 。

创建一个 对象,并绑定到获取的 上面,用于数据传输时的中间读写缓存

总结

本文对 的各种线程服务模型进行了介绍,包括2种阻塞式服务模型: 、 ,3种非阻塞式服务模型: 、 和 。对各种服务模型的具体用法工作流程原理和源码实现进行了一定程度的分析。

鉴于篇幅较长,请各位看官请慢慢批阅!

欢迎关注技术公众号: 零壹技术栈

本帐号将持续分享后端技术干货,包括虚拟机基础,多线程编程,高性能框架,异步、缓存和消息中间件,分布式和微服务,架构学习和进阶等学习资料和文章。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180529G086NL00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励