亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > CMS > Discuz > 正文

詳解Discuz!NT數(shù)據(jù)庫讀寫分離方案

2024-09-11 09:06:54
字體:
供稿:網(wǎng)友

????? 我們?cè)陂_發(fā)項(xiàng)目的時(shí)候,當(dāng)我們的業(yè)務(wù)越來越多的時(shí)候,網(wǎng)站所需要的服務(wù)器壓力也會(huì)越來越大,下面就讓我們一起來了解一下詳解Discuz!NT數(shù)據(jù)庫讀寫分離方案吧!

????? 目前在Discuz!NT這個(gè)產(chǎn)品中,數(shù)據(jù)庫作為數(shù)據(jù)持久化工具,必定在并發(fā)訪問頻繁且負(fù)載壓力較大的情況下成?為系統(tǒng)性能的‘瓶頸'。即使使用本地緩存等方式來解決頻繁訪問數(shù)據(jù)庫的問題,但仍舊會(huì)有大量的并發(fā)請(qǐng)求要訪問動(dòng)態(tài)數(shù)據(jù),雖然 SQL2005及2008以上版本中性能不斷提升,查詢計(jì)劃和存儲(chǔ)過程運(yùn)行得越來越高效,但最終還是?要面臨‘瓶頸'這一問 題。當(dāng)然這也是許多大型網(wǎng)站不斷研究探索各式各樣的方案來有效降低數(shù)據(jù)訪問負(fù)荷的原?因, 其中的‘讀寫分離'方案就是一種被廣泛采用的方案。
????? Discuz!NT這個(gè)產(chǎn)品在其企業(yè)版中提供了對(duì)‘讀寫分離'機(jī)制的支持,使對(duì)CPU及內(nèi)存消耗嚴(yán)重的操作(CUD)被?分離到一臺(tái)或幾臺(tái)性能很高的機(jī)器上,而將頻繁讀取的操作(select)放到幾臺(tái)配置較低的機(jī)器上,然后通過‘事務(wù)?發(fā)布訂閱機(jī)制',實(shí)現(xiàn)了在多個(gè)sqlserver數(shù)據(jù)庫之間快速高效同步數(shù)據(jù),從而達(dá)到了將‘讀寫請(qǐng)求'按實(shí)際負(fù)載?情況進(jìn)行均衡分布的效果。

???? ?下面就簡(jiǎn)要介紹一下其實(shí)現(xiàn)思路。注:有關(guān)數(shù)據(jù)同步的工具已在sqlserver中自帶了,可以參考這篇文章。

??????將相應(yīng)的數(shù)據(jù)由Master(主)數(shù)據(jù)庫中‘發(fā)布'出來,然后使用推送的方式(注:事務(wù)發(fā)布可以指定是‘通過主?數(shù)據(jù)庫推送' 還是‘訂閱服務(wù)器去獲取')發(fā)送到訂閱它的數(shù)據(jù)庫中,就實(shí)現(xiàn)了數(shù)據(jù)同步功能。

????? 下面就介紹一下如何通過改變既有代碼來實(shí)現(xiàn)在‘幾個(gè)從數(shù)據(jù)庫(類似快照)'間進(jìn)行讀取數(shù)據(jù)的負(fù)載均衡。

???? ?原有的代碼中因?yàn)槭褂昧朔謱訖C(jī)制,所以我們只要在‘?dāng)?shù)據(jù)訪問層'動(dòng)一下心思就可以了。在這里我的一個(gè)設(shè)?計(jì)思路就是不改變已有的數(shù)據(jù)庫訪問接口(包括參數(shù)等)的前提下,實(shí)現(xiàn)底層自動(dòng)將現(xiàn)有的數(shù)據(jù)訪問操作進(jìn)行負(fù)載?均衡。這樣做的好處不用多說了,同時(shí)也讓這個(gè)負(fù)載均衡功能與數(shù)據(jù)訪問層相分離,不要耦合的太緊密,同時(shí)如果不曉得底層 的實(shí)現(xiàn)原理也可以只通過一個(gè)開關(guān)(后面會(huì)介紹),就可以讓自己的sql語句自動(dòng)實(shí)現(xiàn)動(dòng)態(tài)負(fù)載均衡。

