网络通信应用中,要开发一个稳定的、高效的、伸缩性好、可扩展性强、单机承载数千甚至上万用户同时在线的网络应用系统是一项比较复杂的工程,其涉及到很多方面的专业知识,像TCP协议、UDP协议、Socket开发、多线程编程、线程池、并发架构、分布式架构、完成端口(IOCP)模型、异步编程模型、设计模式等等。最近研究了一下网上各种对网络编程方面的介绍,于是有了以下一些思路。

    多数网络应用都如以下框架

wKiom1QgyYSywjr7AAIUXtrBKNU739.jpg

    

    网络应用平台分为4层:设备层(客户端、终端设备)、平台层(一级应用服务器、二级应用服务器)、业务层(功能服务器、功能插件)、数据层(网络数据库)。

    FS(Function Server)功能服务器,处理并且仅处理所有的功能性请求,不参与用户管理、状态保持等,提供最纯粹的功能服务。上图中的功能服务器FS的个数可能是0到N(N>0)个。在某种意义上可以认为,每个功能服务器FS是可以互换的。由于FS仅提供最纯粹的功能服务,不需要进行用户管理、状态保持,这种功能服务器在运行时的无状态性,使得功能服务器很容易实现负载均衡集群。

    AS(Appliction Server)应用服务器,主要功能包括:管理各种外部设备(CU、PU)、维持外部设备状态、设备权限认证、系统消息路由、提供“ 框架+插件”结构管理业务功能插件(Addins)、管理功能服务器(FS)等。

    AS可以支持 “区域分布式”的体系结构。上面的4层架构已经是一种分布式架构了,但是这种分布式架构是一种“纵向”的架构,“区域分布式”则侧重于“横向”,在“区域分布式”体系结构中,每一个具体的“4层架构的实现”只是其中的一个组成元素。


AS应用服务器

    AS应用服务器主要实现服务器功能,包括管理各种外部设备(CU、PU、FS)、维持外部设备状态、设备权限认证、系统消息路由、提供“框架+插件”结构管理业务功能插件(Addins)。AS应用服务器提供了底层网络通信框架,用户只需要把注意力放到具体业务处理上,不用关系底层网络通信如何实现。对于具体的业务,用户可以通过两种方式处理,一种是直接开发对应的业务处理插件,通过插件框架加载到AS应用服务器插件管理器中。另一种是开发相应的FS功能服务器接入到AS应用服务器上,由AS应用服务器转发业务数据给FS功能服务器,再由FS功能服务器处理。前者比较适合功能简单、处理器负荷较轻的业务,后者比较适合功能复杂、IO吞吐量大、处理器负荷较重的业务(如图片、视频处理等)。


AS应用服务器模块框图:

wKiom1Qgy1jxX7d3AAKhHK4E36o467.jpg


AS应用服务器主要模块包括:

1.  异步网络模块。

2.  网络流解析模块。

3.  消息管道模块。

4.  消息订阅发布模块。

5.  设备模块。

6.  业务池插件模块。

7.  应用服务器模块。


半同步-半异步并行模式

wKioL1Qgy76gQxDoAAFB-llD7Qk739.jpg



网络应用平台使用半同步-半异步模式解决并发性。组成单元如下描述:

l        同步任务层(用户级)

    本层的任务是完成对消息数据的处理操作,使用同步模型,通过队列层的队列中传输数据。和异步层不同,同步层的任务使用活动对象执行,这些活动对象有自己运行线程。当执行同步任务的时候,他们可能会被阻塞。


l        队列层

    这个层在同步任务层和异步任务层之间,提供了同步控制和缓存的功能。异步任务的I/O事件被缓存到消息队列中,同步任务层在队列中提取这些事件。


l        异步IO

    处理低层的事件,这些事件由多个外部的事件源产生(例如网卡,终端)。和同步任务不同,此层的实体是被动对象,没有自己的运行线程,要求不能被阻塞。

 

当外部事件到达后,半同步-半异步模式的各个组成单元协作和处理。把协作的过程分成下面三个阶段:

    1.异步阶段:通过异步事件通知,外部的事件源和异步任务层完成交互。

    2.排队阶段:队列层的队列提供了一个同步控制机制,响应输入事件,缓存同步层和异步层之间的消息。

    3.同步阶段:同步任务层从队列层提取消息。注意,同步层和异步层传递数据的协议是独立的,和队列层具体处理通信的方式无关。

    

    同步层和异步层之间的通信使用生产者/消费者模型。理解这个模型的关键是:完成同步任务的是活动对象。他们可以在任意时刻阻塞调用read或在write。如果数据没有准备好,这些活动对象可以一直等待。相反的,异步任务层的实体是被动对象。他们不能被阻塞。这些对象被通知或外部对象触发。


异步网络模块

    异步网络模块主要是为上层提供基本的网络操作功能,包括建立服务器监听、接受外来连接、主动连接远程主机等。所有的网络操作都是异步进行,提高并发性。


设备模块

    设备模块主要功能是接入管理网络中的设备,维护设备操作权限等。


消息解析模块

    网络层收到消息流后,需要对消息流进行解析,并把解析出来的一条条消息打包成系统中约定的消息结构体。


