上文已经讲到,Tcp连接池管理器为我们的应用进行了很多复杂的管理,比如功能服务器的调度(实现FS的负载均衡)、连接池的动态添加/移除、控制每个连接池的相关参数在UI上的显示等,并且连接池管理器与单个连接池拥有一样的接口ITcpPool。我们先回顾一下这个接口:
1
public
interface
ITcpPool
2
{
3
RentStreamResult RentTcpStream(
int
poolTypeKey ,
int
serviceKey ,
out
NetworkStream stream ,
out
int
serverID) ;
//
poolTypeKey表示某个城市,serviceKey表示某项服务
4
void
GiveBackTcpStream(
int
streamHashCode ,
int
serverID) ;
//
将tcp连接规还给连接池
5
void
SetStreamDamaged(
int
streamHashCode ,
int
serverID) ;
//
poolKey如果不易保存,则此处简单的传-1即可
6
7
event
CallBackCountChanged ActiveConnectionCountChanged ;
8
event
CallBackPoolStateChanged PoolStateChanged ;
9
}
10
RentTcpStream方法中的serviceKey参数反映了这样一个事实:与一个AS相连的多个FS中,每个FS加载的功能插件可以是不一样的。
比如,上图中的3个FS中只有FS1加载了前面介绍的“天气预测服务”插件,那么当一个“天气预测服务”请求到达AS时,AS就只能从与FS1之间的连接池中Rent一个Tcp连接,而不是从FS2或FS3。RentTcpStream方法的out参数serverID表明了这条连接是指向哪个FS的。
接下来考虑这样一个问题,当一个请求到来,这个请求可以被FS1、FS2、FS3处理,那么ITcpPoolsManager到底返回哪个连接池中的连接了?答案是负载最小的那个FS上的连接。
这是怎么做到的了?其实很简单。每个FS都定时(比如一秒一次)地把自己的负载(CPU利用率和内存利用率)通知给AS,通知给AS的方式可以有多种,比如.Net Remoting。ESFramework中有一个称为连接池调度器ITcpPoolScheduler的东东,它记录了每个FS实时的负载。这样当一个请求到来时,连接池管理器ITcpPoolsManager会要求连接池调度器从众多的FS中选出一个“满足条件”且负载最小的FS。这里的“满足条件”主要指的是对应的FS上有能处理该请求的功能插件。实现这种调度需要的支持的各个相互协作的组件的联系图大致如下:
图中
I
ServerPerfo
rmanceMonitor
是用于监控本地服务器性能的组件,它可以定时发布本服务器的性能数据(主要是
CPU
利用率和内存利用率),其定义如下:
1
public
interface
IServerPerformanceMonitor
2
{
3
void
Start() ;
4
void
Stop() ;
5
6
int
RefreshSpanSecs{
get
;
set
;}
7
8
event
CBackServerPerformance ServerPerformanceDataRefreshed ;
9
}
11
12
public
delegate
void
CBackServerPerformance(ServerPerformance performance) ;
13
public
class
ServerPerformance
14
{
15
public
float
CpuUsagePercent ;
16
public
float
MemoryUsagePercent ;
17
}
连接池调度器ITcpPoolScheduler的定义如下:
1
public
interface
ITcpPoolScheduler
2
{
3
//
以下方法属性仅仅由多连接池管理者调用
4
int
GetNextTcpPool(
int
poolTypeKey) ;
//
返回的是某连接池的服务端点的serverID ,如果没有可用的返回-1
5
int
GetNextTcpPool(
int
poolTypeKey ,
int
serviceKey) ;
6
7
void
Initialize() ;
8
void
Dispose() ;
//
还原到未初始化的状态
9
void
SetServerState(
int
serverID ,
bool
activated) ;
10
void
AddServer(
int
serverID) ;
11
void
RemoveServer(
int
serverID) ;
12
13
14
//
以下方法属性由外部指定或调用
15
void
SetPerformance(
int
serverID ,
float
cpuUsage ,
float
memUsage) ;
16
ITcpPoolHelper TcpPoolHelper{
set
;}
17
}
为了使负载均衡的效果更好,ITcpPoolScheduler可以实现的非常复杂,比如进行历史记录统计、分析、预测等。ESFramework给出了默认实现TcpPoolScheduler。
在组件联系图中还有一个IPoolEndPointsDisplayer组件,它用于在UI上显示每个功能服务器的详细信息和性能数据。
1
public
interface
IPoolEndPointsDisplayer
2
{
3
void
RegisterFs(
int
serverID ,
string
serverName ,IPEndPoint ipe ,
int
exceptCount) ;
4
void
UnRegisterFs(
int
serverID) ;
5
void
SetFsState(
int
serverID ,
bool
activated) ;
6
void
SetActiveCount(
int
serverID ,
int
activeCount) ;
7
void
UpdateFsPerformance(
int
serverID ,
float
cpuUsage ,
float
memUsage) ;
8
void
Clear() ;
9
}
FS管理器管理连接上本AS的每个功能服务器,这将在后文中讲到。
除了ITcpPool接口,连接池管理器还实现了ITcpPoolsManager接口:
1
public
interface
ITcpPoolsManager :ITcpPool
2
{
3
string
TcpPoolSchedulerTypeString{
set
;}
//
"ESFramework.Network.TcpPool.TcpPoolScheduler ,ESFramework"
4
ArrayList PoolEndPointList{
set
;}
//
连接池的服务端PoolEndPointInfo列表
5
int
ReconnectSpan{
get
;
set
;}
//
分钟
6
7
void
Initialize() ;
//
初次建立连接池
8
void
Dispose() ;
//
还原到没有初始化的状态
9
void
AddPool(PoolEndPointInfo info) ;
10
void
RemovePool(
int
serverID) ;
11
12
void
DisposePoolConnections(
int
serverID) ;
//
编号为serverID的服务器已停止,所以释放对应的Pool,但是不删除池,仍然定时重连
13
void
ReconnectPool(
int
serverID) ;
//
曾停止的服务器已启动完毕,所以可以重连了
14
15
///
<summary>
16
///
可直接使用 ESFramework.Network.TcpPool.PoolEndPointsDisplayer
17
///
</summary>
18
IPoolEndPointsDisplayer PoolEndPointsDisplayer{
set
;}
19
20
//
由ITcpPoolScheduler使用
21
void
SetPerformance(
int
serverID ,
float
cpuUsage ,
float
memUsage) ;
22
ITcpPoolHelper TcpPoolHelper{
set
;}
//
可由ESFramework.Architecture.LBS.FourTier.FsManager提供
23
}
AddPool方法和RemovePool方法表明可以动态的添加/移除Tcp连接池。注意接口中的SetPerformance方法,这个方法将被FS管理器调用,用于把从Remoting接收到的FS的性能数据通知给ITcpPoolsManager,然后ITcpPoolsManager再把这些数据提交给ITcpPoolScheduler记录,当需要进行调度的时候,ITcpPoolScheduler从这些记录中进行分析计算并找到负载最小的FS。TcpPoolSchedulerTypeString属性用于向连接池管理器提供调度者的实际类型,管理器将会通过反射创建调度者的实例。
还有一个需要设置的属性ITcpPoolHelper:
1
public
interface
ITcpPoolHelper
2
{
3
bool
ContainsService(
int
serverID ,
int
serviceKey) ;
4
bool
ServerIsTheType(
int
serverID ,
int
destType) ;
5
bool
ServerIsCompatible(
int
serverID ,
int
destType ,
int
serviceKey) ;
6
string
GetServerNameByID(
int
serverID) ;
7
}
由于这个接口提供了每个功能服务器详细信息,所以这个接口的实现可以直接由前面提到的FS管理器顺带实现。
ITcpPoolsManager是一个比较复杂的组件,它需要涉及到多个组件的协作。所以如果看完这篇文章,仍然还有些不清楚的地方,是很正常的。在后面系列文章的继续讲述中,这些不清晰的地方会慢慢拨开迷雾。
感谢关注!
上篇文章:ESFramework介绍之(10)-- Tcp连接池
转到 :ESFramework 可复用的通信框架(序)