???? ?說到這里,我來對(duì)照代碼進(jìn)一步闡述:

???? ?首先就是(Discuz.Data/DbHelper.cs)代碼,主要變動(dòng)如下(新增方法部分):???

復(fù)制代碼 代碼如下:

/// <summary>
/// 獲取使用的數(shù)據(jù)庫(或快照)鏈接串
/// </summary>
/// <param name="commandText">存儲(chǔ)過程名或都SQL命令文本</param>
/// <returns></returns>
public static string GetRealConnectionString(string commandText)
{
if (DbSnapConfigs.GetConfig() != null && DbSnapConfigs.GetConfig().AppDbSnap)
{
commandText = commandText.Trim().ToLower();
if (commandText.StartsWith("select") || ((commandText.StartsWith(BaseConfigs.GetTablePrefix) && UserSnapDatabase(commandText))))
{
DbSnapInfo dbSnapInfo = GetLoadBalanceScheduling.GetConnectDbSnap();
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;
}
}
return ConnectionString;
}


上面的方法將會(huì)對(duì)傳入的sql語句進(jìn)行分析,找出其中是CUD操作還是SELECT操作,來區(qū)別是讀還是寫操作。而snapLogList列表則是之前所配置的‘事務(wù)發(fā)布訂閱'模式下的相關(guān)‘從數(shù)據(jù)庫'(Slave Database)鏈接串的列表,例如(dbsnap.config文件的DbSnapInfoList節(jié)點(diǎn)):

?

復(fù)制代碼 代碼如下:

?


<?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>
</DbSnapInfoList>
</DbSnapAppConfig>


有關(guān)相應(yīng)配置節(jié)點(diǎn)和負(fù)載均衡算法會(huì)在后面提到,這里為了保持文章內(nèi)容的連續(xù)性暫且跳過,下面接著瀏覽一下上面調(diào)用的‘UserSnapDatabase'方法:

?

復(fù)制代碼 代碼如下:

?


/// <summary>
/// 是否使用快照數(shù)據(jù)庫
/// </summary>
/// <param name="commandText">查詢</param>
/// <returns></returns>
private static bool UserSnapDatabase(string commandText)
{
// 如果上次刷新cookie間隔小于5分鐘, 則不刷新數(shù)據(jù)庫最后活動(dòng)時(shí)間
if (commandText.StartsWith(BaseConfigs.GetTablePrefix + "create"))
{
Utils.WriteCookie("JumpAfterWrite", Environment.TickCount.ToString());
return false;
}
else if (!String.IsNullOrEmpty(Utils.GetCookie("JumpAfterWrite")) && (Environment.TickCount - TypeConverter.StrToInt(Utils.GetCookie("JumpAfterWrite"), Environment.TickCount)) < DbSnapConfigs.GetConfig().WriteWaitTime * 1000)
return false;
else if (!commandText.StartsWith(BaseConfigs.GetTablePrefix + "get"))
return false;
return true;
}


該方法的作用很簡(jiǎn)單,就是當(dāng)數(shù)據(jù)庫有CUD操作時(shí),通過寫cookie的方式向客戶端寫一個(gè)鍵值‘JumpAfterWrite',這個(gè)鍵值很重要,就是提供一個(gè)標(biāo)簽(flag)來指示:‘當(dāng)前用戶執(zhí)行cud操作時(shí),頁面跳轉(zhuǎn)到其它頁面而主數(shù)據(jù)庫還沒來得及將數(shù)據(jù)推送到從數(shù)據(jù)庫'這一情況而造成的‘?dāng)?shù)據(jù)不同步'問題。
舉了例子,當(dāng)在一個(gè)版塊中‘發(fā)表主題'后系統(tǒng)自動(dòng)跳轉(zhuǎn)到‘顯示該主題頁面'時(shí),如果主數(shù)據(jù)庫中插入了一個(gè)新主題而從數(shù)據(jù)庫沒有被及時(shí)更新這一主題信息時(shí),就會(huì)報(bào)‘主題不存在'這個(gè)錯(cuò)誤。所以這里加了一個(gè)設(shè)置,就是下面這一行:

?

復(fù)制代碼 代碼如下:

?


