亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 2611 | 回復(fù): 0
打印 上一主題 下一主題

[Cassandra] 如何將 MongoDB MapReduce 速度提升 20 倍 [復(fù)制鏈接]

論壇徽章:
2
2015年辭舊歲徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:55:28
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2013-11-04 09:17 |只看該作者 |倒序?yàn)g覽
分析在MongoDB中正成為越來越重要的話題,因?yàn)樗谠絹碓蕉嗟拇笮晚?xiàng)目中使用。人們厭倦了使用不同的軟件來做分析(包括Hadoop),它們顯然需要傳輸大量開銷的數(shù)據(jù)。

MongoDB提供了兩種內(nèi)置分析數(shù)據(jù)的方法:Map Reduce和Aggregation框架。MR非常靈活,很容易部署。它通過分區(qū)工作良好,并允許大量輸出。MR在MongoDB v2.4中,通過使用JavaScript引擎把Spider Monkey替換成V8,性能提升很多。老板抱怨它太慢了,尤其是和Agg框架(使用C++)相比。讓我們看看能否從中榨出點(diǎn)果汁。


練習(xí)


讓我們插入1千萬條文檔,每個(gè)文檔包含一個(gè)從0到1000000的整數(shù)。這意味著平均有10個(gè)文檔會具有相同的值。
  
> for (var i = 0; i  db.uniques.findOne()
{ "_id" : ObjectId("51d3c386acd412e22c188dec"), "dim0" : 570859 }
> db.uniques.ensureIndex({dim0: 1})
> db.uniques.stats()
{
        "ns" : "test.uniques",
        "count" : 10000000,
        "size" : 360000052,
        "avgObjSize" : 36.0000052,
        "storageSize" : 582864896,
        "numExtents" : 18,
        "nindexes" : 2,
        "lastExtentSize" : 153874432,
        "paddingFactor" : 1,
        "systemFlags" : 1,
        "userFlags" : 0,
        "totalIndexSize" : 576040080,
        "indexSizes" : {
                "_id_" : 324456384,
                "dim0_1" : 251583696
        },
        "ok" : 1
}
            
從這其中,我們想要計(jì)算出現(xiàn)的不同值的個(gè)數(shù)?梢杂孟铝蠱R任務(wù)輕松完成這個(gè)工作:

> db.runCommand(
{ mapreduce: "uniques",
map: function () { emit(this.dim0, 1); },
reduce: function (key, values) { return Array.sum(values); },
out: "mrout" })
{
        "result" : "mrout",
        "timeMillis" : 1161960,
        "counts" : {
                "input" : 10000000,
                "emit" : 10000000,
                "reduce" : 1059138,
                "output" : 999961
        },
        "ok" : 1
}
            
正如你在輸出內(nèi)容中看到的,這耗費(fèi)了大概1200秒(在EC2 M3實(shí)例上進(jìn)行的測試)。有1千萬個(gè)map,1百萬個(gè)reduce,輸出了999961個(gè)文檔。結(jié)果就像下面這樣:

> db.mrout.find()
{ "_id" : 1, "value" : 10 }
{ "_id" : 2, "value" : 5 }
{ "_id" : 3, "value" : 6 }
{ "_id" : 4, "value" : 10 }
{ "_id" : 5, "value" : 9 }
{ "_id" : 6, "value" : 12 }
{ "_id" : 7, "value" : 5 }
{ "_id" : 8, "value" : 16 }
{ "_id" : 9, "value" : 10 }
{ "_id" : 10, "value" : 13 }
...


使用排序


我在上一篇博文中提到了在MR中使用排序多么有益。這個(gè)特性很少被理解。在這個(gè)例子中,處理未排序的輸入意味著MR引擎將得到隨機(jī)順序的值,在RAM中根本無法 reduce。相反,它將不得不把所有文章寫入一個(gè)臨時(shí)收集的磁盤,然后按順序讀取并reduce。讓我們看看使用排序是否有助:
         
> db.runCommand(
{ mapreduce: "uniques",
map: function () { emit(this.dim0, 1); },
reduce: function (key, values) { return Array.sum(values); },
out: "mrout",
sort: {dim0: 1} })
{
        "result" : "mrout",
        "timeMillis" : 192589,
        "counts" : {
                "input" : 10000000,
                "emit" : 10000000,
                "reduce" : 1000372,
                "output" : 999961
        },
        "ok" : 1
}
            
確實(shí)大有助益!我們下降到192秒,已經(jīng)提升了6倍。reduce的數(shù)量基本相同,但現(xiàn)在它們在寫入磁盤前,可以在RAM內(nèi)完成。


使用多線程


MongoDB對單獨(dú)的MR作業(yè)并不使用多線程——它僅僅對多作業(yè)使用多線程。但通過多核CPU,在單個(gè)服務(wù)器使用Hadoop風(fēng)格來并行作業(yè)非常有優(yōu)勢。我們需要做的是把輸入分成幾塊,通過各個(gè)塊來加速一個(gè) MR作業(yè)。也許數(shù)據(jù)集有簡單的方法來分割,但其他使用splitVector命令(不明確)可以使你很快的找到分割點(diǎn):
   
> db.runCommand({splitVector: "test.uniques", keyPattern: {dim0: 1}, maxChunkSizeBytes: 32000000})
{
    "timeMillis" : 6006,
        "splitKeys" : [
                {
                        "dim0" : 18171
                },
                {
                        "dim0" : 36378
                },
                {
                        "dim0" : 54528
                },
                {
                        "dim0" : 72717
                },

                {
                        "dim0" : 963598
                },
                {
                        "dim0" : 981805
                }
        ],
        "ok" : 1
}
            
這個(gè)命令在超過1千萬個(gè)文檔中找到分割點(diǎn)僅僅需要花費(fèi)5秒,很快!那么現(xiàn)在我們僅僅需要一個(gè)方法來創(chuàng)建多個(gè)MR作業(yè)。從一個(gè)應(yīng)用服務(wù)器,使用多線程和為MR命令使用$gt/$It查詢 相當(dāng)簡單。通過shell,你可以使用ScopedThread,使用方法如下:

> var t = new ScopedThread(mapred, 963598, 981805)
> t.start()
> t.join()


現(xiàn)在我們把一些快速運(yùn)行的js代碼放在一起,它們會產(chǎn)生4個(gè)線程(或者更多的線程),執(zhí)行后呈現(xiàn)出下面的結(jié)果:
   
> var res = db.runCommand({splitVector: "test.uniques", keyPattern: {dim0: 1}, maxChunkSizeBytes: 32 *1024 * 1024 })
> var keys = res.splitKeys
> keys.length
39
> var mapred = function(min, max) {
return db.runCommand({ mapreduce: "uniques",
map: function () { emit(this.dim0, 1); },
reduce: function (key, values) { return Array.sum(values); },
out: "mrout" + min,
sort: {dim0: 1},
query: { dim0: { $gte: min, $lt: max } } }) }
> var numThreads = 4
> var inc = Math.floor(keys.length / numThreads) + 1
> threads = []; for (var i = 0; i = keys.length) ? MaxKey : keys[i * inc + inc].dim0 ; print("min:" + min + " max:" + max); var t = new ScopedThread(mapred, min, max); threads.push(t); t.start() }
min:0 max:274736
min:274736 max:524997
min:524997 max:775025
min:775025 max:{ "$maxKey" : 1 }
connecting to: test
connecting to: test
connecting to: test
connecting to: test
> for (var i in threads) { var t = threads; t.join(); printjson(t.returnData()); }
{
        "result" : "mrout0",
        "timeMillis" : 205790,
        "counts" : {
                "input" : 2750002,
                "emit" : 2750002,
                "reduce" : 274828,
                "output" : 274723
        },
        "ok" : 1
}
{
        "result" : "mrout274736",
        "timeMillis" : 189868,
        "counts" : {
                "input" : 2500013,
                "emit" : 2500013,
                "reduce" : 250364,
                "output" : 250255
        },
        "ok" : 1
}
{
        "result" : "mrout524997",
        "timeMillis" : 191449,
        "counts" : {
                "input" : 2500014,
                "emit" : 2500014,
                "reduce" : 250120,
                "output" : 250019
        },
"ok" : 1
}
{
        "result" : "mrout775025",
        "timeMillis" : 184945,
        "counts" : {
                "input" : 2249971,
                "emit" : 2249971,
                "reduce" : 225057,
                "output" : 224964
        },
        "ok" : 1
}
         "ok" : 1
}
{
        "result" : "mrout775025",
        "timeMillis" : 184945,
        "counts" : {
                "input" : 2249971,
                "emit" : 2249971,
                "reduce" : 225057,
                "output" : 224964
        },
        "ok" : 1
}
            
