Discuz!NT数据库读写分离方案-2

原文 http://www.cnblogs.com/daizhj/archive/2010/06/21/dbsnap_master_slave_database.html

 

   
       当然DbSnapAppConfig作为DbSnapInfo列表的容器,其结构如下:

代码
[Serializable]
public   class  DbSnapAppConfig : Discuz.Config.IConfigInfo
{
    
private   bool  _appDbSnap;
    
///   <summary>
    
///  是否启用快照,如不使用,则即使DbSnapInfoList已设置有效快照信息也不会使用。
    
///   </summary>
     public   bool  AppDbSnap
    {
        
get  {  return  _appDbSnap; }
        
set  { _appDbSnap  =  value; }
    }

    
private   int  _writeWaitTime  =   6 ;
    
///   <summary>
    
///  写操作等待时间(单位:秒), 说明:在执行完写操作之后,在该时间内的sql请求依旧会被发往master数据库
    
///   </summary>
     public   int  WriteWaitTime
    {
        
get  {  return  _writeWaitTime; }
        
set  { _writeWaitTime  =  value; }
    }

    
private   string  _loadBalanceScheduling  =   " WeightedRoundRobinScheduling " ;
    
///   <summary>
    
///  负载均衡调度算法,默认为权重轮询调度算法  http://www.pcjx.com/Cisco/zhong/209068.html
    
///   </summary>
     public   string  LoadBalanceScheduling
    {
        
get  {  return  _loadBalanceScheduling; }
        
set  { _loadBalanceScheduling  =  value; }
    }

    
private   bool  _recordeLog  =   false ;
    
///   <summary>
    
///  是否记录日志
    
///   </summary>
     public   bool  RecordeLog
    {
        
get  {  return  _recordeLog; }
        
set  { _recordeLog  =  value; }
    }
    

    
private   List < DbSnapInfo >  _dbSnapInfoList;
    
///   <summary>
    
///  快照轮循列表
    
///   </summary>
     public   List < DbSnapInfo >  DbSnapInfoList
    {
        
get  {  return  _dbSnapInfoList; }
        
set  { _dbSnapInfoList  =  value; }
    }
}

 

 

    通过这两个配置文件,就可以实现对数据访问层负载均衡的灵活配置了,不过上面的DbSnapAppConfig还有一个非常重要的
属性没有介绍清楚,就是‘LoadBalanceScheduling’,其接口声明如下:

 

代码
     ///   <summary>
    
///   负载均衡调度接口
    
///   </summary>
     public   interface  ILoadBalanceScheduling
    {
        
///   <summary>
        
///  获取应用当前负载均衡调度算法下的快照链接信息
        
///   </summary>
        
///   <returns></returns>
        DbSnapInfo GetConnectDbSnap();
    }

 

    
    它就是负载均衡算法的实现接口,为了便于说明在Discuz.EntLib中内置的两个负载均衡算法的实现情况,请先看下图:    
    
Discuz!NT数据库读写分离方案-2     
       内置的两个负载均衡算法,一个是RoundRobinScheduling,即轮叫调度(Round Robin Scheduling)算法,它的实现比较简单,就是对从数据库链接列表的依次遍历,如下:

代码
///   <summary>
///  轮叫调度(Round Robin Scheduling)算法
///   </summary>
public   class  RoundRobinScheduling : ILoadBalanceScheduling
{
    
private   static   object  lockHelper  =   new   object ();
    
///   <summary>
    
///  当前的快照索引和权重信息
    
///   </summary>
     static   int  curentSnapIndex  =   0 ;

    
static  RoundRobinScheduling()
    {}

    
public   DbSnapInfo GetConnectDbSnap()
    {
        
lock  (lockHelper)
        {
            
if  (curentSnapIndex  >=  DbSnapConfigs.GetEnableSnapList().Count)
                curentSnapIndex 
=  (curentSnapIndex)  %  DbSnapConfigs.GetEnableSnapList().Count;
         
            
return  DbSnapConfigs.GetEnableSnapList()[curentSnapIndex ++ ];
        }
    }
}

 

   
   
     而另一种负载均衡算法就相对负载了,不过它也更符合实际的应用场景,它使用了权重的方法来让性能优良的机器分到
更多的任务来均衡整个方案的性能,即权重轮询调度算法,实现代码如下:

 

