乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      在HBase中應(yīng)用MemStore

       WindySky 2016-05-24

       

      譯者注:上個(gè)月寫(xiě)了一遍博文,介紹一種高效的Java緩存實(shí)現(xiàn)http://maoyidao./blog/1559420。其本質(zhì)是模仿Memcached的Slab,通過(guò)分配連續(xù)定長(zhǎng)的byte[]減少大規(guī)模使用Java Heap作為緩存時(shí)不可避免的GC問(wèn)題。雖然當(dāng)時(shí)構(gòu)思和實(shí)現(xiàn)這一思路時(shí)并沒(méi)有參照其他開(kāi)源產(chǎn)品,但這一思路在很多著名的開(kāi)源產(chǎn)品上也有類(lèi)似的實(shí)現(xiàn)。隨著內(nèi)存使用成本越來(lái)越低,高并發(fā)海量數(shù)據(jù)應(yīng)用開(kāi)發(fā)者逐漸傾向于這樣一種思路:“內(nèi)存就是新的硬盤(pán),硬盤(pán)就是新的磁帶”。即通過(guò)盡量多的使用內(nèi)存,和盡量多的順序讀寫(xiě)磁盤(pán)實(shí)現(xiàn)高吞吐。因此大規(guī)模使用內(nèi)存引起的Java GC問(wèn)題就成為了一個(gè)普遍問(wèn)題。翻譯這篇文章的初衷是:

      (1)該系列文章以Hadoop為例介紹了GC停頓帶來(lái)的問(wèn)題,比較生動(dòng)。

      (2)比較詳細(xì)的介紹了GC原理,特別是CMS錯(cuò)誤產(chǎn)生的原因,并且有實(shí)驗(yàn)例子。

      (3)介紹了一系列GC參數(shù)及GC profile思路,比較有借鑒價(jià)值。

      (4)HBase實(shí)現(xiàn)方式和我的實(shí)現(xiàn)思路類(lèi)似,可以作為對(duì)照。

       

      原文地址:http://www./blog/2011/02/avoiding-full-gcs-in-hbase-with-memstore-local-allocation-buffers-part-1/

       

      作者:Todd Lipcon, software engineer for Cloudera. Todd在2012年Hadoop峰會(huì)上介紹了:Optimizing MapReduce Job Performance,對(duì)性能調(diào)優(yōu)有豐富經(jīng)驗(yàn)。

       

      在HBase中應(yīng)用MemStore-Local Allocation Buffers解決Full GC問(wèn)題:第一部分

      今天我想分享一些Cloudera Hadoop中的工程細(xì)節(jié)。在這篇文章中,我將解釋一個(gè)新的Apache HBase組件:MemStore-Local Allocation Buffer,它顯著的降低了Java GC導(dǎo)致的線程暫停頻率。本篇文章將是這個(gè)三部分系列文章的第一部分。

      背景

      堆和堆內(nèi)存!

      廉價(jià)商用服務(wù)器上的內(nèi)存數(shù)量在過(guò)去的幾年中不斷的增長(zhǎng)。當(dāng)Apache的HBase的項(xiàng)目于2007年開(kāi)始時(shí),運(yùn)行Hadoop的典型配置有4到8GB內(nèi)存。今天,大多數(shù)Hadoop客戶以至少24G內(nèi)存運(yùn)行Hadoop,使用48G甚至72G內(nèi)存的客戶也變得越來(lái)越普遍,而內(nèi)存使用成本則繼續(xù)回落。表面上,這對(duì)像HBase的數(shù)據(jù)庫(kù)這樣對(duì)延遲敏感的軟件來(lái)說(shuō),這似乎是一個(gè)偉大的勝利,大量的內(nèi)存可以容納更多的數(shù)據(jù)緩存,在刷新到磁盤(pán)前作為寫(xiě)入緩,避免昂貴的磁盤(pán)尋址和讀。然而在實(shí)踐中,HBase使用的內(nèi)存不斷增長(zhǎng),但JDK可用的垃圾收集算法仍然相同。這導(dǎo)致了HBase的許多用戶的一個(gè)主要問(wèn)題:隨著Java使用堆大小繼續(xù)增長(zhǎng),垃圾回收導(dǎo)致的“stop-the-world”時(shí)間變得越來(lái)越長(zhǎng)。這在實(shí)踐中意味著什么?

       

      在垃圾回收導(dǎo)致的“stop-the-world”期間,任何到HBase客戶端請(qǐng)求都不會(huì)被處理,造成用戶可見(jiàn)的延遲,甚至超時(shí)。如果因?yàn)闀和?dǎo)致請(qǐng)求超過(guò)一分鐘響應(yīng),HBase本身也可能會(huì)停止 - 僅僅因?yàn)槔厥諏?dǎo)致這樣的延遲顯得很不值。

       

      HBase依賴Apache Zookeeper的管理群集成員和生命周期。如果服務(wù)器暫停的時(shí)間過(guò)長(zhǎng),它將無(wú)法發(fā)送心跳ping消息到Zookeeper quorum(譯者注:Zookeeper的分布式算法),其余的服務(wù)器將假定該服務(wù)器已經(jīng)死亡。這將導(dǎo)致主服務(wù)器啟動(dòng)特定的恢復(fù)程序,替換被認(rèn)為死亡的服務(wù)器。當(dāng)這個(gè)服務(wù)器從暫停中恢復(fù)時(shí),會(huì)發(fā)現(xiàn)所有它擁有的租約都被撤銷(xiāo),進(jìn)而只好自殺。HBase的開(kāi)發(fā)團(tuán)隊(duì)已經(jīng)親切地稱這種情況為朱麗葉暫停,此情況下 - 主服務(wù)器(羅密歐)假定邊緣服務(wù)器(朱麗葉)死亡的(其實(shí)它真沒(méi)死,只是睡覺(jué)),因此需要一些激烈的行動(dòng)(恢復(fù))。當(dāng)邊緣服務(wù)器從GC暫停中醒過(guò)來(lái),它發(fā)現(xiàn)了一個(gè)巨大的錯(cuò)誤已經(jīng)鑄成,只好結(jié)束自己的生命。這是一個(gè)非??膳碌墓收?!

      (譯者注:由于Java GC導(dǎo)致的心跳包沒(méi)有及時(shí)響應(yīng)問(wèn)題,在對(duì)延時(shí)要求敏感的場(chǎng)景非常普遍。曾經(jīng)有一個(gè)業(yè)務(wù)場(chǎng)景,集群中的服務(wù)器每500ms發(fā)送一次心跳包到mater服務(wù)器,而master服務(wù)器由于GC導(dǎo)致沒(méi)有及時(shí)響應(yīng)心跳包,進(jìn)而認(rèn)為服務(wù)器死亡,導(dǎo)致故障)

       

      做過(guò)大負(fù)載HBase集群負(fù)載測(cè)試的人應(yīng)該對(duì)上述問(wèn)題很熟悉,在典型的硬件環(huán)境上,每GB的堆可以導(dǎo)致Hadoop暫停8-10秒。則分配8G堆的Hadoop會(huì)因GC暫停一分鐘以上。

      (譯者注:Hadoop這個(gè)回收時(shí)間比較恐怖,我在線上服務(wù)分配36G Heap,平均FullGC暫停時(shí)間是6-8秒,因此萬(wàn)惡不是“大堆”為首,而是“內(nèi)存使用方式不當(dāng)”為首。這也是后文中調(diào)優(yōu)的原因所在)

      不管人們?nèi)绾握{(diào)整,事實(shí)證明這個(gè)問(wèn)題是完全不可避免的。由于這是一個(gè)共同的問(wèn)題,而且每況愈下。因此在今年年初,它成為一個(gè)Cloudera的優(yōu)先項(xiàng)目。在這篇文的其余部分,我將介紹我們開(kāi)發(fā)的方法,該解決方案在很大程度上消除了這個(gè)問(wèn)題。

       

      Java的GC背景

      為了徹底了解GC暫停的問(wèn)題,有必要了解有一些在Java GC的技術(shù)背景。這里只作出一些簡(jiǎn)單描述,所以我非常鼓勵(lì)你做進(jìn)一步的研究。如果你已經(jīng)在GC的專(zhuān)家,隨時(shí)跳過(guò)這一節(jié)。

       

      Generational GC(譯者注:即分“代”回收算法)

      Java的垃圾回收器通常工作在Generational GC模式,該模式基于一個(gè)假設(shè):假設(shè)大多數(shù)對(duì)象英年早逝,還是堅(jiān)持相當(dāng)長(zhǎng)的時(shí)間?(譯者注:事實(shí)上兩種情況同時(shí)存在)例如,在RPC請(qǐng)求緩沖區(qū)中對(duì)象將只存活幾毫秒,而在HBase的MemStore數(shù)據(jù)的數(shù)據(jù)可能會(huì)存活許多分鐘。很顯然用兩種不同的垃圾收集算法處理兩種不同的生命周期的對(duì)象更好些。因此,JVM把對(duì)象分成兩代:年輕代(New)和老年代(Old)。分配對(duì)象時(shí),JVM在年輕代里分配對(duì)象。如果一個(gè)對(duì)象經(jīng)過(guò)幾次GC在還存活在年輕代,垃圾回收程序就把這個(gè)對(duì)象搬遷到老年代,在這里我們假設(shè)數(shù)據(jù)是會(huì)存活很長(zhǎng)時(shí)間。

       

      在大多數(shù)對(duì)延遲敏感的場(chǎng)景,比如HBase,我們建議使用JVM參數(shù):-XX:+ UseParNewGC和-XX:+ UseConcMarkSweepGC。

       

      Parallel New Collector

      Parallel New Collector是“stop-the-world”復(fù)制收集。每當(dāng)它運(yùn)行時(shí),它首先暫停所有的Java線程。然后,它追蹤的對(duì)象引用來(lái)確定些對(duì)象是活的(仍然有程序引用這些對(duì)象)。最后它移動(dòng)活動(dòng)對(duì)象到堆里的空閑空間,并更新到這些對(duì)象的指針指向新的地址。

       

      重點(diǎn)是:

      • 它stop-the-world,但不是很長(zhǎng)。因?yàn)槟贻p代通常是相當(dāng)小的,它可以非常迅速地完成其工作。在生產(chǎn)環(huán)境中,我們通常建議不超過(guò)512MB ,這導(dǎo)致即使在最壞的情況下,年輕代GC暫停的時(shí)間也不到幾百毫秒。

      (譯者注:似乎很少見(jiàn)到有配置這么小得Yong區(qū),一般是New:Old=1:8,比如:-Xms8g -Xmx8g -Xmn1g;不過(guò)作者的說(shuō)法也可以試一試。原則是,不管你把JVM Heap設(shè)置多大,Yong區(qū)都不要設(shè)置的過(guò)大)

       

      • 它復(fù)制活動(dòng)對(duì)象到一個(gè)自由的堆區(qū),同時(shí)在每次回收后壓縮(compating)自由空間。因此每次GC后,free space在年輕代都是一個(gè)連續(xù)的塊,這意味著再次分配可以是非常有效的。

      每次Parallel New collector復(fù)制一個(gè)對(duì)象,該對(duì)象的計(jì)數(shù)器遞增。當(dāng)對(duì)象在年輕代多次復(fù)制后仍存活,決定了它屬于長(zhǎng)壽命的對(duì)象,將移動(dòng)到老年代。在對(duì)象被移入老年代之前,在年輕代內(nèi)被拷貝的最大次數(shù)被稱為tenuring threshold。

       

      Concurrent-Mark-Sweep collector

      每一次新的并行收集器運(yùn)行時(shí),它將移動(dòng)一些對(duì)象到老年代,老年代最終將被填滿。因此我們需要一個(gè)回收老年代的策略。Concurrent-Mark-Sweep collector(CMS)是負(fù)責(zé)清除老年代里的死對(duì)象。

       

      CMS的收集工作包括一系列階段。某些階段stop-the-world,某些階段則和其他Java應(yīng)用程序同時(shí)運(yùn)行。主要階段是:

       

      • 初始標(biāo)志(停止世界)。在這個(gè)階段CMS對(duì)根對(duì)象打標(biāo)記。根對(duì)象是線程直接引用的對(duì)象 - 例如,該線程使用的局部變量。這個(gè)階段是的暫停是短暫的,因?yàn)楦鶎?duì)象數(shù)量很少。
      • 并發(fā)標(biāo)記(并行)?,F(xiàn)在CMS從根對(duì)象開(kāi)始標(biāo)記被根對(duì)象引用的所有對(duì)象,直到它標(biāo)記完系統(tǒng)中的所有活動(dòng)對(duì)象。
      • 重標(biāo)記(停止世界)。由于對(duì)象可能有引用改變,新的對(duì)象可能已經(jīng)在并發(fā)標(biāo)記創(chuàng)建的,我們需要回去考慮那些在這個(gè)階段被創(chuàng)建的對(duì)象。這也是個(gè)短期的停頓,因?yàn)橛幸粋€(gè)特殊的數(shù)據(jù)結(jié)構(gòu),讓我們只需要檢查那些在上一個(gè)階段被修改的對(duì)象。
      • 并發(fā)掃描(并行)?,F(xiàn)在,我們繼續(xù)梳理在堆中的所有對(duì)象。任何沒(méi)有被標(biāo)記的對(duì)象將會(huì)被回收并視為空閑空間。在此期間分配的新對(duì)象也會(huì)被打標(biāo)記,以免被回收。

       

      這里要注意的重要事情是:

       

      • stop-the-world的階段很短。而掃描整個(gè)堆和清除死對(duì)象這種長(zhǎng)期工作可以和Java線程并行發(fā)生。
      • CMS不搬遷的活動(dòng)對(duì)象,所以自由空間可以分布在整個(gè)堆的不同區(qū)塊。我們將稍后回來(lái)?。ㄗg者注:這個(gè)是優(yōu)化的重點(diǎn),稍后的系列文章會(huì)繼續(xù)介紹)

      CMS的失效模式(CMS Failure)

      正如我所描述的,CMS看起來(lái)真的很棒 - 只停留很短的時(shí)間,而繁重的工作都可以和Java線程同時(shí)進(jìn)行。那么當(dāng)我們?cè)谥刎?fù)載下運(yùn)行分配了大Heap HBase時(shí),GC是如何造成我們看到的多分鐘暫停的呢?事實(shí)證明,CMS有兩種故障模式。

       

      并發(fā)模式失敗

      第一種失敗的模式,是簡(jiǎn)單的并發(fā)模式失敗。最好的一個(gè)例子:假設(shè)有一個(gè)8GB堆,已經(jīng)使用了7GB。當(dāng)CMS的收集開(kāi)始第一階段,它歡快的隆隆的做著并發(fā)標(biāo)記。與此同時(shí),有更多的數(shù)據(jù)被分配到老年代。如果老年代增長(zhǎng)的速度太快,在CMS完成第一階段標(biāo)記工作之前就填滿了全部老年代。這時(shí)候因?yàn)闆](méi)有自由空間,CMS就無(wú)法工作!CMS必須放棄并行工作,并回落到停止世界(stop-the-world)單線程復(fù)制收集算法。此算法開(kāi)始搬遷堆,檢查所有活動(dòng)對(duì)象,并釋放了所有死角。長(zhǎng)時(shí)間的停頓后,該程序可能會(huì)繼續(xù)。

       

      但我們可以很容易的通過(guò)調(diào)整JVM參數(shù)避免并發(fā)模式失?。何覀冎恍枰膭?lì)CMS提前開(kāi)始工作!設(shè)置-XX:CMSInitiatingOccupancyFraction = N,其中N是堆在開(kāi)始收集過(guò)程中的百分比。HBase仔細(xì)的計(jì)算了內(nèi)存使用,以保持其只使用60%的堆空間,所以我們通常將此值設(shè)置為大約70。(譯者注:同時(shí)也可以考慮Old區(qū)的30%要比Young區(qū)大,這樣即使Young區(qū)在CMS之前全部搬遷到Old區(qū)也不會(huì)把Old區(qū)填滿)

       

      碎片導(dǎo)致的CMS失敗

      這種故障模式是多一點(diǎn)復(fù)雜?;叵胍幌?,CMS收集不搬遷對(duì)象,而是簡(jiǎn)單地跟蹤所有堆的自由空間,而且自有空間是分開(kāi)的。作為一個(gè)思想實(shí)驗(yàn),想象我撥出1億個(gè)對(duì)象,每個(gè)1KB,這正是1GB堆的總用量為1GB。然后,我釋放所有奇數(shù)對(duì)象,所以我有500MB的自有空間,然而自由空間都是1KB的塊。如果我需要分配一個(gè)2KB的對(duì)象,盡管我表面上有500MB免費(fèi)空間,依然會(huì)無(wú)處可放。這就是所謂的內(nèi)存碎片。因?yàn)镃MS不搬遷對(duì)象,不管如何讓CMS提前啟動(dòng),都不可以解決這個(gè)問(wèn)題!發(fā)生此問(wèn)題時(shí),CM再次回落到復(fù)制收集器,該方法能夠壓縮所有的對(duì)象并釋放空間。

       

      GC知識(shí)已經(jīng)足夠了!回到HBase來(lái)!

      讓我們回來(lái)并使用我們關(guān)于Java GC的知識(shí)思考HBase:

      通過(guò)設(shè)置的CMSInitiatingOccupancyFraction,一些用戶能夠避免GC的問(wèn)題。但對(duì)于其他的場(chǎng)景,GC會(huì)經(jīng)常發(fā)生,無(wú)論CMSInitiatingOccupancyFraction設(shè)置的多么低。我們則經(jīng)??吹皆谶@些GC停頓時(shí),堆還有幾個(gè)GB的自由空間!鑒于這些情況,我們推測(cè),我們的問(wèn)題應(yīng)該是由碎片引起的,而不是一些內(nèi)存泄漏或不當(dāng)調(diào)整。

       

      一個(gè)實(shí)驗(yàn):測(cè)量碎片

       

      我們將運(yùn)行一個(gè)實(shí)驗(yàn)證實(shí)這一假設(shè)。第一步是收集一些有關(guān)堆的碎片信息。在探查OpenJDK源代碼后,我發(fā)現(xiàn)鮮為人知的參數(shù)的-XX:PrintFLSStatistics = 1(譯者注:JDK1.6也支持該選項(xiàng)),結(jié)合其他詳細(xì)GC日志記錄選項(xiàng)時(shí),會(huì)導(dǎo)致CMS之前和之后每打印有關(guān)其自由空間的統(tǒng)計(jì)信息。特別是,我們關(guān)心的指標(biāo)是:

      • free space - 老年代的空閑內(nèi)存的總數(shù)
      • NUM塊 - 非連續(xù)的內(nèi)存空閑塊總數(shù)
      • 最大塊大小 - 空閑塊的最大大小

      我啟用了這個(gè)選項(xiàng),啟動(dòng)了一個(gè)集群,然后運(yùn)行了Yahoo Cloud Serving Benchmark(YCSB)的三個(gè)獨(dú)立的壓力測(cè)試:

      只寫(xiě):每行10列,每列100個(gè)字節(jié),1億個(gè)row key。

      只讀(有緩存替換):隨機(jī)讀取1億不同的行鍵的數(shù)據(jù),使數(shù)據(jù)不能完全存儲(chǔ)在適LRU緩存。

      只讀(無(wú)緩存替換):隨機(jī)讀取1萬(wàn)不同的行鍵的數(shù)據(jù),使數(shù)據(jù)完全符合LRU緩存。

      每個(gè)壓力測(cè)試將運(yùn)行至少一個(gè)小時(shí),這樣我們可以收集GC行為數(shù)據(jù)。這個(gè)實(shí)驗(yàn)的目標(biāo)是首先要驗(yàn)證我們的假說(shuō),暫停是由碎片引起的,第二,以確定造成這些問(wèn)題的主要原因是讀取路徑(包括LRU緩存)還是寫(xiě)路徑(包

       

      括每個(gè)地區(qū)的MemStores )。

       

      將要繼續(xù)...

       

      在本系列的下一篇文章將顯示HBase的這個(gè)實(shí)驗(yàn)和挖掘內(nèi)部結(jié)果,了解不同的工作負(fù)載如何影響內(nèi)存布局。

      同時(shí),如果您想了解更多有關(guān)Java的垃圾收集器,我推薦以下幾個(gè)環(huán)節(jié):

      Jon “the collector” Masamitsu has a good post describing the various collectors in Java 6.

      To learn more about CMS, you can read the original paper: A Generational Mostly-concurrent Garbage Collector [Printezis/Detlefs, ISMM2000]


       

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類(lèi)似文章 更多