ESFramework 4.0 进阶(09)-- ESPlatform 支持的三种群集模型一文中,我们介绍了ESPlatform支持的三种群集模型 -- 垂直分割模型、水平分割模型、交叉模型。我们看到,在垂直分割模型和交叉模型中,每个客户端都要与多个应用服务器AS进行通信,这就要求客户端与多个AS中的每一个都建立一条通信通道,如此才能保证客户端能获得服务端提供的完整的服务。

在ESPlatform中有一系列基础设施和组件来支持这样的结构,而多通道引擎就是其中的一个关键组件。首先要注意,多通道引擎的说法对客户端才有意义,因为服务端引擎都是多通道的 -- 服务端与每个客户端之间都有一个通道。所以,当我们提到多通道引擎时,一定指的是多通道客户端引擎。在ESFramework 4.0 进阶(03)-- 驱动力:通信引擎 中,我们介绍的基础的客户端引擎都是单通道的,即一个客户端引擎实例只与一个AS通信。单通道客户端引擎是ESFramework提供的基元组件,我们可以将多个单通道引擎实例组装起来,构成一个多通道引擎。实际上,ESPlatform已经为我们做好了这件事,那就是ESPlatform.Paasive.MultiChannelEngine。

一.多通道引擎的结构

  MultiChannelEngine 内部集成了多个单通道引擎(ESFramework.Passive.IPassiveEngine),每个引擎实例与一个对应的AS通信。示意图如下所示:

(1)首先,MultiChannelEngine 也实现了ESFramework.Passive.IPassiveEngine接口(Composite模式),在任何使用IPassiveEngine的地方,都可以使用MultiChannelEngine来替换对应的单通道引擎。

(2)MultiChannelEngine 内部集成的是IPassiveEngine实例,所以,其既可以支持客户端的TCP引擎集成,也支持客户端UDP引擎的集成,甚至可以交叉搭配。比如,AS01通过TCP提供服务,而AS02通过UDP提供服务,那么engine1实例就使用TCP客户端引擎,engine2就使用UDP客户端引擎。

(3)所有的引擎实例都公用同一个消息处理骨架流程实例,即公用同一个IMessageDispatcher对象来分派处理消息。这种设计可以使配置非常简单。

二.再论MessageType

接下来,我们需要考虑一个问题,那就是当我们要通过MultiChannelEngine发一个消息给服务端时,该选择哪个引擎实例、即哪个通道进行发送了 ?

在ESFramework中,使用MessageType来标志消息的类型,每一个消息的消息头MessageHeader都有一个MessageType属性,以说明当前消息的类别。在ESFramework 1.0之前的版本中,MessageType原名叫ServiceKey或ServiceType,即服务类型。其隐藏的含义是,每一个消息类型都对应着服务端提供的一种服务。所以,在ESFramework 4.0 进阶(09)-- ESPlatform 支持的三种群集模型 一文中,我们在提到“服务”时,经常都加备注说明就是“MessageType”。可以这么认为,ESFramework中的MessageType就是服务的类型。

在垂直分割模型中,对服务加以拆分,实际就是对MessageType进行拆分,使不同的AS处理不同的消息类型。比如,AS01处理A类型的业务,其对应MessageType为101~200的消息;而AS02处理的B类型业务,其对应MessageType为201~300的消息。基于这样的认识,我们刚提出的问题就就解决了,那就是如果客户端要发送的消息类型在101~200之间,则使用engine1进行发送;若要发送的消息类型在201~300之间,则使用engine2进行发送。

至于每个引擎实例能处理哪些消息类型,ESFramework使用自描述的PassiveEngineUnit类进行封装:

MessageTypesAllowed属性是一个集合,包含了当前引擎实例允许发送的所有消息类型。所以,MultiChannelEngine的内部集成了多个PassiveEngineUnit,它就据此知道即将发送的消息要交给哪个引擎实例去发送。

三.Default引擎

我们再来考虑一个问题,在垂直分割群集模型中,当多个AS中的某一个挂掉,或者客户端与某个AS的连接突然断开时,该如何处理?出现这种情况是非常严重的,因为,此时客户端就不能获得服务端提供的完整的服务了。ESPlatform是如何解决的了?

ESFramework提供的多通道引擎MultiChannelEngine是支持Default模式的,我们再将上面的结构图稍作变形:

相比于原来的结构图,该图增加了一个default AS应用服务器,多通道引擎内部也增加了一个default engine。ESPlatform的垂直群集模型中的default模式描述如下:

(1)default AS 必须能处理所有类型的消息,即default AS 能提供完整的服务端服务。

