[源]
http://zhuweisky.cnblogs.com/archive/2006/03/16/351301.html凡是帶有“池”的,比如數據庫連接池、對象池、緩沖區池(后面可以看到
IBuffPool)等等,都是為了避免資源的反復創建/銷毀所帶來的開銷。需要為哪些資源對象建立“池”了?這些資源對象通常符合下面幾個特性:
(1)在應用中需要反復的被創建/銷毀。
(2)創建/銷毀的開銷比較大
(3)應用中給定時刻,對該資源對象的數量要求比較大
(4)資源對象最好是無狀態的(Stateless),這樣方便直接復用
AS(回顧)將所有的功能服務請求轉發給為該AS提供服務的FS群中的一個(參見。。。),然后FS將請求交給對應的功能插件處理。那么AS和FS之間的通信通過什么方式進行了?可選的方式有.netRemoting、WebService、Tcp/Udp等。基于效率和準確性的考慮,WebService和Udp是不大合適的。那么TCP和.netRemoting,到底選用哪個?我們知道.netRemoting底層也是基于Tcp或Http協議的,為了做到模擬本地方法調用的方式,.NETRemoting也做了很多轉換的操作(堆棧幀《=》消息),導致了一些開銷,而直接使用Tcp則可以避免,而且AS和FS之間的消息的格式是兼容的(主要是使用了完全相同的消息頭,這就夠了),也就是說一條消息從客戶端發出,可以不需做任何轉換就直接被FS的功能插件處理(加密、壓縮不計在內)。
如你所想,ESFramework推薦的方式是AS和FS直接通過低層的Tcp進行通信。為了避免Tcp連接不斷建立、銷毀所帶來的開銷,AS和FS通信前,可以建立Tcp連接池。本文就關注Tcp連接池的原理和實現。
Tcp連接池中存放的是Tcp連接――即NetworkStream對象,當應用需要使用時,就從Tcp連接池中租借“Rent”一條連接,用完后再歸還“GiveBack”給連接池。
public class TcpStreamPool :ITcpStreamPool ,ITcpPool
從上面的定義可以看到TcpStreamPool從兩個接口繼承:ITcpPool和ITcpStreamPool。先看看ITcpStreamPool的定義:
1 /// <summary>
2 /// ITCPStreamPool tcp連接池用于管理大量的TCP連接
3 /// 作者:朱偉 sky.zhuwei@163.com
4 /// sky 2005.02.24
5 /// </summary>
6 public interface ITcpStreamPool
7 {
8 int ServerID {get ;set ;}
9 int StreamCount {get ;set ;} //期望連接總數
10 int ActiveConnectionCount {get ;} //實際可用的連接數
11 IPEndPoint FsIpe {get ;set ;} //功能服務器的IPE
12 int ReconnectSpan{get ;set ;} // 分鐘
13 bool IsActive{get;}
14
15 void ReConnect() ; //手動重連
16 void Initialize() ;
17 void DisposeConnections() ; //釋放池中所有連接,可以通過ReConnect來重新建立連接
18 void SetStreamDamaged(int streamHashCode) ;
19
20 NetworkStream RentTcpStream() ;
21 void GiveBackTcpStream(int streamHashCode) ;//將tcp連接規還給連接池
22 }
AS和每個FS之間都有一個連接池,每個功能服務器的區分是通過ServerID來的,所以連接池也有一個ServerID屬性標志了本連接池是與哪個FS相連的。ReconnectSpan屬性表明連接池要支持重連機制,即當連接池中的所有連接都斷開后(可能是FS掉線引起的),連接池應能定時重連FS,直至該池中的所有連接重新建立。
如果應用從連接池Rent了一條連接,然后在使用的過程中該連接斷開了,則應用應該調用連接池的SetStreamDamaged方法通知連接池該連接已不可用。RentTcpStream方法和GiveBackTcpStream方法是我們最常用的租借/歸還連接的方法了。
注意,很多方法的參數中有streamHashCode參數,它是NetworkStream對象的Hashcode,系統中的每個NetworkStream對象的HashCode是不同的,并且,它的HashCode在NetworkStream對象的整個生命期間不變,所以可以使用HashCode唯一標志每個連接。
似乎,ITcpStreamPool接口已經反映了一個連接池的所有東西,是的。那么ITcpPool接口又起什么作用了?現看看ITcpPool的樣子:
1 /// <summary>
2 /// ITcpPool 用于將一個TCP連接池和一組TCP連接池統一起來。這樣消息分派器只需使用ITcpPool接口即可。
3 /// zhuweisky
4 /// </summary>
5 public interface ITcpPool
6 {
7 RentStreamResult RentTcpStream(int poolTypeKey ,int serviceKey ,out NetworkStream stream ,out int serverID) ;//poolTypeKey表示某個城市,serviceKey表示某項服務
8 void GiveBackTcpStream(int streamHashCode ,int serverID) ;//將tcp連接規還給連接池
9 void SetStreamDamaged(int streamHashCode ,int serverID) ;//poolKey如果不易保存,則此處簡單的傳-1即可
10
11 event CallBackCountChanged ActiveConnectionCountChanged ;
12 event CallBackPoolStateChanged PoolStateChanged ;
13 }
14
15 public delegate void CallBackCountChanged(int serverID ,int activeConnCount) ;
16 public delegate void CallBackPoolStateChanged(int serverID ,bool disconnected) ;
17
18 public enum RentStreamResult
19 {
20 Succeed ,Busy ,TheServiceNotExist
21 }
你可能已經發現,ITcpPool中的所有元素在ITcpStreamPool接口中都可以找到對應物,只是有些方法的參數變復雜了。這主要是因為ITcpStreamPool接口針對的是一個FS,而ITcpPool可能是針對一個FS也可能是一組FS。當ITcpPool背后是一組FS時,就需要參數ServerID來區分每一個FS。我們知道,AS和對應的每個FS之間都使用一個Tcp連接池通信:
所有的這些連接池需要被管理起來,ESFramework中的ITcpPoolsManager(連接池管理器)組件實現了對多個Tcp連接池的管理。為了把連接池管理器和單個連接池統一起來,使它們有相同的外部接口,所以引入了ITcpPool接口。
這樣做的好處是,在應用中直接使用ITcpPool接口就可以了,而不用關心這個接口背后是一個“單個連接池”(對應單個FS)還是由連接池管理器管理的“一組連接池”(對應多個FS)。而且ITcpPoolsManager為我們的應用進行了很多復雜的管理,比如動能服務器的調度(實現FS的負載均衡)、連接池的動態添加/移除等。這些將在下文中介紹。
感謝關注。