publicstaticobjectExecuteScalar(DbConnectionconnection,CommandTypecommandType,stringcommandText,paramsDbParameter[]commandParameters){if(connection==null)thrownewArgumentNullException(“connection”);//connection.Close();connection.ConnectionString=GetRealConnectionString(commandText);//负载均衡改造完成的方法connection.Open();//创建DbCommand命令,并进行预处理DbCommandcmd=Factory.CreateCommand();boolmustCloseConnection=false;PrepareCommand(cmd,connection,(DbTransaction)null,commandType,commandText,commandParameters,outmustCloseConnection);//执行DbCommand命令,并返回结果.objectretval=cmd.ExecuteScalar();//清除参数,以便再次使用.cmd.Parameters.Clear();if(mustCloseConnection)connection.Close();returnretval;}
上面的 ‘connection.ConnectionString =’之前绑定的ConnectionString这个静态属性,而这个属性链接的就是‘主数据库’,这里我们只要将GetRealConnectionString(commandText)赋值给它就可以了,还是那句话,在GetRealConnectionString()就实现了数据库链接串的负载均衡,呵呵。类似上面的变动在DbHelper.cs还有几处,好在变化不太大,当然更不需要改变原有的数据访问层(比如IDataProvider.cs文件)了。
其实本文中介绍的数据库层负载均衡实现方法在MYSQL中早有相应的插件实现了,参见这篇文章。
该文章中的LUA脚本实现方式与本文类似,如下:
代码
–发送所有的非事务性SELECT到一个从数据库ifis_in_transaction==0andpacket:byte()==proxy.COM_QUERYandpacket:sub(2,7)==”SELECT”thenlocalmax_conns=-1localmax_conns_ndx=0fori=1,#proxy.serversdolocals=proxy.servers[i]–选择一个拥有空闲连接的从数据库ifs.type==proxy.BACKEND_TYPE_ROands.idling_connections>0thenifmax_conns==-1ors.connected_clients<max_connsthenmax_conns=s.connected_clientsmax_conns_ndx=iendendend…..
接着,我再介绍一下相应的配置文件和负载均衡算法的实现情况:) 配置文件(比如:Discuz.EntLib.ToolKit\config\dbsnap.config):
代码
<?xmlversion=”1.0″?><DbSnapAppConfigxmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”xmlns:xsd=”http://www.w3.org/2001/XMLSchema”><AppDbSnap>true</AppDbSnap><WriteWaitTime>1</WriteWaitTime><LoadBalanceScheduling>RoundRobinScheduling</LoadBalanceScheduling>–WeightedRoundRobinScheduling<RecordeLog>false</RecordeLog><DbSnapInfoList><DbSnapInfo><SouceID>1</SouceID><Enable>true</Enable><DbconnectString>DataSource=DAIZHJ\DNT_DAIZHJ;UserID=sa;Password=123123;InitialCatalog=dnt_snap;Pooling=true</DbconnectString><Weight>4</Weight></DbSnapInfo><DbSnapInfo><SouceID>2</SouceID><Enable>true</Enable><DbconnectString>DataSource=DAIZHJ-PC\2222;UserID=sa;Password=123;InitialCatalog=tabletest;Pooling=true</DbconnectString><Weight>3</Weight></DbSnapInfo><DbSnapInfo><SouceID>3</SouceID><Enable>true</Enable><DbconnectString>DataSource=DAIZHJ-PC\333333;UserID=sa;Password=123;InitialCatalog=tabletest;Pooling=true</DbconnectString><Weight>2</Weight></DbSnapInfo><DbSnapInfo><SouceID>4</SouceID><Enable>true</Enable><DbconnectString>DataSource=DAIZHJ-PC\44444444;UserID=sa;Password=123;InitialCatalog=tabletest;Pooling=true</DbconnectString><Weight>2</Weight></DbSnapInfo></DbSnapInfoList></DbSnapAppConfig>
上面的DbSnapInfoList就是相应的slave数据库链接列表,其中它的相应节点信息说明如下(Discuz.Config\DbSnapInfo.cs):
代码
[Serializable]publicclassDbSnapInfo{///<summary>///源ID,用于唯一标识快照在数据库负载均衡中的信息///</summary>privateint_souceID;///<summary>///源ID,用于唯一标识快照在数据库负载均衡中的信息///</summary>publicintSouceID{get{return_souceID;}set{_souceID=value;}}///<summary>///快照是否有效///</summary>privatebool_enable;///<summary>///是否有效///</summary>publicboolEnable{get{return_enable;}set{_enable=value;}}///<summary>///快照链接///</summary>privatestring_dbConnectString;///<summary>///快照链接///</summary>publicstringDbconnectString{get{return_dbConnectString;}set{_dbConnectString=value;}}///<summary>///权重信息,该值越高则意味着被轮循到的次数越多///</summary>privateint_weight;///<summary>///权重信息,该值越高则意味着被轮循到的次数越多///</summary>publicintWeight{get{return_weight;}set{_weight=value;}}}
当然DbSnapAppConfig作为DbSnapInfo列表的容器,其结构如下:
代码
[Serializable]publicclassDbSnapAppConfig:Discuz.Config.IConfigInfo{privatebool_appDbSnap;///<summary>///是否启用快照,如不使用,则即使DbSnapInfoList已设置有效快照信息也不会使用。///</summary>publicboolAppDbSnap{get{return_appDbSnap;}set{_appDbSnap=value;}}privateint_writeWaitTime=6;///<summary>///写操作等待时间(单位:秒),说明:在执行完写操作之后,在该时间内的sql请求依旧会被发往master数据库///</summary>publicintWriteWaitTime{get{return_writeWaitTime;}set{_writeWaitTime=value;}}privatestring_loadBalanceScheduling=”WeightedRoundRobinScheduling”;///<summary>///负载均衡调度算法,默认为权重轮询调度算法http://www.pcjx.com/Cisco/zhong/209068.html///</summary>publicstringLoadBalanceScheduling{get{return_loadBalanceScheduling;}set{_loadBalanceScheduling=value;}}privatebool_recordeLog=false;///<summary>///是否记录日志///</summary>publicboolRecordeLog{get{return_recordeLog;}set{_recordeLog=value;}}privateList<DbSnapInfo>_dbSnapInfoList;///<summary>///快照轮循列表///</summary>publicList<DbSnapInfo>DbSnapInfoList{get{return_dbSnapInfoList;}set{_dbSnapInfoList=value;}}}
通过这两个配置文件,就可以实现对数据访问层负载均衡的灵活配置了,不过上面的DbSnapAppConfig还有一个非常重要的属性没有介绍清楚,就是‘LoadBalanceScheduling’,其接口声明如下:
代码
///<summary>///负载均衡调度接口///</summary>publicinterfaceILoadBalanceScheduling{///<summary>///获取应用当前负载均衡调度算法下的快照链接信息///</summary>///<returns></returns>DbSnapInfoGetConnectDbSnap();}
它就是负载均衡算法的实现接口,为了便于说明在Discuz.EntLib中内置的两个负载均衡算法的实现情况,请先看下图: 内置的两个负载均衡算法,一个是RoundRobinScheduling,即轮叫调度(Round Robin Scheduling)算法,它的实现比较简单,就是对从数据库链接列表的依次遍历,如下:
代码
///<summary>///轮叫调度(RoundRobinScheduling)算法///</summary>publicclassRoundRobinScheduling:ILoadBalanceScheduling{privatestaticobjectlockHelper=newobject();///<summary>///当前的快照索引和权重信息///</summary>staticintcurentSnapIndex=0;staticRoundRobinScheduling(){}publicDbSnapInfoGetConnectDbSnap(){lock(lockHelper){if(curentSnapIndex>=DbSnapConfigs.GetEnableSnapList().Count)curentSnapIndex=(curentSnapIndex)%DbSnapConfigs.GetEnableSnapList().Count;returnDbSnapConfigs.GetEnableSnapList()[curentSnapIndex++];}}}
而另一种负载均衡算法就相对负载了,不过它也更符合实际的应用场景,它使用了权重的方法来让性能优良的机器分到更多的任务来均衡整个方案的性能,即权重轮询调度算法,实现代码如下:
代码
///<summary>///权重轮询调度算法///http://www.pcjx.com/Cisco/zhong/209068.html///http://id-phatman.spaces.live.com/blog/cns!CA763CA8DB2378D1!627.entry///</summary>publicclassWeightedRoundRobinScheduling:ILoadBalanceScheduling{privatestaticobjectlockHelper=newobject();///<summary>///快照的权重列表///</summary>staticList<int>snapWeightList=newList<int>();///<summary>///当前的快照索引和权重信息///</summary>staticintcurentSnapIndex,currentWeight;///<summary>///快照权重列表中最大的权重值和最大公约数///</summary>staticintmaxWeight,gcd;staticWeightedRoundRobinScheduling(){curentSnapIndex=-1;currentWeight=0;snapWeightList=GetSnapWeightList();maxWeight=GetMaxWeight(snapWeightList);gcd=GCD(snapWeightList);}///<summary>///获取应用当前负载均衡调度算法下的快照链接信息///</summary>///<returns></returns>publicDbSnapInfoGetConnectDbSnap(){lock(lockHelper){DbSnapInfocurrent=RoundRobinScheduling();if(current!=null)returncurrent;elsereturnDbSnapConfigs.GetEnableSnapList()[0];}}///<summary>///获取快照权重的列表///</summary>///<returns></returns>staticList<int>GetSnapWeightList(){List<int>snapWeightList=newList<int>();foreach(DbSnapInfodbSnapInfoinDbSnapConfigs.GetEnableSnapList()){snapWeightList.Add(dbSnapInfo.Weight);}returnsnapWeightList;}///<summary>///权重轮询调度算法///</summary>staticDbSnapInfoRoundRobinScheduling(){while(true){curentSnapIndex=(curentSnapIndex+1)%DbSnapConfigs.GetEnableSnapList().Count;if(curentSnapIndex==0){currentWeight=currentWeight-gcd;if(currentWeight<=0){currentWeight=maxWeight;if(currentWeight==0)returnnull;}}if(DbSnapConfigs.GetEnableSnapList()[curentSnapIndex].Weight>=currentWeight)returnDbSnapConfigs.GetEnableSnapList()[curentSnapIndex];}}///<summary>///获取最大权重///</summary>///<paramname=”snapList”></param>///<returns></returns>staticintGetMaxWeight(List<int>snapWeightList){intmaxWeight=0;foreach(intsnapWeightinsnapWeightList){if(maxWeight<snapWeight)maxWeight=snapWeight;}returnmaxWeight;}///<summary>///获取权重的最大公约数///</summary>///<returns></returns>staticintGCD(List<int>snapWeightList){//排序,得到数字中最小的一个snapWeightList.Sort(newWeightCompare());intminNum=snapWeightList[0];//最大公约数肯定大于等于1,且小于等于最小的那个数。//依次整除,如果余数全部为0说明是一个约数,直到打出最大的那个约数intgcd=1;for(inti=1;i<=minNum;i++){boolisFound=true;foreach(intsnapWeightinsnapWeightList){if(snapWeight%i!=0){isFound=false;break;}}if(isFound)gcd=i;}returngcd;}///<summary>///实现IComparer接口,用于对数字列表进行排序///</summary>privateclassWeightCompare:System.Collections.Generic.IComparer<int>{publicintCompare(intweightA,intweightB){returnweightA-weightB;}}}
到这里,主要的功能代码就介绍的差不多了,我们可以通过对dbsnap.config的相应节点配置,来灵活定制我们的负载均衡方案。同时,对一般开发者而言,这种架构是透明的,大家可以完全在不了解它的情况下开发自己的数据访问功能,并通过相应开关来让自己的代码支持均衡负载。
当然这个方案还有一些没考虑到的问题比如: 1.对‘主从数据库的健康度检查’,即如果主或从数据库出现故障的时候该如何处理,当然在sqlserver中还提供了镜像功能来解决类似问题,所以它也可做为一个备选方案。
2.当主数据库被发布出去后,主数据库的表和存储过程就会被‘锁定’,其不允许被再次修改了,所以还要继续研究如何解决这一问题。
不敢接受失败的人,往往是那些追求完美的人,
相关文章:
你感兴趣的文章:
标签云:
亚洲高清电影在线 ,
免费高清电影 ,
八戒影院夜间 ,
八戒电影最新大片 ,
出轨在线电影 ,
午夜电影院 ,
在线影院a1166 ,
在线电影院 ,
在线观看美剧下载 ,
日本爱情电影 ,
日韩高清电影在线 ,
电影天堂网 ,
直播盒子app ,
聚合直播 ,
高清美剧 ,
高清美剧在线观看
EhViewer-E站 ,
E站 ,
E站绿色版 ,
qqmulu.com ,
qq目录网 ,
qq网站目录 ,