(Environment.TickCount - TypeConverter.StrToInt(Utils.GetCookie("JumpAfterWrite"), Environment.TickCount)) < DbSnapConfigs.GetConfig().WriteWaitTime * 1000)


它所做的就是確保用戶cud操作之后,在規(guī)定的時(shí)間內(nèi)還是訪問主數(shù)據(jù)庫,當(dāng)時(shí)間超過時(shí),才將當(dāng)前用戶的訪問請(qǐng)求(select)均衡到其它從數(shù)據(jù)庫中。
當(dāng)然,在GetRealConnectionString()方法中,還有一行代碼很重要,就是下面這一行:

?

復(fù)制代碼 代碼如下:

?


DbSnapInfo dbSnapInfo = GetLoadBalanceScheduling.GetConnectDbSnap();

?


它的作用就是加載配置文件信息,其中最主要的就是相應(yīng)的‘負(fù)載均衡算法實(shí)例'來獲取相應(yīng)的從數(shù)據(jù)庫鏈接串,下面先看一
下‘靜態(tài)屬性'GetLoadBalanceScheduling的相關(guān)信息:

代碼

?

?

復(fù)制代碼 代碼如下:

?


/// <summary>
/// 負(fù)載均衡調(diào)度接口
/// </summary>
private static ILoadBalanceScheduling m_loadBalanceSche;
/// <summary>
/// 初始化負(fù)載均衡調(diào)度接口實(shí)例
/// </summary>
private static ILoadBalanceScheduling GetLoadBalanceScheduling
{
get
{
if (m_loadBalanceSche == null)
{
try
{
m_loadBalanceSche = (ILoadBalanceScheduling)Activator.CreateInstance(Type.GetType(string.Format("Discuz.EntLib.{0}, Discuz.EntLib", DbSnapConfigs.GetConfig().LoadBalanceScheduling), false, true));
}
catch
{
throw new Exception("請(qǐng)檢查config/dbsnap.config中配置是否正確");
}
}
return m_loadBalanceSche;
}
}


它主要是通過反射的方法將Discuz.EntLib.dll文件中的相應(yīng)負(fù)載均衡算法實(shí)例進(jìn)行綁定,然后以m_loadBalanceSche這個(gè)靜態(tài)變量進(jìn)行保存,而m_loadBalanceSche本身就是ILoadBalanceScheduling接口變量,該接口即是相應(yīng)負(fù)載均衡算法的實(shí)現(xiàn)接口。同樣因?yàn)槲恼聝?nèi)容的連續(xù)性,這里先不深挖相應(yīng)的實(shí)現(xiàn)算法,我會(huì)在后面進(jìn)行介紹。下面再來看一下GetRealConnectionString()中還有一段代碼,如下:
代碼

?

復(fù)制代碼 代碼如下:

?


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;


上面代碼將當(dāng)前的負(fù)載均衡得到的鏈接串保存到一個(gè)snapLogList列表中,該列表聲明如下:

?

復(fù)制代碼 代碼如下:

?


List<string> snapLogList = new List<string>(400)


為什么要提供這個(gè)列表并進(jìn)行記錄?主要是為了考查負(fù)載均衡算法的工作情況,因?yàn)樵跀?shù)據(jù)訪問層獲取相應(yīng)鏈接串信息并進(jìn)行記錄很不方便,所以我用這個(gè)變量記錄大約400條‘負(fù)載均衡'數(shù)據(jù)鏈接串,以便在相應(yīng)的Discuz.EntLib.ToolKit工具包中進(jìn)行觀察,監(jiān)視其‘工作情況'。這里我們只要知道通過GetRealConnectionString()方法就實(shí)現(xiàn)了對(duì)sql語句或存儲(chǔ)過程進(jìn)行分析并進(jìn)行負(fù)載均衡的效果了(注:該操作可能會(huì)耗時(shí),所以在DbSnapConfigs中提供了一個(gè)開關(guān)‘RecordeLog'來進(jìn)行控制,后面會(huì)介紹)。

下面再來簡(jiǎn)單介紹一下,如何改造DbHelper.cs中原有方法,使其支持負(fù)載均衡功能。這里強(qiáng)調(diào)一點(diǎn),就是:
GetRealConnectionString()方法只是造了一個(gè)房子,里面的家具還是要自己搬。
而家具就是那些老的方法,比如:

代碼

?

復(fù)制代碼 代碼如下:

?


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);//負(fù)載均衡改造完成的方法
connection.Open();
// 創(chuàng)建DbCommand命令,并進(jìn)行預(yù)處理
DbCommand cmd = Factory.CreateCommand();
bool mustCloseConnection = false;
PrepareCommand(cmd, connection, (DbTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection);
// 執(zhí)行DbCommand命令,并返回結(jié)果.
object retval = cmd.ExecuteScalar();
// 清除參數(shù),以便再次使用.
cmd.Parameters.Clear();
if (mustCloseConnection)
connection.Close();
return retval;
}