消息管道模块

网络中收到数据后经过解析器解析,得到的消息体直接进入系统消息管道框架进行处理,消息管道处理框架如下:

wKioL1Qgz7ay6XOqAAG29agdmjc812.jpg

   

    消息管道框架涉及多个模块,包括异步网络模块、消息管道模块、消息订阅-发布模块等,消息管道框架是系统消息处理流程的“桥梁”,系统通过消息管道框架对网络层和应用层解耦。

    消息管道MessagePipe可以看做是GatewayMessageSpy以及MessageTransformer和 InnerMessageSpy的“封装“。消息进入消息管道的处理顺序是GatewayMessageSpy,MessageTransformer,InnerMessageSpy。消息流出消息管道的处理顺序是InnerMessageSpy,MessageTransformer,GatewayMessageSpy。


消息订阅发布

    当平台收到消息并打算传递给业务逻辑层处理时,有多种方式可以实现,我们使用消息订阅发布模式实现平台到业务逻辑的消息“传递”。每个业务逻辑充当订阅者角色,向发布者订阅自己关心的消息。当有消息到发布者时,发布者会调用订阅者对应的函数处理。消息订阅发布模式降低了平台和业务逻辑的耦合,使用统一的消息订阅接口,减少了依赖。

wKiom1QgzWeSBwN0AAF-wbjb7dI496.jpg

整个网络平台在并行模式上使用的是半同步-半异步模式,异步层就是异步网络模块,网络模块收到数据后不停的把数据放入到消息订阅发布模块中,而队列层和同步层由消息订阅发布模块实现。消息订阅发布模块中消息处理器堆起着缓存异步层传来的消息数据,同时处理器堆中的消息处理组件作为活动对象不停的从消息队列中取出消息并调用对应的消息订阅者函数。

消息处理模块包括消息订阅-发布模块和消息执行模块,其中消息订阅-发布模块主要实现系统消息订阅-发布框架,消息执行模块主要实现缓存网络层传来的消息数据、从消息队列中取消息并作为活动对象同步处理消息。


应用服务器模块

    功能服务器模块是网络应用平台的核心模块之一,其主要功能是融合其他功能模块,搭建一个统一的网络管理平台。

wKioL1QgzgfDg4QTAAHTJe-_IaA478.jpg

    对于最多几千个设备同时在线的通信应用,通常使用单台服务器就可以支撑。但是,当同时在线的设备数达到几万、几十万、甚至百万的时候,我们就需要很多的服务器来分担负载。但是,依据什么规则和结构来组织这些服务器,并使它们能相互协调合作,是最关键的问题。网络应用平台旨在协助快速构建大型的基于网络的通信应用。网络应用平台也是通过应用服务器群集来解决巨大并发。

    网络平台采用基于域的分布式架构,分为一级平台和二级平台,每个域中包含一个二级应用服务器和若干功能服务器、终端设备、客户端设备、数据库。二级应用服务器管理本域中所有接入设备。域和域之间是相对独立的,域间节点不能直接访问。每个域中的二级应用服务器由一级应用服务器统一管理,域间访问都是通过一级应用服务器来交换数据。


全网统一设备编码

    为了识别接入网络平台中的所有设备,整个网络平台中的设备都需要赋予一个唯一的编码作为身份标识。

编码如下:

XXXX | XXXX 32位,前16位表示区域编码,后16位表示本区域中的节点编码。

    应用服务器编码格式为XXXX0000,其他设备编码为XXXXXXXX。其中应用服务器和本域内的所有设备的区域编码是一样的,因此可以通过区域编码来判断设备和应用服务器是不是在同一个域中。

 

全网消息路由

    网络中的消息,都有发送端和目的端,那么怎么让消息在整个网络平台中流通呢?当某个终端需要向另外个终端发送消息或是当终端处理了别的终端发来的消息需要回复时怎么处理呢?这都需要考虑网络中消息怎么路由到目的地。

 

消息体路由标识

    每个网络中的消息体均有如下结构:

<?xml version=”1.0” encoding=”UTF-8”?>    
<Message version=”1.0”>
    <Header Message_Type=”协议类型” SessionId=”会话ID” Seq=”包序号”  From=”协议发送端” To="协议目的端”/>
    <!-- 具体协议内容 -->
    <parameters></parameters>
</Message>

其中FromTo字段就表明了消息源和消息目的地。不管是主动向终端发送消息还是终端回复消息,都必须正确填写FromTo字段。


消息路由器(ASMsgGatewaySpy)

    本域内二级应用服务器收到网络消息后,首先需要判断当前的消息是不是发送给本域的设备,如果消息目的地是本域设备,则把消息通过二级应用服务器投递给对应的设备,如果消息目的地不是本域内的设备,则需要把消息通过本域的二级应用服务器投递给一级应用服务器,让一级应用服务器去把消息投递给对应域的二级应用服务器,再由二级应用服务器转发消息给对应的目的设备。

    消息管道处理机制解决了网络消息刚到应用服务器时就进行相应的路由处理。我们可以实现一个IGatewayMessageSpy接口,在spyMessageReceived函数中实现消息路由。