TCP连接可用性检测

1:问题的引出

    我们假设有两种服务,A和B。其中B部署在无差别的多台机器上。当A向B请求服务的时候我们通过软件或是硬件的负载均衡算法把该请求路由到提供B服务的某台机器上。这个时候B对A提供的服务在可靠性上我们是要做些工作的。如果负载均衡是通过软件来实现的那么检测通向B的TCP链接是否可用这个工作就显得很有必要。如果您认同以上的文字那么接下来我试着构造一个场景并提出一个解决方案来。

2:场景

    假设B服务就是我们的缓存服务。如果我们通过某些哈希算法把不同的内容存储到缓存服务器上。那么他的执行序列应该是

    1:计算要缓存对象的键值

    2:拿到缓存服务器的列表

    3:通过哈希算法把内容分配到缓存服务器上(一致性哈希算法我会再撰稿给大家介绍) 

    好了,问题来了。如果提供B服务的某台机器网络出现瞬断或是连接不可用了。那么A将得到大量的错误。这个时候我们需要加强缓存服务的可靠性指标。

3:解决方案 

    基于可靠性考虑,我们可以这样,建立A到B多台服务器的长连接,在B不能连通的时候我们把这台不能连通的服务器从可用服务列表中移除把备用服务器顶上来,同时把这台不可用的服务器存储到不可用列表中。我们再开启一个工作,按照策略我们周期性的探测不可用列表中的机器看那台可用,如果某一时刻变得可用了我们再把它加入可用列表同时把备用服务器顶下来。 

    以下提供一些代码

    public class TCPReliabilityCheck
    {

        
public delegate void ReportChange(string HostAddress, SocketError info);
        
public event ReportChange changeInfo;

        
private Socket clientSocket;
        
private string hostAddress = string.Empty;

        
public TCPReliabilityCheck(string HostAddress,int Port)
        {
            hostAddress 
= HostAddress;
            Check(HostAddress, Port);
        }

        
private void Check(string HostAddress, int Port)
        {
            
if (string.IsNullOrEmpty(HostAddress))
            {
                
throw new Exception("IP Address is Missing");
                
return;
            }

            
if (Port == 0)
            {
                
throw new Exception("Port is Missing");
                
return;
            }

            IPHostEntry host 
= Dns.GetHostEntry(HostAddress);
            IPAddress[] addressList 
= host.AddressList;
            IPEndPoint point 
= new IPEndPoint(addressList[addressList.Length - 1], Port);
            clientSocket 
= new Socket(point.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            SocketAsyncEventArgs connectArgs 
= new SocketAsyncEventArgs();
            connectArgs.UserToken 
= clientSocket;
            connectArgs.RemoteEndPoint 
= point;
            connectArgs.Completed 
+= new EventHandler<SocketAsyncEventArgs>(OnConnect);
            clientSocket.ConnectAsync(connectArgs);
        }

        
private void OnConnect(object sender, SocketAsyncEventArgs e)
        {
            
if (e.SocketError == SocketError.Success)
            {
                e.Completed 
-= OnConnect;
                e.Completed 
+= Receive;

                var buffer 
= new byte[1024];
                e.SetBuffer(buffer, 
0, buffer.Length);

                clientSocket.ReceiveAsync(e);
            }
            
else
                changeInfo(hostAddress,e.SocketError);
        }

        
private void Receive(object sender, SocketAsyncEventArgs e)
        {
            changeInfo(hostAddress, e.SocketError);
        }

    } 

    接下来对TCPReliabilityCheck做些介绍。

    首先这个类是建立了与某台服务器的TCP长连接,其次这个类只会把连接出现异常时的信息发布出来。 

4:后记

    当然这只是一种方法。如果您有其他解决方案的话,希望能提出来我们一起讨论讨论。当然本文的解决方案也接受您的批评指正。

 

追加一个状态图

 

 

posted @ 2009-11-26 17:12  李占卫  阅读(2105)  评论(7编辑  收藏  举报