上面的 ‘connection.ConnectionString ='之前綁定的ConnectionString這個(gè)靜態(tài)屬性,而這個(gè)屬性鏈接的就是‘主數(shù)據(jù)庫',
這里我們只要將GetRealConnectionString(commandText)賦值給它就可以了,還是那句話,在GetRealConnectionString()就實(shí)現(xiàn)了
數(shù)據(jù)庫鏈接串的負(fù)載均衡,呵呵。類似上面的變動(dòng)在DbHelper.cs還有幾處,好在變化不太大,當(dāng)然更不需要改變?cè)械臄?shù)據(jù)訪問層
(比如IDataProvider.cs文件)了。
其實(shí)本文中介紹的數(shù)據(jù)庫層負(fù)載均衡實(shí)現(xiàn)方法在MYSQL中早有相應(yīng)的插件實(shí)現(xiàn)了,參見這篇文章。??????

該文章中的LUA腳本實(shí)現(xiàn)方式與本文類似,如下:
--發(fā)送所有的非事務(wù)性SELECT到一個(gè)從數(shù)據(jù)庫

?

復(fù)制代碼 代碼如下:

?


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]
-- 選擇一個(gè)擁有空閑連接的從數(shù)據(jù)庫
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
.....


接著,我再介紹一下相應(yīng)的配置文件和負(fù)載均衡算法的實(shí)現(xiàn)情況:)
配置文件(比如:Discuz.EntLib.ToolKit/config/dbsnap.config):
代碼

?

復(fù)制代碼 代碼如下:

?


<?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就是相應(yīng)的slave數(shù)據(jù)庫鏈接列表,其中它的相應(yīng)節(jié)點(diǎn)信息說明如下(Discuz.Config/DbSnapInfo.cs):
代碼

?

復(fù)制代碼 代碼如下:

?


[Serializable]
public class DbSnapInfo
{
/// <summary>
/// 源ID,用于唯一標(biāo)識(shí)快照在數(shù)據(jù)庫負(fù)載均衡中的信息
/// </summary>
private int _souceID;
/// <summary>
/// 源ID,用于唯一標(biāo)識(shí)快照在數(shù)據(jù)庫負(fù)載均衡中的信息
/// </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>
/// 權(quán)重信息,該值越高則意味著被輪循到的次數(shù)越多
/// </summary>
private int _weight;
/// <summary>
/// 權(quán)重信息,該值越高則意味著被輪循到的次數(shù)越多
/// </summary>
public int Weight
{
get { return _weight; }
set { _weight = value; }
}
}


當(dāng)然DbSnapAppConfig作為DbSnapInfo列表的容器,其結(jié)構(gòu)如下:
代碼

?

復(fù)制代碼 代碼如下:

?


[Serializable]
public class DbSnapAppConfig : Discuz.Config.IConfigInfo
{
private bool _appDbSnap;
/// <summary>
/// 是否啟用快照,如不使用,則即使DbSnapInfoList已設(shè)置有效快照信息也不會(huì)使用。
/// </summary>
public bool AppDbSnap
{
get { return _appDbSnap; }
set { _appDbSnap = value; }
}
private int _writeWaitTime = 6;
/// <summary>
/// 寫操作等待時(shí)間(單位:秒), 說明:在執(zhí)行完寫操作之后,在該時(shí)間內(nèi)的sql請(qǐng)求依舊會(huì)被發(fā)往master數(shù)據(jù)庫
/// </summary>
public int WriteWaitTime
{
get { return _writeWaitTime; }
set { _writeWaitTime = value; }
}
private string _loadBalanceScheduling = "WeightedRoundRobinScheduling";
/// <summary>
/// 負(fù)載均衡調(diào)度算法,默認(rèn)為權(quán)重輪詢調(diào)度算法 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; }
}
}


