它主要是通过反射的方法将Discuz.EntLib.dll文件中的相应负载均衡算法实例进行绑定,然后以m_loadBalanceSche这个静态变量进行保存,而m_loadBalanceSche本身就是ILoadBalanceScheduling接口变量,该接口即是相应负载均衡算法的实现接口。同样因为文章内容的连续性,这里先不深挖相应的实现算法,我会在后面进行介绍。下面再来看一下GetRealConnectionString()中还有一段代码,如下: 代码
if (DbSnapConfigs.GetConfig().RecordeLog && snapLogList.Capacity > snapLogList.Count)
snapLogList.Add(string.Format("{{'SouceID' : {0}, 'DbconnectString' : '{1}', 'CommandText' : '{2}', 'PostDateTime' : '{3}'}},", dbSnapInfo.SouceID, dbSnapInfo.DbconnectString, commandText.Replace("'",""), Discuz.Common.Utils.GetDateTime())); return dbSnapInfo.DbconnectString;
List<string> snapLogList = new List<string>(400)
下面再来简单介绍一下,如何改造DbHelper.cs中原有方法,使其支持负载均衡功能。这里强调一点,就是:
代码
public static object ExecuteScalar(DbConnection connection, CommandType commandType, string commandText, params DbParameter[] commandParameters)
{ if (connection == null) throw new ArgumentNullException("connection"); //connection.Close(); connection.ConnectionString = GetRealConnectionString(commandText);//负载均衡改造完成的方法 connection.Open(); // 创建DbCommand命令,并进行预处理 DbCommand cmd = Factory.CreateCommand(); bool mustCloseConnection = false; PrepareCommand(cmd, connection, (DbTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection); // 执行DbCommand命令,并返回结果. object retval = cmd.ExecuteScalar(); // 清除参数,以便再次使用. cmd.Parameters.Clear(); if (mustCloseConnection) connection.Close(); return retval; } 其实本文中介绍的数据库层负载均衡实现方法在MYSQL中早有相应的插件实现了,参见这篇文章。
该文章中的LUA脚本实现方式与本文类似,如下: 代码
--发送所有的非事务性SELECT到一个从数据库
if is_in_transaction == 0 and packet:byte() == proxy.COM_QUERY and packet:sub(2, 7) == "SELECT" then local max_conns = -1 local max_conns_ndx = 0 for i = 1, #proxy.servers do local s = proxy.servers[i] -- 选择一个拥有空闲连接的从数据库 if s.type == proxy.BACKEND_TYPE_RO and s.idling_connections > 0 then if max_conns == -1 or s.connected_clients < max_conns then max_conns = s.connected_clients max_conns_ndx = i end end end ..... 接着,我再介绍一下相应的配置文件和负载均衡算法的实现情况:) 代码
<?xml version="1.0"?>
<DbSnapAppConfig xmlns: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>Data Source=DAIZHJ\DNT_DAIZHJ;User ID=sa;Password=123123;Initial Catalog=dnt_snap;Pooling=true</DbconnectString> <Weight>4</Weight> </DbSnapInfo> <DbSnapInfo> <SouceID>2</SouceID> <Enable>true</Enable> <DbconnectString>Data Source=DAIZHJ-PC\2222;User ID=sa;Password=123;Initial Catalog=tabletest;Pooling=true</DbconnectString> <Weight>3</Weight> </DbSnapInfo> <DbSnapInfo> <SouceID>3</SouceID> <Enable>true</Enable> <DbconnectString>Data Source=DAIZHJ-PC\333333;User ID=sa;Password=123;Initial Catalog=tabletest;Pooling=true</DbconnectString> <Weight>2</Weight> </DbSnapInfo> <DbSnapInfo> <SouceID>4</SouceID> <Enable>true</Enable> <DbconnectString>Data Source=DAIZHJ-PC\44444444;User ID=sa;Password=123;Initial Catalog=tabletest;Pooling=true</DbconnectString> <Weight>2</Weight> </DbSnapInfo> </DbSnapInfoList> </DbSnapAppConfig> 上面的DbSnapInfoList就是相应的slave数据库链接列表,其中它的相应节点信息说明如下(Discuz.Config\DbSnapInfo.cs): 代码
[Serializable]
public class DbSnapInfo { /// <summary> /// 源ID,用于唯一标识快照在数据库负载均衡中的信息 /// </summary> private int _souceID; /// <summary> /// 源ID,用于唯一标识快照在数据库负载均衡中的信息 /// </summary> public int SouceID { get { return _souceID; } set { _souceID = value; } } /// <summary> /// 快照是否有效 /// </summary> private bool _enable; /// <summary> /// 是否有效 /// </summary> public bool Enable { get { return _enable; } set { _enable = value; } } /// <summary> /// 快照链接 /// </summary> private string _dbConnectString; /// <summary> /// 快照链接 /// </summary> public string DbconnectString { get { return _dbConnectString; } set { _dbConnectString = value; } } /// <summary> /// 权重信息,该值越高则意味着被轮循到的次数越多 /// </summary> private int _weight; /// <summary> /// 权重信息,该值越高则意味着被轮循到的次数越多 /// </summary> public int Weight { get { return _weight; } set { _weight = value; } } } 代码
[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还有一个非常重要的 代码
(责任编辑:admin) /// <summary>
/// 负载均衡调度接口 /// </summary> public interface ILoadBalanceScheduling { /// <summary> /// 获取应用当前负载均衡调度算法下的快照链接信息 /// </summary> /// <returns></returns> DbSnapInfo GetConnectDbSnap(); } |