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

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

1970-01-01    來(lái)源:

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

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

??? 2.考慮到有些用戶公司是有相應(yīng)技術(shù)儲(chǔ)備的,兩種方案也便于用戶公司進(jìn)行的技術(shù)選型(當(dāng)然因?yàn)椴捎媒涌诜绞,用戶完全可以引入其它第三方的NOSQL工具來(lái)實(shí)現(xiàn))。

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

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

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

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

因?yàn)槟壳爸皇前堰@類NOSQL工具當(dāng)作高級(jí)的‘緩存’來(lái)用,所以接口命名上都帶著‘Cache’的字樣。
然后我使用了一個(gè)叫做DBCacheService的類,提供獲取這幾個(gè)接口實(shí)例的方法,比如ICacheTopics的實(shí)例代碼如下:

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

///
/// 該類用于獲取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("請(qǐng)檢查" + (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)中的 類信息并初始化該實(shí)例。當(dāng)然,這里還定義了一個(gè)配置文件,也就是EntLibConfigs.GetConfig()這個(gè)方法所獲取的配置文件信息, 相應(yīng) 配置文件內(nèi)容包括:

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

///
/// 提供數(shù)據(jù)庫(kù)緩存服務(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池中線程的最大空閑時(shí)間
///

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

public int MaxBusy = 50000;
///
/// 維護(hù)線程休息時(shí)間
///

public int MaintenanceSleep = 300000;
///
/// TcpClient讀操作超時(shí)時(shí)間
///

public int TcpClientTimeout = 3000;
///
/// TcpClient鏈接超時(shí)時(shí)間
///

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

public int CacheType = 1;
}

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

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

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

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

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

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

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

public DBCache Cacheposts = new DBCache();
}

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

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




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



當(dāng)然,因?yàn)槭褂玫拈_源的客戶源工具在配置上有一定的的差異性(比如命名上等),所以這里有些參數(shù)可以對(duì)TTCACHE有效,卻對(duì)MONGODB無(wú)效,?不過(guò)這并不影響對(duì)這兩種工具的使用。
?
????? 這里要說(shuō)明的是,對(duì)于TokyoTrant而言,這里使用的是我開發(fā)的這款客戶端軟件:

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


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

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

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;

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

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

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;
}

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

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

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

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; }
///
///主題圖標(biāo)id
///

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

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

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

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

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

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

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

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

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

/// 要獲得的主題ID
/// 版塊ID
/// 模式選擇, 0=當(dāng)前主題, 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;
}

當(dāng)然,因?yàn)槭褂昧司彺娣绞,所以就牽扯到緩存中的?shù)據(jù)與數(shù)據(jù)庫(kù)中數(shù)據(jù)的一致性問(wèn)題,所以對(duì)于主題的CUD操作,也要對(duì)應(yīng)有相應(yīng)的對(duì)緩存的操作,這基本上就是一個(gè)工作量的問(wèn)題了。因?yàn)闊o(wú)論是TTCACHED,還是MONGODB,都支持更新操作。
比如同樣是更新主題附件類型的操作,下面是TTCACHED的寫法:

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

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

/// 主題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的寫法

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

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

/// 主題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;
}

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

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

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

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

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