代码
///   <summary>
///  权重轮询调度算法 
///   http://www.pcjx.com/Cisco/zhong/209068.html  
///   http://id-phatman.spaces.live.com/blog/cns !CA763CA8DB2378D1!627.entry
///   </summary>
public   class  WeightedRoundRobinScheduling : ILoadBalanceScheduling
{
    
private   static   object  lockHelper  =   new   object ();
    
///   <summary>
    
///  快照的权重列表
    
///   </summary>
     static  List < int >  snapWeightList  =   new  List < int > ();
    
///   <summary>
    
///  当前的快照索引和权重信息
    
///   </summary>
     static   int  curentSnapIndex, currentWeight;
    
///   <summary>
    
///  快照权重列表中最大的权重值和最大公约数
    
///   </summary>
     static   int  maxWeight, gcd;

    
static  WeightedRoundRobinScheduling()
    {
        curentSnapIndex 
=   - 1 ;
        currentWeight 
=   0 ;

        snapWeightList 
=  GetSnapWeightList();
        maxWeight 
=  GetMaxWeight(snapWeightList);
        gcd 
=  GCD(snapWeightList);
    }

    
///   <summary>
    
///  获取应用当前负载均衡调度算法下的快照链接信息
    
///   </summary>
    
///   <returns></returns>
     public   DbSnapInfo GetConnectDbSnap()
    {
        
lock  (lockHelper)
        {
            DbSnapInfo current 
=  RoundRobinScheduling();
            
if  (current  !=   null )
                
return  current;
            
else
                
return  DbSnapConfigs.GetEnableSnapList()[ 0 ];
        }
    }

    
///   <summary>
    
///  获取快照权重的列表
    
///   </summary>
    
///   <returns></returns>
     static  List < int >  GetSnapWeightList()
    {
        List
< int >  snapWeightList  =   new  List < int > ();

        
foreach  (DbSnapInfo dbSnapInfo  in  DbSnapConfigs.GetEnableSnapList())
        {
            snapWeightList.Add(dbSnapInfo.Weight);
        }
        
return  snapWeightList;
    }

    
///   <summary>
    
///  权重轮询调度算法
    
///   </summary>
     static  DbSnapInfo RoundRobinScheduling()
    {
        
while  ( true )
        {
            curentSnapIndex 
=  (curentSnapIndex  +   1 %  DbSnapConfigs.GetEnableSnapList().Count;
            
if  (curentSnapIndex  ==   0 )
            {
                currentWeight 
=  currentWeight  -  gcd;
                
if  (currentWeight  <=   0 )
                {
                    currentWeight 
=  maxWeight;
                    
if  (currentWeight  ==   0 )
                        
return   null ;
                }
            }
            
if  (DbSnapConfigs.GetEnableSnapList()[curentSnapIndex].Weight  >=  currentWeight)
                
return  DbSnapConfigs.GetEnableSnapList()[curentSnapIndex];
        }
    }

    
///   <summary>
    
///  获取最大权重
    
///   </summary>
    
///   <param name="snapList"></param>
    
///   <returns></returns>
     static   int  GetMaxWeight(List < int >  snapWeightList)
    {
        
int  maxWeight  =   0 ;
        
foreach  ( int  snapWeight  in  snapWeightList)
        {
            
if  (maxWeight  <  snapWeight)
                maxWeight 
=  snapWeight;
        }
        
return  maxWeight;
    }

    
///   <summary>
    
///  获取权重的最大公约数
    
///   </summary>
    
///   <returns></returns>
     static   int  GCD(List < int >  snapWeightList)
    {
        
//  排序,得到数字中最小的一个 
        snapWeightList.Sort( new  WeightCompare());
        
int  minNum  =  snapWeightList[ 0 ];

        
//  最大公约数肯定大于等于1,且小于等于最小的那个数。 
        
//  依次整除,如果余数全部为0说明是一个约数,直到打出最大的那个约数 
         int  gcd  =   1 ;
        
for  ( int  i  =   1 ; i  <=  minNum; i ++ )
        {
            
bool  isFound  =   true ;
            
foreach  ( int  snapWeight  in  snapWeightList)
            {
                
if  (snapWeight  %  i  !=   0 )
                {
                    isFound 
=   false ;
                    
break ;
                }
            }
            
if  (isFound)
                gcd 
=  i;
        }
        
return  gcd;
    }

    
///   <summary>
    
///  实现IComparer接口,用于对数字列表进行排序
    
///   </summary>   
     private   class  WeightCompare : System.Collections.Generic.IComparer < int >
    {
        
public   int  Compare( int  weightA,  int  weightB)
        {
            
return  weightA  -  weightB;
        }
    }
}

 

        到这里,主要的功能代码就介绍的差不多了,我们可以通过对dbsnap.config的相应节点配置,来灵活定制我们的负载均衡方案。同时,对一般开发者 而言,这种架构是透明的,大家可以完全在不了解它的情况下开发自己的数据访问功能,并通过相应开关来让自己的代码支持均衡负载。

        当然这个方案还有一些没考虑到的问题比如:
        1.对‘主从数据库的健康度检查’,即如果主或从数据库出现故障的时候该如何处理,当然在sqlserver中还提供了镜像功能 来解决类似问题,所以它也可做为一个备选方案。

        2.当主数据库被发布出去后,主数据库的表和存储过程就会被‘锁定’,其不允许被再次修改了,所以还要继续研究如何解决这一问题。

 

你可能感兴趣的:(html,数据结构,sql,算法,Cisco)