(2)当AS01,AS02,AS...指定了要处理的消息类型后,剩下的未被指定的消息类型则统统由default AS处理(因为default AS能处理所有类型的消息,所以这点肯定没问题)。MultiChannelEngine内部也一样,没有被其它引擎实例允许发送的消息类型统统交由default engine发送。

(3)当某个引擎实例与对应的AS的连接断开或该AS挂掉时,原本由该引擎实例发送的类型的消息全部交由default engine发送,这些消息将被default AS处理。当挂掉的AS恢复正常且对应的引擎实例重连成功后,指定类型的消息还是由原引擎实例发送。如此看来,default AS和default engine就充当了冗余后备的角色,以增强整个系统的健壮性。

(4)我们的建议是,更进一步,除default AS外,其它的AS将所有的消息类型全部分配完,这样,在正常情况下,default AS 和 default engine是没有任务的,只有在出现异常状况时,default AS 和default engine才作为后备上场。

(5)更进一步,ESPlatform也支持使用多个default AS和多个default engine,因为单个default AS也有可能出状况啊。至于实际上需要部署多少个default AS,取决于你项目的具体要求。

(6)要特别强调,default AS 能作为后备顺利上场接替原AS是有前提的 -- 最好的情况是,所有的AS都是无状态的(stateless),即AS不需要保存用户的任何状态,或者,同一个用户发过来的前后两条消息是没有逻辑关联的。

如果我们的应用一定要保存用户的某些状态数据,并且一定要依靠这些状态数据才能处理用户的后续消息,这种情况就不能随意让default AS接替原AS了。解决的办法也是有的,比如说:

a.把状态数据从AS中迁移出来,放到一个default AS 也能够访问的地方,这样普通AS就是无状态的,等必要时切换到default AS,业务也能正常继续执行。

b.在设计时,所有涉及到用户状态管理的消息类型都交给default AS处理,这样普通的AS就是没有状态的了。

c.在设计时,所有涉及到用户状态管理的消息类型交给固定的几个普通AS处理,但是客户端与这些消息类型相关的业务逻辑代码在引用IPassiveEngine时,就直接使用对应的普通引擎对象,而不是使用MultiChannelEngine对象。

这几个方案在ESPlatform中都是被支持的,但就我们的经验来说,保证普通AS无状态是最简单也是最容易实施的方案。只有到迫不得已的时候,才采用方案C。当然就具体的项目而言,可能还存在其它的解决方法,设计者可以在ESPlatform提供的基础设施上自由发挥。

四.MultiChannelEngine类

前面做了这么多铺垫,再来理解本文的主角MultiChannelEngine就非常容易了。

(1)MultiChannelEngine由多个Default引擎和多个普通引擎构成。
(2)客户端状态以default引擎为准。
(3)Initialize/Start/Stop/InitializeAndStart方法以及所有属性set等方法会逐个调用内部所有的引擎。
(4)当向服务器发送一条消息时,首先看是否有普通引擎允许该消息通过,如果有这样的普通引擎,则采用该普通引擎发送;否则通过default引擎列表中第一个可用的default引擎发送。
(5)如果要发送的是心跳消息,则会将其使用每个引擎发送一遍,以保证每个引擎实例都不会超时掉线。

在项目中具体使用时,我们只要装配好MultiChannelEngine对象,然后,在以前所有使用IPassiveEngine的地方,更改为引用这个MultiChannelEngine对象就可以了。如果是使用类似Spring.net的IOC容器,那么通过修改配置文件就可以很快地做到这一点。

  本文我们探讨的是客户端与服务器之间的多通道结构,实际上,当在客户端启用了P2P Channel时,客户端与客户端之间的也是多通道的模型,只不过这种多通道模型是依据消息的接收者而不是消息的类型,来决定当前消息应该使用哪一条通道进行发送的。关于P2P Channel及其管理,已经超出了本文探讨的范围,这里就不多说了。

另外,虽然ESPlatform水平分割群集模型在相对简单的应用中只需要单通道即可,但是某些情况下,也需要做一些扩展,比如“租借”更多的通道来减少服务端跨服务器的P2P消息转发 -- 而这也正是我们在实践ESPlatform水平分割群集模型时,觉得最有效的模式。后面我们将撰文详细介绍ESPlatform水平分割群集模型的这种扩展模式,以及ESPlatform对支持这种模式所提供的基础设施和组件。敬请关注,谢谢。