第一個(gè)線程時(shí)間確實(shí)超過了其他的線程,但是平均每個(gè)線程仍然用了大約190s的時(shí)間.這意味著并沒有一個(gè)線程快!這有點(diǎn)奇怪,自從用了‘top’,在某種程度上,你可以看到所有的內(nèi)核運(yùn)行情況。


使用多數(shù)據(jù)庫


問題是在多線程之間會有很多鎖競爭。在上鎖時(shí),MR并不是那么無私的(它每1000次讀操作就會產(chǎn)生一次鎖定),而且MR任務(wù)還會執(zhí)行許多寫操作,導(dǎo)致線程最終都會在等待另一個(gè)線程。由于每個(gè)MongoDB數(shù)據(jù)庫都有私有鎖,讓我們嘗試為每一個(gè)線程使用一個(gè)不同的輸出數(shù)據(jù)庫:
   
> var mapred = function(min, max) {
return db.runCommand({ mapreduce: "uniques",
map: function () { emit(this.dim0, 1); },
reduce: function (key, values) { return Array.sum(values); },
out: { replace: "mrout" + min, db: "mrdb" + min },
sort: {dim0: 1},
query: { dim0: { $gte: min, $lt: max } } }) }
> threads = []; for (var i = 0; i = keys.length) ? MaxKey : keys[i * inc + inc].dim0 ; print("min:" + min + " max:" + max); var t = new ScopedThread(mapred, min, max); threads.push(t); t.start() }
min:0 max:274736
min:274736 max:524997
min:524997 max:775025
min:775025 max:{ "$maxKey" : 1 }
connecting to: test
connecting to: test
connecting to: test
connecting to: test
> for (var i in threads) { var t = threads; t.join(); printjson(t.returnData()); }
...
{
        "result" : {
                "db" : "mrdb274736",
                "collection" : "mrout274736"
        },
        "timeMillis" : 105821,
        "counts" : {
                "input" : 2500013,
                "emit" : 2500013,
                "reduce" : 250364,
                "output" : 250255
        },
        "ok" : 1
}
...


