中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Discuz!NT千萬級數(shù)據(jù)量上的兩駕馬車 TokyoCabinet,MongoDB

1970-01-01    來源:

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用
特別是像主題表(topic),用戶表(user)等,因為對于一個流量和發(fā)帖量都很大的論壇而言,在運行幾年之后,這兩個表的數(shù)據(jù)量可能會破千萬(注:因為帖子表采用分表機制,所以這里暫未涉及,但出于性能考慮,也提供了本文中類似的解決方案)。當時考慮的架構(gòu)設(shè)計中有兩種思路來解決這種問題:
???? ?一種是采用類似MYSPACE的方式,即按一定記錄KEY值(比如用戶表的UID)來對大數(shù)據(jù)表中的記錄進行分割,比如前200萬用戶(即:UID????? 第二種就是使用能處理大數(shù)據(jù)量表格的第三方工具,比如本文所說的TokyoTyrant,Mongodb等,這類NOSQL軟件從一問世就是面向海量數(shù)據(jù)存儲訪問的,而且這類軟件往往都是開源的,另外通過與打算布署企業(yè)版的用戶接觸,發(fā)現(xiàn)雖然他們的服務(wù)器配置很高,但數(shù)量即不多,所以就要考慮如何最大限度的復用已有的機器資源,而這類NOSQL軟件往往都是‘性價比’很高的,即用不多的資源(內(nèi)存,CPU等)就能達到意想不到的效果。當然我目前對其還是很謹慎的使用,即不會馬上把它當做主力數(shù)據(jù)存儲工具,而是輔助MSSQL數(shù)據(jù)庫工具,所以大家在看完本文后會發(fā)現(xiàn),這兩個工具在企業(yè)版中的角色頂多就是一個高級的MEMCACEHD。不過我的想法很簡單,就是任何工具和技術(shù),如果不是很了解它或者它很新,那么必定要有一個“考核期”,如果在‘任間’內(nèi)它通過考核,才委以重任,如未通過考核,也不會讓系統(tǒng)平臺承擔過多的技術(shù)層面上的‘風險’。

???? 綜上所述,最終我把方向放到了TokyoTyrant,Mongodb上,之所以選擇了這兩個工具,主要基于下面因素:
???
??? 1.海量數(shù)據(jù)的解決方案應(yīng)該可以跑在LINUX和WINDOW平臺上。當然有人會說Mongodb完全可以跑這兩個平臺,那還為什么要引入TokyoTyrant呢?其實這里有一些產(chǎn)品的特殊情況要考慮,比如我們的用戶中絕大多數(shù)對于數(shù)據(jù)的讀寫比在 4:1,即5條SQL訪問中有4條是SELECT操作,1條是CUD操作,這就造成了讀寫比例的失衡。雖然Mongodb在讀寫性能上非常優(yōu)異和穩(wěn)定,但在并發(fā)讀上相對于TokyoTyrant+cabinet還是有一些差距(注:更多內(nèi)容參見該鏈接,然后這只限于在我們產(chǎn)品中壓力測試環(huán)境下的結(jié)果,不具備普遍性,所以希望大家具體問題具體分析)

??? 2.考慮到有些用戶公司是有相應(yīng)技術(shù)儲備的,兩種方案也便于用戶公司進行的技術(shù)選型(當然因為采用接口方式,用戶完全可以引入其它第三方的NOSQL工具來實現(xiàn))。

??? 好了,說了這么多,開始今天的正文吧。
???
??? 前面說過,該方案使用了接口方式,這里就先看一下相應(yīng)的接口聲明:
????
???????
???

???? 可以看到,目前在企業(yè)版中,對主題表(dnt_topics),用戶表(dnt_users),在線表(dnt_online)以及帖子表(dnt_posts)進行了NOSQL數(shù)據(jù)支持,所以定義了如下的幾個接口(圖中):

復制代碼
代碼如下:

public interface ICacheTopics
public interface ICacheUsers
public interface ICacheOnlineUser
public interface ICachePosts

因為目前只是把這類NOSQL工具當作高級的‘緩存’來用,所以接口命名上都帶著‘Cache’的字樣。
然后我使用了一個叫做DBCacheService的類,提供獲取這幾個接口實例的方法,比如ICacheTopics的實例代碼如下:

復制代碼
代碼如下:

///
/// 該類用于獲取NoSqlDb聲明的緩存服務(wù)
///

public class DBCacheService
{
static ICacheTopics iCacheTopics = null;
public static ICacheTopics GetTopicsService()
{
if (iCacheTopics == null)
{
lock (lockHelper)
{
if (iCacheTopics == null)
{
try
{
if (EntLibConfigs.GetConfig().Cachetopics.Enable)
{
iCacheTopics = (ICacheTopics)Activator.CreateInstance(Type.GetType(
EntLibConfigs.GetConfig().Cachetopics.CacheType == 2 ?
"Discuz.EntLib.TokyoTyrant.Data.Topics, Discuz.EntLib.TokyoTyrant" :
"Discuz.EntLib.MongoDB.Data.Topics, Discuz.EntLib.MongoDB", false, true));
}
}
catch
{
throw new Exception("請檢查" + (EntLibConfigs.GetConfig().Cachetopics.CacheType == 2 ?
"Discuz.EntLib.TokyoTyrant.dll" :
"Discuz.EntLib.MongoDB.dll") + "文件是否被放置到了bin目錄下!");
}
}
}
}
return iCacheTopics;
}
}

從上面代碼可以看出,使用反射方式獲取相應(yīng)DLL文件(分別是Discuz.EntLib.TokyoTyrant.dll和Discuz.EntLib.MongoDB.dll)中的 類信息并初始化該實例。當然,這里還定義了一個配置文件,也就是EntLibConfigs.GetConfig()這個方法所獲取的配置文件信息, 相應(yīng) 配置文件內(nèi)容包括:

復制代碼
代碼如下:

///
/// 提供數(shù)據(jù)庫緩存服務(wù),將在線表主題表這類大表放入緩存之中
///

public class DBCache
{
///
/// 是否有效
///

public bool Enable = false;
///
/// 服務(wù)地址
///

public string Host = "";
///
/// 服務(wù)地址
///

public int Port = 0;
///
/// 鏈接池名稱
///

public string PoolName = "dnt";
///
/// 初始化鏈接數(shù)
///

public int IntConnections = 4;
///
/// 最少鏈接數(shù)
///

public int MinConnections = 4;
///
/// 最大連接數(shù)
///

public int MaxConnections = 4;
///
/// avaiable pool池中線程的最大空閑時間
///

public int MaxIdle = 30000;
///
/// busy pool中線程的最大忙碌時間
///

public int MaxBusy = 50000;
///
/// 維護線程休息時間
///

public int MaintenanceSleep = 300000;
///
/// TcpClient讀操作超時時間
///

public int TcpClientTimeout = 3000;
///
/// TcpClient鏈接超時時間
///

public int TcpClientConnectTimeout = 30000;
///
/// 緩存類型1為mongodb,2為tokyotyrnat
///

public int CacheType = 1;
}

上面是配置文件中‘可復用信息’的基類,下面是具體的配置類實例聲明:

復制代碼
代碼如下:

///
/// 企業(yè)版配置信息類文件
///

public class EntLibConfigInfo : IConfigInfo
{
///
/// 提供數(shù)據(jù)庫緩存服務(wù),將在線表(dnt_online)放入CACHE中
///

public DBCache Cacheonlineuser = new DBCache();
///
/// 提供數(shù)據(jù)庫緩存服務(wù),將用戶表(dnt_users)放入CACHE中
///

public DBCache Cacheusers = new DBCache();
///
/// 提供數(shù)據(jù)庫緩存服務(wù),將主題表(dnt_topic)放入CACHE中
///

public DBCache Cachetopics = new DBCache();
///
/// 提供數(shù)據(jù)庫緩存服務(wù),將主題表(dnt_topic)放入CACHE中
///

public DBCache Cacheposts = new DBCache();
}

通過該類,就可以用如下配置文件內(nèi)容初始化相應(yīng)的實例了:

復制代碼
代碼如下:




10.0.4.119
27017
false
dnt_online
4
4
4
30000
50000
300000
3000
30000
1



10.0.4.66
112121
false
dnt_users
4
4
4
30000
50000
300000
3000
30000
1



10.0.4.5
27017
false
dnt_topics
25
25
25
30000
5000
300000
300000
30000
1



10.0.4.5
27017
false
dnt_posts
25
25
25
30000
5000
300000
300000
30000
1



當然,因為使用的開源的客戶源工具在配置上有一定的的差異性(比如命名上等),所以這里有些參數(shù)可以對TTCACHE有效,卻對MONGODB無效,?不過這并不影響對這兩種工具的使用。
?
????? 這里要說明的是,對于TokyoTrant而言,這里使用的是我開發(fā)的這款客戶端軟件:

??????http://www.cnblogs.com/daizhj/archive/2010/06/08/tokyotyrantclient.html


????? Mongodb使用的是:http://github.com/samus/mongodb-csharp
????
????? 這里還有個小插曲,之前園子里有朋友介紹了這個客戶端NoRM ,不過在我寫了一個LINQ示例并進行壓力測試后,發(fā)現(xiàn)速度不快,比samus的那個客戶端慢了不少,在苦找原因無果的情況下,最終選擇了samus,不過在samus中目前也支持LINQ的寫法(也算是擴展和嘗試吧),如下面的寫法(更多具體示例還是參見其官方源碼包中的相應(yīng)內(nèi)容):?

復制代碼
代碼如下:

Mongo db = new Mongo("Servers=10.0.4.5:27017;ConnectTimeout=30000;ConnectionLifetime=300000;MinimumPoolSize=64;MaximumPoolSize=256;Pooled=true");
db.Connect();
var topicColl = db.GetDatabase("dnt_mongodb").GetCollection("topics");
var topicInfoList = topicColl.Linq().Where(t => t.Fid == 2 && t.Displayorder == 0).Skip(skip).OrderByDescending(t=>t.Lastpostid).Take(16).ToList();
Discuz.Common.Generic.List topicList = new List();
foreach (var topic in topicInfoList)
{
topicList.Add(LoadTopicInfo(topic));
}
db.Disconnect();
return topicList;

不過在使用上述代碼進行1500萬主題分頁時,發(fā)現(xiàn)LR的測試周期延長(前者(document方式)從2:10秒延長到后者(linq)2:30秒)和吞吐量降低。
所以這里還是最終延用了samus的document訪問方式,參照上面的LINQ寫法,下面是document寫法,形如:

復制代碼
代碼如下:

public Discuz.Common.Generic.List GetTopicList(int fid, int pageSize, int pageIndex, int startNumber)
{
int skip = 0;
if (pageIndex pageSize = pageSize - startNumber;
else
skip = (pageIndex - 1) * pageSize - startNumber;
Discuz.Common.Generic.List topicInfoList = new Common.Generic.List();
System.Collections.Generic.List docList = MongoDbHelper.Find(mongoDB, "topics",
new Document().Add("fid", fid).Add("displayorder", 0), "lastpostid", IndexOrder.Descending, pageSize, skip);
return docList;
}

如果在你的項目中非要使用LINQ方式的話,那在這里再要介紹的一個samus的屬性綁定功能,這個功能對于那些數(shù)據(jù)庫字段與代碼中的屬性存在 “大小寫”差異的情況下,非常有用,即對相應(yīng)實體類進行‘別名’的綁定,比如對于主題表(需引入MongoDB.Attributes名空間):

復制代碼
代碼如下:

///
/// 主題信息描述類
///

public class TopicInfo : Discuz.Entity.TopicInfo
{
[MongoAlias("attention")]
public new int Attention { get; set; }
///
///主題tid
///

[MongoAlias("tid")]
public new int Tid { get; set; }
///
/// 板塊名稱
///

[MongoAlias("forumname")]
public new string Forumname { get; set; }
///
///版塊fid
///

[MongoAlias("fid")]
public new int Fid { get; set; }
///
///主題圖標id
///

[MongoAlias("iconid")]
public new int Iconid { get; set; }
......

上面的MongoAlias屬性就是屬性別名,它就是MONGODB中所存儲的數(shù)據(jù)字段名稱。

介紹到這里,再回到正文。
因為這兩個工具都是在數(shù)據(jù)庫層面進行緩存的,所以它對于原有的DISCUZ!NT中的緩存系統(tǒng)而言,與數(shù)據(jù)庫帖的更近,所以對原有的業(yè)務(wù)邏輯改造,
就停留在了數(shù)據(jù)訪問層"DISCUZ.DATA.dll"中了,其實到這里,就看出了當初為什么要分層,以及分層帶來的好處了。
比如在Discuz.Data.Topics這個類中添加了這兩個靜態(tài)變量:

復制代碼
代碼如下:

///
/// 是否啟用TokyoTyrantCache緩存用戶表
///

public static bool appDBCache = (EntLibConfigs.GetConfig() != null && EntLibConfigs.GetConfig().Cachetopics.Enable);
public static ICacheTopics ITopicService = appDBCache ? DBCacheService.GetTopicsService() : null;

前者用戶判斷是否啟用主題緩存,后者則獲取相應(yīng)的緩存服務(wù)實例(前面配置文件中已做相應(yīng)說明)。
這樣,在已有的數(shù)據(jù)訪問代碼中加入相應(yīng)的緩存邏輯,比如獲取主題信息:

復制代碼
代碼如下:

///
/// 獲得主題信息
///

/// 要獲得的主題ID
/// 版塊ID
/// 模式選擇, 0=當前主題, 1=上一主題, 2=下一主題
public static TopicInfo GetTopicInfo(int tid, int fid, byte mode)
{
TopicInfo topicInfo = null;
if (appDBCache)//新增代碼
topicInfo = ITopicService.GetTopicInfo(tid, fid, mode);
if(topicInfo == null)
{
//原代碼
IDataReader reader = DatabaseProvider.GetInstance().GetTopicInfo(tid, fid, mode);
if (reader.Read())
topicInfo = LoadSingleTopicInfo(reader);
reader.Close();
if (appDBCache && topicInfo != null)
ITopicService.CreateTopic(topicInfo);
}
return topicInfo;
}

當然,因為使用了緩存方式,所以就牽扯到緩存中的數(shù)據(jù)與數(shù)據(jù)庫中數(shù)據(jù)的一致性問題,所以對于主題的CUD操作,也要對應(yīng)有相應(yīng)的對緩存的操作,這基本上就是一個工作量的問題了。因為無論是TTCACHED,還是MONGODB,都支持更新操作。
比如同樣是更新主題附件類型的操作,下面是TTCACHED的寫法:

復制代碼
代碼如下:

///
/// 更新主題附件類型
///

/// 主題Id
/// 附件類型,1普通附件,2為圖片附件
///
public int UpdateTopicAttachmentType(int tid, int attType)
{
var qrecords = TokyoTyrantService.QueryRecords(pool, new Query().NumberEquals("tid", tid));
foreach (string key in qrecords.Keys)
{
var column = qrecords[key];
column["attachment"] = attType.ToString();
TokyoTyrantService.PutColumns(pool, column["tid"], column, true);
break;
}
return 1;
}

下面是MongoDB的寫法

復制代碼
代碼如下:

///
/// 更新主題附件類型
///

/// 主題Id
/// 附件類型,1普通附件,2為圖片附件
///
public int UpdateTopicAttachmentType(int tid, int attType)
{
MongoDbHelper.Update(mongoDB, "topics",
new Document() { { "$set", new Document() { { "attachment", attType } } } },
new Document().Add("_id", tid));
return 1;
}

通過對比可以看出,MONGODB可以對某一字段進行操作,而TTCACEHD則只能通過查詢先獲取整條記錄,然后修改某一‘字段’,之后再整條提交更新,所以單從這一角度講,MONGDOB要比TTCACHED更新性能要高許多(之后的測試結(jié)果也說明了這一點)。
??
??? ? 正如之前所說的那樣,如用戶對于這兩個接口實現(xiàn)方案均不滿意,那么他可以使用其它類型的NOSQL數(shù)據(jù)庫,只要實現(xiàn)了相應(yīng)的接口:
???? public interface ICacheTopics
???? public interface ICacheUsers
???? public interface ICacheOnlineUser
???? public interface ICachePosts?????
???????并在配置文件中進行相應(yīng)的配置就可以了,當然本文中代碼因為時間問題還是有待考量的,但主要的架構(gòu)設(shè)計思想基本被確定下來了。
?
?
?? ?? 當然對于原有的數(shù)據(jù)庫中的記錄,如果要使用本方案,我提供了轉(zhuǎn)換工具,用于把數(shù)據(jù)轉(zhuǎn)到TTCACHED或MONGODB中的任一服務(wù)端上。如下:
?
???? TTCACEHD:
????
????
???? MongoDB(目前比TTACEHD多了帖子分表轉(zhuǎn)換功能):
???
?
?
??????最后在壓力測試過程中,還出現(xiàn)了一些小問題,好在對著官方文檔,逐步優(yōu)化解決了,這里要特別說一下MONGDOB,其文件的詳細程度要好于TTCACHED,基本上主要的功能都有詳細的介紹說明頁面,呵呵。當然TTCACHED的誕生時間要比MONGODB早,所以在生產(chǎn)環(huán)境下的成功案例也相對多一些。
????
????
???? 下面列了一下使用過程中的小問題,僅作記錄:????? ?????
?????
????? TokyoTyrant的使用問題:盡量不要在查詢的列表中使用排序操作,因為它的排序效率還不如數(shù)據(jù)庫高。盡量使用索引進行查詢
?????????????????? 鍵值操作。2000w記錄以下查詢效率很高,但更高的數(shù)據(jù)量上目前沒做過壓力測試(包括CRUD操作)
?????
????? Mongodb:盡量使用_ID做為查詢鍵值操作,包括排序等,對索引進行優(yōu)化(單列或多列進行索引)。
原文鏈接:http://www.cnblogs.com/daizhj/archive/2010/07/20/1781140.html

標簽: isp linux 處理大數(shù)據(jù) 大數(shù)據(jù) 代碼 服務(wù)器 企業(yè) 數(shù)據(jù)庫 問題 選擇 用戶

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:Discuz論壇上傳圖片附件成功貼子里看不到圖片

下一篇:解析Discuz!7.0快速定位功能