通過這兩個(gè)配置文件,就可以實(shí)現(xiàn)對(duì)數(shù)據(jù)訪問層負(fù)載均衡的靈活配置了,不過上面的DbSnapAppConfig還有一個(gè)非常重要的
屬性沒有介紹清楚,就是‘LoadBalanceScheduling',其接口聲明如下:
代碼

?

復(fù)制代碼 代碼如下:

?


/// <summary>
/// 負(fù)載均衡調(diào)度接口
/// </summary>
public interface ILoadBalanceScheduling
{
/// <summary>
/// 獲取應(yīng)用當(dāng)前負(fù)載均衡調(diào)度算法下的快照鏈接信息
/// </summary>
/// <returns></returns>
DbSnapInfo GetConnectDbSnap();
}


它就是負(fù)載均衡算法的實(shí)現(xiàn)接口,為了便于說明在Discuz.EntLib中內(nèi)置的兩個(gè)負(fù)載均衡算法的實(shí)現(xiàn)情況,請(qǐng)先看下圖:

內(nèi)置的兩個(gè)負(fù)載均衡算法,一個(gè)是RoundRobinScheduling,即輪叫調(diào)度(Round Robin Scheduling)算法,它的實(shí)現(xiàn)比較簡(jiǎn)單,就是對(duì)從數(shù)據(jù)庫鏈接列表的依次遍歷,如下:
代碼

?

復(fù)制代碼 代碼如下:

?


/// <summary>
/// 輪叫調(diào)度(Round Robin Scheduling)算法
/// </summary>
public class RoundRobinScheduling : ILoadBalanceScheduling
{
private static object lockHelper = new object();
/// <summary>
/// 當(dāng)前的快照索引和權(quán)重信息
/// </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++];
}
}
}


而另一種負(fù)載均衡算法就相對(duì)負(fù)載了,不過它也更符合實(shí)際的應(yīng)用場(chǎng)景,它使用了權(quán)重的方法來讓性能優(yōu)良的機(jī)器分到
更多的任務(wù)來均衡整個(gè)方案的性能,即權(quán)重輪詢調(diào)度算法,實(shí)現(xiàn)代碼如下:
代碼

?

復(fù)制代碼 代碼如下:

?


/// <summary>
/// 權(quán)重輪詢調(diào)度算法
/// 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>
/// 快照的權(quán)重列表
/// </summary>
static List<int> snapWeightList = new List<int>();
/// <summary>
/// 當(dāng)前的快照索引和權(quán)重信息
/// </summary>
static int curentSnapIndex, currentWeight;
/// <summary>
/// 快照權(quán)重列表中最大的權(quán)重值和最大公約數(shù)
/// </summary>
static int maxWeight, gcd;
static WeightedRoundRobinScheduling()
{
curentSnapIndex = -1;
currentWeight = 0;
snapWeightList = GetSnapWeightList();
maxWeight = GetMaxWeight(snapWeightList);
gcd = GCD(snapWeightList);
}
/// <summary>
/// 獲取應(yīng)用當(dāng)前負(fù)載均衡調(diào)度算法下的快照鏈接信息
/// </summary>
/// <returns></returns>
public DbSnapInfo GetConnectDbSnap()
{
lock (lockHelper)
{
DbSnapInfo current = RoundRobinScheduling();
if (current != null)
return current;
else
return DbSnapConfigs.GetEnableSnapList()[0];
}
}
/// <summary>
/// 獲取快照權(quán)重的列表
/// </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>
/// 權(quán)重輪詢調(diào)度算法
/// </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>
/// 獲取最大權(quán)重
/// </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>
/// 獲取權(quán)重的最大公約數(shù)
/// </summary>
/// <returns></returns>
static int GCD(List<int> snapWeightList)
{
// 排序,得到數(shù)字中最小的一個(gè)
snapWeightList.Sort(new WeightCompare());
int minNum = snapWeightList[0];
// 最大公約數(shù)肯定大于等于1,且小于等于最小的那個(gè)數(shù)。
// 依次整除,如果余數(shù)全部為0說明是一個(gè)約數(shù),直到打出最大的那個(gè)約數(shù)
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>
/// 實(shí)現(xiàn)IComparer接口,用于對(duì)數(shù)字列表進(jìn)行排序
/// </summary>
private class WeightCompare : System.Collections.Generic.IComparer<int>
{
public int Compare(int weightA, int weightB)
{
return weightA - weightB;
}
}
}