垂直分割群集模型与多通道引擎 -- ESFramework 4.0 进阶(10)的更多相关文章

  1. ESFramework 4.0 进阶(04)-- 驱动力:通信引擎(下)

    在ESFramework 4.0 进阶(03)-- 驱动力:通信引擎(上)一文中,我们对ESFramework提供的每一个通信引擎的接口都做了详细了说明,这篇文章我们将继续探讨这些接口的实现类 -- ...

  2. 驱动力—— 通信引擎(上)—— ESFramework 4.0 进阶(03)

    在ESFramework 4.0 进阶(02)-- 核心:消息处理的骨架流程一文中我们详细介绍了ESFramework中消息处理的骨架流程,并且我们已经知道,ESFramework中的所有通信引擎使用 ...

  3. 好友与组--ESFramework 4.0 进阶(11)

    大部分分布式通信系统中,都会涉及到客户端之间相互通信.以及需要将客户端进行分组的功能,或者是类似这方面的需求.ESFramework对这一常见的任务内置了强大的支持,包括从客户端到服务端.一直到Pla ...

  4. 消息同步调用-- ESFramework 4.0 进阶(07)

    分布式系统的构建一般有两种模式,一是基于消息(如Tcp,http等),一是基于方法调用(如RPC.WebService.Remoting).深入想一想,它们其实是一回事.如果你了解过.NET的Prox ...

  5. 在线用户管理--ESFramework 4.0 进阶(05)

    无论我们采用何种通信框架来构建我们的分布式系统,在服务端进行用户管理都是非常重要的一个环节.然而用户管理是否应该隶属于通信框架了?这个并不一定,通常来说,用户管理是与具体应用紧密相关的,应该是由应用解 ...

  6. 正规消息发送器-- ESFramework 4.0 进阶(06)

    在ESFramework 4.0 进阶(04)-- 驱动力:通信引擎(下)一文末尾我们已经将通信引擎以及整个消息骨架流程组装起来了,只要通信引擎一接收到消息,框架就会按照规定的流程进行运转.到这里,自 ...

  7. 核心梳理——消息处理的骨架流程——ESFramework 4.0 进阶(02)

    在ESFramework 4.0 概述一文中,我们提到ESFramework.dll作为通信框架的核心,定义了消息处理的骨架流程,本文我们来详细剖析这个流程以及该骨架中所涉及的各个组件.ESFrame ...

  8. 挂接P2P通道-- ESFramework 4.0 进阶(08)

    最新版本的ESFramework/ESPlus提供了基于TCP和UDP的P2P通道,而无论我们是使用基于TCP的P2P通道,还是使用基于UDP的P2P通道,ESPlus保证所有的P2P通信都是可靠的. ...

  9. ESFramework 4.0 进阶(01)-- 消息

    需要交互的分布式系统之间通过消息来传递有意义的信息.消息是通信框架的核心.离开了消息,再谈通信框架就没有任何意义,所以,消息是ESFramework中一个最核心的概念. 一. 消息的类别 在具体的应用 ...

随机推荐

  1. Winform_devexpress开发框架主界面设计

    做了好多年的C#开发,从.Net.Winform及第三方的DevExpress.无论什么样的系统,主界面的设计及风格无疑非常重要.从客户的角度考虑,要求功能区清晰,整体美观大方,这样才会有可能从第一视 ...

  2. cout 格式化的一些方法

    cout格式化的方式有很多,和C中的printf相比较,在实现方式上更加容易理解. 1.计数进制. 1.十六进制:hex 2.八进制:oct 3.十进制:dec(默认) 在控制进制的时候,可以使用两种 ...

  3. Ubuntu下Git的使用之创建版本库

    创建版本库 什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都可以 ...

  4. Ubuntu 16.04上Docker使用手记

    一.Docker Hub的使用Docker Hub是Docker官方维护的仓库,里面已经包含了很多的镜像,一般我们的需求直接在官方仓库搜索就可以得到解决.在官方的公共仓库中我们无需登录就可以进行镜像的 ...

  5. 杭电OJ--自行车计速器

    Biker's Trip Odometer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Ot ...

  6. Python基础(六)-内置函数

      map().filter().reduce() map(func,iterator) --> filter(func,iterator) --> reduce(func,iterato ...

  7. Java的关键字和标识符

    1.关键字 Java中共有52个关键字,其中有两个保留字,虽然查到百度百科上说是50个,但是事实确实是有52个(47+3+2). 1.1保留字 Java语言的的保留字是指在Java中商务预留的关键字 ...

  8. Eclipse主题设置

    1. 内部编辑区域主题 Eclipse黑色主题包 下载主题包解压到Eclipse安装目录下的dropins目录,重启Eclipse,Windows—>Preferences—>Genera ...

  9. @Autowired与 @Resource

    @Autowired, @Resource 1.注解类型: Autowired可用于构造器.属性.方法.注解 @Target({ElementType.CONSTRUCTOR, ElementType ...

  10. python ast

    import ast print ast.literal_eval('[1, 2, 3]')print eval("2 + 3 * len('hello')") == 17prin ...