這才像話!我們現(xiàn)在降到了100秒,這意味著相比一個(gè)線程而言已經(jīng)提升了2倍。還算差強(qiáng)人意吧,F(xiàn)在我們只有4個(gè)核所以只快了2倍,要是在8核CPU上將會快4倍,以此類推。


使用純JavaScript模式


當(dāng)把輸入數(shù)據(jù)拆分到不同線程上去的時(shí)候,發(fā)生了一些有趣的事情:每個(gè)線程現(xiàn)在有大約250000個(gè)不同的值來輸出,而不是1百萬。這意味著我們可以使用“純JS模式”,它可以通過使用jsMode:true來開啟。開啟后,MongoDB在處理時(shí)將不會把對象在JS和BSON之間來回翻譯,相反,它使用一個(gè)限額500000個(gè)key的內(nèi)部JS字典來化簡所有對象。讓我們看看這是否有用:
   
> var mapred = function(min, max) {
return db.runCommand({ mapreduce: "uniques",
map: function () { emit(this.dim0, 1); },
reduce: function (key, values) { return Array.sum(values); },
out: { replace: "mrout" + min, db: "mrdb" + min },
sort: {dim0: 1},
query: { dim0: { $gte: min, $lt: max } },
jsMode: true }) }
> threads = []; for (var i = 0; i = keys.length) ? MaxKey : keys[i * inc + inc].dim0 ; print("min:" + min + " max:" + max); var t = new ScopedThread(mapred, min, max); threads.push(t); t.start() }
min:0 max:274736
min:274736 max:524997
min:524997 max:775025
min:775025 max:{ "$maxKey" : 1 }
connecting to: test
connecting to: test
connecting to: test
connecting to: test
> for (var i in threads) { var t = threads; t.join(); printjson(t.returnData()); }
...
{
        "result" : {
                "db" : "mrdb274736",
                "collection" : "mrout274736"
        },
        "timeMillis" : 70507,
        "counts" : {
                "input" : 2500013,
                "emit" : 2500013,
                "reduce" : 250156,
                "output" : 250255
        },
        "ok" : 1
}
...


現(xiàn)在我們降到了70秒,就搞定了任務(wù)!jsMode真心有用,尤其是當(dāng)對象有很多字段的時(shí)候。這里只有一個(gè)數(shù)字字段就已經(jīng)下降了30%。


MongoDB在2.6版本上的改進(jìn)


在很早的2.6版本中,在任何的js函數(shù)調(diào)用的時(shí)候,我們就通過一段代碼設(shè)置一個(gè)可選參數(shù)”args“。這種做法并不標(biāo)準(zhǔn),不在使用。但是它確有留下來的原因(查看 SERVER-4654)。讓我們從Git資源庫中導(dǎo)入MongoDB,編譯并運(yùn)行進(jìn)行測試:
   
...
{
        "result" : {
                "db" : "mrdb274736",
                "collection" : "mrout274736"
        },
        "timeMillis" : 62785,
        "counts" : {
                "input" : 2500013,
                "emit" : 2500013,
                "reduce" : 250156,
                "output" : 250255
        },
        "ok" : 1
}
...
            
這是明顯的提高了3倍的運(yùn)行速度,時(shí)間降低到了60s,大約10-15%。這種變化也提高了整體JS引擎的堆消耗。


結(jié)語


回顧一下,對于同一個(gè)MR作業(yè),我們開始時(shí)花費(fèi)1200 秒,最后花費(fèi)60秒,提升了20倍!這項(xiàng)提高應(yīng)該對大部分應(yīng)用都有效,即使有些trick不太理想(例如,使用多種輸出 dbs/collections)。至少這能提供給人們思路,如何加速他們的MR作業(yè),希望這些特征在將來會更加易于使用。接下來的票將使得‘splitVector’命令更加有用,這張票將在同一個(gè)數(shù)據(jù)庫中提升多MR作業(yè)。干杯!

文章轉(zhuǎn)載自:開源中國社區(qū) [http://www.oschina.net]

本文地址:http://www.oschina.net/translate/how-to-speed-up-mongodb-map-reduce-by-20x

英文原文:How to Speed Up MongoDB MapReduce by 20x


本文來自ChinaUnix新聞?lì)l道,如果查看原文請點(diǎn):http://news.chinaunix.net/opensource/2013/1102/2998020.shtml

您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP