ESFramework 开发手册(11) -- 服务端信息处理模型

       基于ESFramework进行二次开发时,主要是通过自定义信息来实现业务逻辑功能,而自定义消息的处理则是通过ICustomizeHandler接口的HandleInformation(或HandleQuery)方法来进行的。但是,ICustomizeHandler接口的这两个方法是如何被框架调用的了?在介绍之前,我们先要了解一下.NET的线程池(ThreadPool)。

一. 线程池

       .NET线程池中有两种类型的线程:工作者线程、完成端口IOCP线程。通过ThreadPool的静态方法SetMinThreads、SetMaxThreads可以对线程池做一些简单的设置。

       一般在程序启动时,我们可以调用 System.Threading.ThreadPool.SetMaxThreads(100, 100);  将最大的工作者线程和IOCP线程数量设置为100。

       然后,在服务端运行的过程中,可定时调用(比如每秒一次)ThreadPool的GetAvailableThreads方法,来查看线程中可用的(即,空闲的)工作者线程和IOCP线程的数量。这样就可以实时监控线程池中线程的状态。 

       ESFramework对ICustomizeHandler接口的调用都是在线程池的IOCP线程或工作者线程中进行的,至于究竟使用的是哪种类型的线程,取决于信息处理模型的设定。  

       另外说一下,ESFramework框架本身使用了数个工作者线程,以维持网络引擎的正常运转,但是,ESFramework框架自身的运转并不消耗任何IOCP线程。   

二. CustomizeInfoHandleMode

      ESFramework服务端为信息处理提供了两种方案,这两种方案通过CustomizeInfoHandleMode枚举进行定义,并对应该枚举有两个取值:IocpDirectly、TaskQueue。

      我们知道,ESFramework内核是基于IOCP(Windows系统中最高效的模型)的,即服务端接收到的信息都是在IOCP线程中提交的, 对于提交的信息:

(1)如果信息处理模型被指定为IocpDirectly,则框架将直接在该IOCP线程中调用ICustomizeHandler接口来处理该信息。

(2)如果信息处理模型被指定为TaskQueue,则框架首先会将信息放入到一个任务队列中。然后由工作者线程从队列中依次取出信息,并调用ICustomizeHandler接口进行处理。

       这里可以看出,这两种方案有几个明显的区别:

(1)IocpDirectly方案,ICustomizeHandler的调用是在IOCP线程中进行的;而TaskQueue方案,ICustomizeHandler的调用是在工作者线程中进行的。

(2)对于TaskQueue方案,IOCP线程的工作仅仅是将接收的信息放入到任务队列中。

       我们可以通过IRapidServerEngine的Advanced控制器的CustomizeInfoHandleMode属性来指定要使用的方案(默认是IocpDirectly), 像这样:

    rapidServerEngine.Advanced.CustomizeInfoHandleMode = CustomizeInfoHandleMode.TaskQueue;

       对于二次开发人员而言,从一种方案切换到另一种方案,体现在代码上只是上面属性设置的修改,不需要在做任何其它的事情,框架内部会自动完成相应的工作。下面我们将深入这两种方案。 

三. IocpDirectly方案

        无论是使用IocpDirectly方案还是TaskQueue方案,一个客户端连接最多用到一个IOCP线程(提交接收到的消息的时候才用到)。但是对于IocpDirectly方案,由于提交消息是直接进入ICustomizeHandler的HandleInformation(或HandleQuery)方法调用,所以,IocpDirectly方案有以下特点:

(1)针对一个具体的TCP连接而言,信息处理是串行的。只有当前一个信息处理完成(即HandleInformation / HandleQuery方法返回)后,才处理该连接上的下一个请求信息。

(2)针对所有的TCP连接而言,信息处理是并行的。即同时有多个HandleInformation / HandleQuery方法 正在执行。   

(3)通过观察IOCP线程的使用个数,就可以知道有多少个信息正在被处理。

(4)如果某个信息处理的耗时超过了心跳超时的设定,则对应的客户端会被当作心跳超时掉线,其TCP连接将被服务端主动断开。 

四. TaskQueue方案

       在TaskQueue方案中,IOCP线程不再重要,我们要关注的是任务队列和工作者线程。前面我们说道,工作者线程从队列中依次取出消息然后调用ICustomizeHandler接口进行处理。用于从事这一工作的工作者线程的数量是可以设定的,通过IRapidServerEngine的Advanced控制器的QueueWorkerThreadCount属性(默认是20), 像这样:

         rapidServerEngine.Advanced.QueueWorkerThreadCount = 50;

       当然,这个设定的数量必须不能超过ThreadPool的SetMaxThreads方法设定的最大工作者线程数。

       另外,通过IRapidServerEngine的Advanced控制器提供的GetTaskQueueInfo方法,我们可以获取任务队列的当前状态:

         /// <summary>
        /// 当CustomizeInfoHandleMode设置为TaskQueue时,获取队列中待处理的任务个数,以及历史中最大的待处理任务个数。
        /// </summary>
        /// <param name="taskCount">待处理的任务个数</param>
        /// <param name="maxTaskCount">历史中最大的待处理任务个数</param>
        void GetTaskQueueInfo(out int taskCount, out int maxTaskCount); 

       那么,相比于IocpDirectly方案,TaskQueue方案有以下特点:

(1)针对一个具体的TCP连接而言,信息的处理也不是串行的,而且,后接收到的信息有可能先处理完。

(2)通过与空闲时(比如,程序启动时)线程池中可用的工作者线程数的对比,就可以知道有多少个信息正在被处理。

(3)如果某些信息处理缓慢,那么,通过GetTaskQueueInfo方法可看到队列中待处理的任务越来越多,同时可以观察到当前进程的内存消耗越来越大。从客户端表现来看,就是响应越来越慢。   

五. 生产 - 消费模型

       我们可以使用生产-消费模型来进行分析,从网络接收到消息,相当于生产消息,HandleInformation / HandleQuery方法的执行相当于是消费消息。决定服务端吞吐量的因素有很多,但最首要也是最核心的因素就是服务端消费消息的能力。每秒消费掉的消息数量越大,吞吐量也就越大。

       当生产消息的速度小于或等于消息消费的速度时,服务端的业务处理是从容不迫的。

       但是,当生产消息的速度大于或远远大于消息消费的速度时,并且这一状况一直持续下去时,可以想想会发生什么状况?我们简单推导一下。

1. TaskQueue方案

(1)为任务队列服务的工作者线程都将处于忙碌状态。

(2)队列中待处理的任务越来越多。

(3)内存消耗越来越大,可能导致进程引发OutOfMemory(内存溢出)异常。

(4)从客户端来看,新的请求无法被服务端响应。

2. IocpDirectly方案 

(1)线程池中可用的IOCP线程会越来越少。

(2)每个TCP连接的Socket缓冲区中排队等待接收的消息会越来越多,当这个缓冲区满时,客户端再向服务端发送消息的方法调用将被阻塞。

(3)如果某些消息处理的异常缓慢,则可能导致某些客户端心跳超时掉线。

      当生产消息的速度大于或远远大于消息消费的速度时,提升服务端信息处理能力(这涉及到的诸多方面的优化)是唯一的解决方案。但是,在未提升服务器的处理能力之前,对于这种情况,IocpDirectly方案和TaskQueue方案哪种更好一点了?

      虽然,无论哪种方案,客户端的体验都将比较差,但是相比而言,我们推荐是IocpDirectly方案,原因在于:基于上面描述IocpDirectly方案的第(2)点,客户端发送消息的方法调用将被阻塞,这意味着会倒逼客户端降低生产消息的速度。采用IocpDirectly方案是ESFramework框架的默认设置。        

 

 

下一篇:ESFramework 开发手册(12) -- 服务端性能诊断

上一篇:ESFramework 开发手册(10) -- 安全机制

-----------------------------------------------------------------------------------------------------------------------------------------------   

下载免费版本的ESFramework 以及 demo源码  

阅读 更多ESFramework开发手册系列文章

Q Q:168757008

官网:www.oraycn.com

导航

首页

官方网站

立即咨询 

站内搜索

ESFramework 通信框架

详细说明

SDK下载

ESFramework FAQ

版本变更记录

OMCS 语音视频框架

详细说明

SDK下载

OMCS FAQ

版本变更记录

OrayTalk 企业即时通讯系统

详细说明

客户端下载

傲瑞实用组件

SDK下载

NPush 消息推送组件

StriveEngine 轻量级的通信引擎

MFile 语音视频录制组件

MCapture 语音视频采集组件

MPlayer 语音视频播放组件

OAUS 自动升级系统

傲瑞组件 FAQ

授权

授权流程

产品授权说明

产品选购指南

授权SDK使用说明

其它

SDK使用技巧

联系我们

电话:027-87638960

Q Q:168757008

邮件:master@oraycn.com