垂直分割群集模型与多通道引擎 -- ESFramework 4.0 进阶(10)
在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)的更多相关文章
- ESFramework 4.0 进阶(04)-- 驱动力:通信引擎(下)
在ESFramework 4.0 进阶(03)-- 驱动力:通信引擎(上)一文中,我们对ESFramework提供的每一个通信引擎的接口都做了详细了说明,这篇文章我们将继续探讨这些接口的实现类 -- ...
- 驱动力—— 通信引擎(上)—— ESFramework 4.0 进阶(03)
在ESFramework 4.0 进阶(02)-- 核心:消息处理的骨架流程一文中我们详细介绍了ESFramework中消息处理的骨架流程,并且我们已经知道,ESFramework中的所有通信引擎使用 ...
- 好友与组--ESFramework 4.0 进阶(11)
大部分分布式通信系统中,都会涉及到客户端之间相互通信.以及需要将客户端进行分组的功能,或者是类似这方面的需求.ESFramework对这一常见的任务内置了强大的支持,包括从客户端到服务端.一直到Pla ...
- 消息同步调用-- ESFramework 4.0 进阶(07)
分布式系统的构建一般有两种模式,一是基于消息(如Tcp,http等),一是基于方法调用(如RPC.WebService.Remoting).深入想一想,它们其实是一回事.如果你了解过.NET的Prox ...
- 在线用户管理--ESFramework 4.0 进阶(05)
无论我们采用何种通信框架来构建我们的分布式系统,在服务端进行用户管理都是非常重要的一个环节.然而用户管理是否应该隶属于通信框架了?这个并不一定,通常来说,用户管理是与具体应用紧密相关的,应该是由应用解 ...
- 正规消息发送器-- ESFramework 4.0 进阶(06)
在ESFramework 4.0 进阶(04)-- 驱动力:通信引擎(下)一文末尾我们已经将通信引擎以及整个消息骨架流程组装起来了,只要通信引擎一接收到消息,框架就会按照规定的流程进行运转.到这里,自 ...
- 核心梳理——消息处理的骨架流程——ESFramework 4.0 进阶(02)
在ESFramework 4.0 概述一文中,我们提到ESFramework.dll作为通信框架的核心,定义了消息处理的骨架流程,本文我们来详细剖析这个流程以及该骨架中所涉及的各个组件.ESFrame ...
- 挂接P2P通道-- ESFramework 4.0 进阶(08)
最新版本的ESFramework/ESPlus提供了基于TCP和UDP的P2P通道,而无论我们是使用基于TCP的P2P通道,还是使用基于UDP的P2P通道,ESPlus保证所有的P2P通信都是可靠的. ...
- ESFramework 4.0 进阶(01)-- 消息
需要交互的分布式系统之间通过消息来传递有意义的信息.消息是通信框架的核心.离开了消息,再谈通信框架就没有任何意义,所以,消息是ESFramework中一个最核心的概念. 一. 消息的类别 在具体的应用 ...
随机推荐
- [转]奇异值分解(We Recommend a Singular Value Decomposition)
原文作者:David Austin原文链接: http://www.ams.org/samplings/feature-column/fcarc-svd译者:richardsun(孙振龙) 在这篇文章 ...
- Openjudge-NOI题库-数根
题目描述 Description 数根可以通过把一个数的各个位上的数字加起来得到.如果得到的数是一位数,那么这个数就是数根.如果结果是两位数或者包括更多位的数字,那么再把这些数字加起来.如此进行下去, ...
- wpf 寻找某个控件下的子控件
/// <summary> /// 寻找某个控件下的子控件 /// </summary> /// <typeparam name="ChildType" ...
- magento获取一些值的方法函数
1显示产品列表页(列表.PHTML).echo $this->getProductListHtml(); 2.得到你的Magento的页面的路径. echo $this->getUrl( ...
- niceScroll接口大全
Query滚动条插件兼容ie6+.手机.ipad http://www.areaaperta.com/nicescroll/ jQuery(function($){ $("#scrollIn ...
- [Q]自定义纸张大小
问:当打印机纸张列表里没有符合要求的纸张大小,例如如何打印加长图?答:当打印非标准图框时,你可能在图纸列表里找不到想要纸幅.你需要自己新建你需要的纸幅,以pdfFactory虚拟打印机为例(其它打印机 ...
- 一步步优化JVM三:GC优化基础
本节主要描述关于垃圾回收器性能的三个指标,三个关于垃圾回收器优化的基本原则,以及优化HotSpot VM的垃圾回收器的信息收集,在这些指标中权衡以及信息的收集是非常重要的. 性能指标 吞吐量:衡 ...
- DFS - leetcode [深度优先遍历]
最短路径=>BFS 所有路径=>DFS 126. Word Ladder II BFS+DFS: BFS找出下一个有效的word进队 并记录step 更新两个变量:unordered ...
- HDU 5795 A Simple Nim(SG打表找规律)
SG打表找规律 HDU 5795 题目连接 #include<iostream> #include<cstdio> #include<cmath> #include ...
- sqlite导入后无法使用
问题:sqlite导入后无法使用 解决方式:引入sqlite3 的libraries ,然后再在 projectName-Bridging-Header.h 中添加 #import "sql ...