Discuz!NT数据库读写分离方案
??????目前在Discuz!NT這個產品中,數據庫作為數據持久化工具,必定在并發訪問頻繁且負載壓力較大的情況下成?為系統性能的‘瓶頸’。即使使用本地緩存等方式來解決頻繁訪問數據庫的問題,但仍舊會有大量的并發請求要訪問動態數據,雖然 SQL2005及2008以上版本中性能不斷提升,查詢計劃和存儲過程運行得越來越高效,但最終還是?要面臨‘瓶頸’這一問 題。當然這也是許多大型網站不斷研究探索各式各樣的方案來有效降低數據訪問負荷的原?因, 其中的‘讀寫分離’方案就是一種被廣泛采用的方案。
????? Discuz!NT這個產品在其企業版中提供了對‘讀寫分離’機制的支持,使對CPU及內存消耗嚴重的操作(CUD)被?分離到一臺或幾臺性能很高的機器上,而將頻繁讀取的操作(select)放到幾臺配置較低的機器上,然后通過‘事務?發布訂閱機制’,實現了在多個sqlserver數據庫之間快速高效同步數據,從而達到了將‘讀寫請求’按實際負載?情況進行均衡分布的效果。
?
???? ?下面就簡要介紹一下其實現思路。注:有關數據同步的工具已在sqlserver中自帶了,可以參考這篇文章。
?????
??????將相應的數據由Master(主)數據庫中‘發布’出來,然后使用推送的方式(注:事務發布可以指定是‘通過主?數據庫推送’ 還是‘訂閱服務器去獲取’)發送到訂閱它的數據庫中,就實現了數據同步功能。
?
????? 下面就介紹一下如何通過改變既有代碼來實現在‘幾個從數據庫(類似快照)’間進行讀取數據的負載均衡。
?
???? ?原有的代碼中因為使用了分層機制,所以我們只要在‘數據訪問層’動一下心思就可以了。在這里我的一個設?計思路就是不改變已有的數據庫訪問接口(包括參數等)的前提下,實現底層自動將現有的數據訪問操作進行負載?均衡。這樣做的好處不用多說了,同時也讓這個負載均衡功能與數據訪問層相分離,不要耦合的太緊密,同時如果不曉得底層 的實現原理也可以只通過一個開關(后面會介紹),就可以讓自己的sql語句自動實現動態負載均衡。
????
???? ?說到這里,我來對照代碼進一步闡述:
?
???? ?首先就是(Discuz.Data\DbHelper.cs)代碼,主要變動如下(新增方法部分):???
///?獲取使用的數據庫(或快照)鏈接串
///?</summary>
///?<param?name="commandText">存儲過程名或都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;
}
?
?????? 上面的方法將會對傳入的sql語句進行分析,找出其中是CUD操作還是SELECT操作,來區別是讀還是寫操作。而snapLogList列表則是之前所配置的‘事務發布訂閱’模式下的相關‘從數據庫’(Slave Database)鏈接串的列表,例如(dbsnap.config文件的DbSnapInfoList節點):?
?
代碼 <?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>
?
????
????? ?有關相應配置節點和負載均衡算法會在后面提到,這里為了保持文章內容的連續性暫且跳過,下面接著瀏覽一下上面調用的‘UserSnapDatabase’方法:
?
代碼 ///?<summary>///?是否使用快照數據庫
///?</summary>
///?<param?name="commandText">查詢</param>
///?<returns></returns>
private?static?bool?UserSnapDatabase(string?commandText)
{
????//?如果上次刷新cookie間隔小于5分鐘,?則不刷新數據庫最后活動時間
????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;
}
?
????? 該方法的作用很簡單,就是當數據庫有CUD操作時,通過寫cookie的方式向客戶端寫一個鍵值‘JumpAfterWrite’,這個鍵值很重要,就是提供一個標簽(flag)來指示:‘當前用戶執行cud操作時,頁面跳轉到其它頁面而主數據庫還沒來得及將數據推送到從數據庫’這一情況而造成的‘數據不同步’問題。
???? 舉了例子,當在一個版塊中‘發表主題’后系統自動跳轉到‘顯示該主題頁面’時,如果主數據庫中插入了一個新主題而從數據庫沒有被及時更新這一主題信息時,就會報‘主題不存在’這個錯誤。所以這里加了一個設置,就是下面這一行:?
?
????
????? 它所做的就是確保用戶cud操作之后,在規定的時間內還是訪問主數據庫,當時間超過時,才將當前用戶的訪問請求(select)均衡到其它從數據庫中。
????? 當然,在GetRealConnectionString()方法中,還有一行代碼很重要,就是下面這一行:????
????
?
????
??? 它的作用就是加載配置文件信息,其中最主要的就是相應的‘負載均衡算法實例’來獲取相應的從數據庫鏈接串,下面先看一
下‘靜態屬性’GetLoadBalanceScheduling的相關信息:
?
代碼 ///?<summary>///?負載均衡調度接口
///?</summary>
private?static?ILoadBalanceScheduling?m_loadBalanceSche;
///?<summary>
///?初始化負載均衡調度接口實例
///?</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("請檢查config/dbsnap.config中配置是否正確");
????????????}
????????}
????????return?m_loadBalanceSche;
????}
}
?
??? ? 它主要是通過反射的方法將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;
?
?????
???? 上面代碼將當前的負載均衡得到的鏈接串保存到一個snapLogList列表中,該列表聲明如下:?????
????
?
?????
???? ?為什么要提供這個列表并進行記錄?主要是為了考查負載均衡算法的工作情況,因為在數據訪問層獲取相應鏈接串信息并進行記錄很不方便,所以我用這個變量記錄大約400條‘負載均衡’數據鏈接串,以便在相應的Discuz.EntLib.ToolKit工具包中進行觀察,監視其‘工作情況’。這里我們只要知道通過GetRealConnectionString()方法就實現了對sql語句或存儲過程進行分析并進行負載均衡的效果了(注:該操作可能會耗時,所以在DbSnapConfigs中提供了一個開關‘RecordeLog’來進行控制,后面會介紹)。
????
???? 下面再來簡單介紹一下,如何改造DbHelper.cs中原有方法,使其支持負載均衡功能。這里強調一點,就是:
????
???? GetRealConnectionString()方法只是造了一個房子,里面的家具還是要自己搬。
????
???? 而家具就是那些老的方法,比如:
?
代碼 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;
}
?
????
??? ? 上面的 ‘connection.ConnectionString =’之前綁定的ConnectionString這個靜態屬性,而這個屬性鏈接的就是‘主數據庫’,
這里我們只要將GetRealConnectionString(commandText)賦值給它就可以了,還是那句話,在GetRealConnectionString()就實現了
數據庫鏈接串的負載均衡,呵呵。類似上面的變動在DbHelper.cs還有幾處,好在變化不太大,當然更不需要改變原有的數據訪問層
(比如IDataProvider.cs文件)了。
????? 其實本文中介紹的數據庫層負載均衡實現方法在MYSQL中早有相應的插件實現了,參見這篇文章。??????
??
?????
?
?
?????? ?該文章中的LUA腳本實現方式與本文類似,如下:????
????
????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
????.....
?
?
????? 接著,我再介紹一下相應的配置文件和負載均衡算法的實現情況:)
???
???
???? ?配置文件(比如:Discuz.EntLib.ToolKit\config\dbsnap.config):?????
?????
<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):?????
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;?}
????}
}
?
??????
??????
????? ?當然DbSnapAppConfig作為DbSnapInfo列表的容器,其結構如下:????
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中內置的兩個負載均衡算法的實現情況,請先看下圖:????
????
????
????? ?內置的兩個負載均衡算法,一個是RoundRobinScheduling,即輪叫調度(Round Robin Scheduling)算法,它的實現比較簡單,就是對從數據庫鏈接列表的依次遍歷,如下:
///?輪叫調度(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++];
????????}
????}
}
?
???
???
???? 而另一種負載均衡算法就相對負載了,不過它也更符合實際的應用場景,它使用了權重的方法來讓性能優良的機器分到
更多的任務來均衡整個方案的性能,即權重輪詢調度算法,實現代碼如下:
///?權重輪詢調度算法?
///?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.當主數據庫被發布出去后,主數據庫的表和存儲過程就會被‘鎖定’,其不允許被再次修改了,所以還要繼續研究如何解決這一問題。
?
??????原文鏈接:http://www.cnblogs.com/daizhj/archive/2010/06/21/dbsnap_master_slave_database.html ?
????? 作者: daizhj, 代震軍
????? Tags: discuz!nt,dbsnap,讀寫分離
????? 網址: http://daizhj.cnblogs.com/
?
轉載于:https://www.cnblogs.com/daizhj/archive/2010/06/21/dbsnap_master_slave_database.html
總結
以上是生活随笔為你收集整理的Discuz!NT数据库读写分离方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上周热点回顾(6.14-6.20)
- 下一篇: 关于nunit调试VS2010中的4.0