到這里,主要的功能代碼就介紹的差不多了,我們可以通過對(duì)dbsnap.config的相應(yīng)節(jié)點(diǎn)配置,來靈活定制我們的負(fù)載均衡方案。同時(shí),對(duì)一般開發(fā)者而言,這種架構(gòu)是透明的,大家可以完全在不了解它的情況下開發(fā)自己的數(shù)據(jù)訪問功能,并通過相應(yīng)開關(guān)來讓自己的代碼支持均衡負(fù)載。
當(dāng)然這個(gè)方案還有一些沒考慮到的問題比如:
1.對(duì)‘主從數(shù)據(jù)庫的健康度檢查',即如果主或從數(shù)據(jù)庫出現(xiàn)故障的時(shí)候該如何處理,當(dāng)然在sqlserver中還提供了鏡像功能來解決類似問題,所以它也可做為一個(gè)備選方案。
2.當(dāng)主數(shù)據(jù)庫被發(fā)布出去后,主數(shù)據(jù)庫的表和存儲(chǔ)過程就會(huì)被‘鎖定',其不允許被再次修改了,所以還要繼續(xù)研究如何解決這一問題。

上述是錯(cuò)新技術(shù)頻道小編為大家?guī)淼脑斀釪iscuz!NT數(shù)據(jù)庫讀寫分離方案,我們可以在實(shí)際操作過程中按上述介紹進(jìn)行操作,如有任何疑問,歡迎在下方進(jìn)行留言,我們將第一時(shí)間為大家解決。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
久久国内精品视频| 亚洲精品之草原avav久久| 久久国产乱子伦免费精品| 中文字幕国产精品一区二区| 免费a级黄色片| 日本不卡免费高清视频| 欧美一区二区三区思思人| 中文字幕第一页在线视频| 一级片免费在线观看视频| 一区二区冒白浆视频| 国产极品美女到高潮| 99一区二区| 亚洲伦理一区二区| 在线观看中文字幕| 成人在线播放| 黄色日本网站| 国产精品一区二区三区免费观看| 一本色道久久99精品综合| 精品72久久久久中文字幕| 爱高潮www亚洲精品| 欧美精品videosex极品1| 国产一区二区视频免费观看| 欧美酷刑日本凌虐凌虐| 欧美大片在线播放| 爱福利视频一区二区| 成人短视频软件网站大全app| 视频91a欧美| 麻豆av一区二区三区久久| 日韩av在线网页| 大色综合视频网站在线播放| 五月激情六月婷婷| 最新中文字幕2018| 欧美国产日韩电影| 我的公把我弄高潮了视频| 国内精品国产三级国产aⅴ久| 91色|porny| 国产精品久久波多野结衣| 色婷婷一区二区三区av免费看| 国产精品久久三区| 国产亚洲精品久久久网站好莱| 亚洲精品一区二区在线观看| 乱人伦中文视频在线| 国产一区999| 人妻少妇精品视频一区二区三区| 黑人操亚洲人| av亚洲精华国产精华精华| 国产一级做a爱免费视频| 国产视频你懂的| 91在线直播亚洲| 国产一区二区三区四区五区3d| 亚洲福利一区二区三区| 欧美亚洲在线观看| 日韩精品视频一区二区在线观看| 一区二区在线电影| 成人xxxxx色| 精品国产1区2区3区| 欧美日韩精品免费| 久久激情免费视频| 亚洲成人av一区二区| 日韩av一区在线| www国产黄色| 美女露胸一区二区三区| 欧美视频精品全部免费观看| www..com日韩| 国产丝袜自拍| 久久久久亚洲av成人毛片韩| 久久久久久久久久伊人| 91香蕉视频污| 欧美激情1区| 中文在线免费视频| 成人动漫一区二区三区| 亚洲电影成人成人影院| 男女猛烈无遮挡午夜视频| 美女尤物国产一区| 99久久精品国产色欲| 天堂中文а√在线| 国产精品人人妻人人爽| 亚洲欧美在线第一页| 久久精品一二区| 真人抽搐一进一出视频| 国产综合成人久久大片91| 少妇高潮一69aⅹ| 亚洲精品综合久久| 日韩少妇内射免费播放| 女囚岛在线观看| 国产香蕉一区二区三区| 久久久一区二区三区捆绑**| 无罩大乳的熟妇正在播放| 怡春院在线视频| 国产精品无码一区二区三区免费| 麻豆精品视频在线观看视频| 99久热re在线精品视频| 中文字幕一区二区免费| 91天堂素人约啪| 好吊成人免视频| 三妻四妾完整版在线观看电视剧| 虎白女粉嫩尤物福利视频| 精品中文字幕不卡在线视频| 综合激情婷婷| av综合电影网站| 欧美人动性xxxxz0oz| 国产一区二区日韩| 国产男女无套在线播放| 免费av网站在线| 国产成人无码一区二区在线播放| 日本一区二区成人在线| 国产精品毛片久久久久久久久久99999999| 欧美午夜电影在线播放| 久久综合给合久久狠狠狠97色69| 欧美三级三级三级| 一个人看的视频www| 国产精品69av| 一本久道中文字幕精品亚洲嫩| 国产青草视频在线观看视频| 一区二区国产精品| 精品视频在线免费观看| 国产精品手机在线播放| 不卡的av电影在线观看| 天干夜夜爽爽日日日日| www.久久久久久.com| 在线观看欧美一区二区| 欧美大尺度做爰床戏| 国产一区二区三区福利| 国产av天堂无码一区二区三区| 国产精品视频999| 女人天堂在线| 日本午夜精品一区二区三区电影| 国产人妻精品一区二区三区| 在线视频亚洲色图| 99久久久无码国产精品不卡| 天天看天天色| 免费在线播放第一区高清av| 麻豆亚洲av成人无码久久精品| 夜夜夜久久久| 婷婷综合在线| 91精品国产综合久久香蕉最新版| 天堂成人免费av电影一区| 久久久久久免费观看| 久久综合九色综合97_久久久| 无码人妻精品一区二区三区不卡| japansex久久高清精品| 日本中文字幕在线观看| 亚洲一区二区在线免费观看视频| 日日噜噜夜夜狠狠视频欧美人| 亚洲成人亚洲激情| 亚洲成人网在线播放| 国产成人香蕉在线视频fuz| 91成品人影院| 韩国成人二区| 亚洲精品综合在线观看| 精品在线观看一区二区| 91一区二区三区四区| 亚洲午夜精品久久久久久高潮| 美洲精品一卡2卡三卡4卡四卡| 亚洲日本中文| 午夜视频一区二区| 亚洲美女免费精品视频在线观看| 国内精品嫩模av私拍在线观看| 国产人妻人伦精品| www.久久草.com| 天天影视色香欲综合网天天录日日录| 小草av在线播放| 国产精品久久久久久久久久三级| 美丽的姑娘在线观看免费动漫| 一区二区乱子伦在线播放| 中文字幕第31页| 男捅女免费视频| 国产精品视频一| 国产激情在线观看| 免费网站看黄yyy222| 欧美黄色一区二区三区| 国产情侣av自拍| 91超碰成人| 欧美日韩国产综合视频在线| 国产河南妇女毛片精品久久久| 国产乱子夫妻xx黑人xyx真爽| 另类小说综合网| 日韩免费av一区二区| 99久久精品久久亚洲精品| 日本欧美在线看| 亚洲乱码国产乱码精品精98午夜| www.色呦呦| 国产噜噜噜噜噜久久久久久久久| av高清在线观看| 午夜精品三级视频福利| 亚洲一级影院| 午夜影院免费视频| 毛片av在线播放| 天天骑夜夜操| 欧美极品少妇xxxxⅹ免费视频| 99re6热在线精品视频| 亚洲人妖在线| 国产精品九九九九九| 久久久精品少妇| 国产午夜免费视频| 久久久资源网| 国产一二三区在线播放| 91九色在线视频| 91视频.com| www.xxx麻豆| 亚洲黄色精品| 九九热免费精品视频| 国产精品免费久久久久久| 超碰免费在线| av小次郎在线| 精品自拍一区| 天天综合网入口| 亚洲日韩中文字幕一区| 亚洲啪啪aⅴ一区二区三区9色| 欧美日韩性视频| 亚洲天堂在线视频观看| 国产av天堂无码一区二区三区| 欧美专区在线| 亚洲1区2区3区视频| 亚洲午夜精品一区二区| 一二三区不卡| 亚洲欧美成人在线| 欧美一级大片在线免费观看| 欧美亚洲激情视频| 国产伊人网av.| 久久精品无码一区二区三区| 调教+趴+乳夹+国产+精品| 国产深夜男女无套内射| 国产99久久久| 永久免费看片视频教学| 亚洲乱码国产乱码精品精98午夜| 中文在线字幕在线观看| 欧美久久精品一级黑人c片| 精品少妇一区二区三区| 成年人免费看的视频| 欧美日韩中文在线视频| 视频精品导航| 国产成人一区二区三区免费看| 亚洲精品乱码久久久久久蜜桃图片| 在线播放日本| 欧美啪啪网站| 久久爱com| 水蜜桃精品av一区二区| 永久免费看片在线播放| 99国产精品久久久| 亚洲色成人一区二区三区小说| 中文字幕有码无码人妻av蜜桃| 永久免费不卡在线观看黄网站| 精品久久久中文字幕人妻| 国产一区玩具在线观看| 99久久免费精品国产免费| 日韩视频在线播放| 五月天国产视频| 国产成人精品视频免费看| 久久综合色婷婷| 亚洲永久激情精品| 高清精品xnxxcom| 欧美精品aaaa| 国产精品成人在线| 欧美无乱码久久久免费午夜一区| 亚洲成人精品一区二区| 中文字幕第28页| 国产成人亚洲精品播放器下载| 91九色视频蝌蚪| 蜜桃欧美视频| 国产精品1区2区3区4区| 97视频在线观看亚洲| 国产日韩亚洲欧美精品| 香蕉精品999视频一区二区| 日韩在线视频免费观看| 国产午夜精品一区二区三区四区| 亚洲在线免费播放| 色综合久久久网| 午夜视频你懂的| 日本人视频jizz页码69| 欧美一区二区三区网站| 国产激情久久久| 天天色天天射天天干| 一区二区电影在线观看| 国产91色综合久久免费分享| 亚洲国产裸拍裸体视频在线观看乱了| eeuss网址直达入口| 国精产品一区一区三区四川| 精品国产乱码久久久久久果冻传媒| 黄色免费网站在线观看| 啦啦啦啦免费高清视频在线观看1| 91久久国产综合久久91| www.黄在线| 日本韩国欧美中文字幕| 欧美国产专区| 国产精品美女久久久久久久| 国产美女视频黄a视频免费| 成人在线免费观看av| 国产69精品久久久久孕妇| 欧美黄色免费看| 亚洲人成网站色ww在线| 国产精品三级av在线播放| 91九色porny视频| 黄色精品一二区| 国产精品视频播放| 伦理欧美一区| 欧美美女色图| 欧美亚洲国产精品| 91传媒久久久| www精品国产| 夜夜狠狠擅视频| 99精品视频在线播放观看| 亚洲国产剧情在线观看| 7777精品伊人久久久大香线蕉超级流畅| 2020国产在线| 日韩最新在线| 九九热免费精品视频| 日本黄大片在线观看| 国产在线视频欧美一区| 伊人亚洲视频| 日韩黄色三级视频| 麻豆精品视频在线观看免费| 在线观看免费毛片| 亚洲精品日韩欧美| 日本精品一区二区三区在线| 日韩中文字幕一区二区三区| 免费看av毛片| 亚洲电影免费观看高清| 91老师片黄在线观看| 嫩草影院一区二区三区| 韩国成人在线| 91精品啪在线观看国产手机| 亚洲va韩国va欧美va| a中文字幕www| 黄色综合网站| 一二三中文字幕在线| 欧美成人在线网站| 成年女人免费v片|