redis.conf翻譯與配置(六)【redis6.0.6】
775
2022-05-28
環形緩沖區底層實現
首先明白改過程發生在Map——Collect階段:在用戶編寫的map()函數中,當數據處理完成后,一般會調用OutputCollector.collect()輸出結果。在該函數內部,它會將生成的key/value分片(通過調用Partitioner),并寫入一個環形內存緩沖區中。
MapOutputBuffer內部使用了一個緩沖區暫時存儲用戶輸出數據,當緩沖區使用率達到一定閾值后,再將緩沖區中的數據寫到磁盤上。
數據緩沖區的設計方式直接影響到Map Task的寫效率,而現有多種數據結構可供選擇,最簡單的是單向緩沖區,生產者向緩沖區中單向寫入輸出,當緩沖區寫滿后,一次性寫到磁盤上,就這樣,不斷寫緩沖區,直到所有數據寫到磁盤上。單向緩沖區最大的問題是性能不高,不能支持同時讀寫數據。
雙緩沖區是對單向緩沖區的一個改進,它使用兩個緩沖區,其中一個用于寫入數據,另一個將寫滿的數據 寫到磁盤上,這樣,兩個緩沖區交替讀寫,進而提高效率。實際上,雙緩沖區只能一定程度上讓讀寫并行,仍會存在讀寫等待問題。
一種更好的緩沖區設計方式是采用環形緩沖區:當緩沖區使用率達到一定閾值后,便開始向磁盤上寫入數據,同時,生產者仍可以向不斷增加的剩余空間中循環寫入數據,進而達到真正的讀寫并行。
底層就是一個字節數組:數組前面記錄關于KV的索引位置,數組后面記錄KV數據。首尾相接構成一個環形的緩沖區,中間是赤道。用于數據spll溢出處理。
單生產者消費者模型,其中,MapOutputBuffer的collect方法和MapOutputBuffer.Buffer的write方法是生 產者,spillThread線程是消費者,它們之間同步是通過可重入的互斥鎖spillLock和spillLock上的兩個條件變量(spillDone和spillReady)完成 的.生產者主要代碼如下
//取得下一個可寫入的位置 spillLock.lock(); if(緩沖區使用率達到閾值){ //喚醒SpillThread線程,將緩沖區數據寫入磁盤 spillReady.signal(); } if(緩沖區滿){ //等待SpillThread線程結束 spillDone.wait(); } spillLock.lock(); //將數據寫入緩沖區
MapOutputBuffer內部采用了兩級索引結構,涉及三個環形內存緩沖區,分別是kvoffsets、kvindices和kvbuffer,這三個緩沖 區所占內存空間總大小為io.sort.mb(默認是100 MB)。
kvoffsets即偏移量索引數組,用于保存key/value信息在位置索引kvindices中的偏移量。考慮到一對key/value需占用數組kvoffsets的1個 int(整型)大小,數組kvindices的3個int大小(分別保存所在partition號、key開始位置和value開始位置),所以Hadoop按比例1:3將大小為 ${io.sort.record.percent}*${io.sort.mb}的內存空間分配給數組kvoffsets和kvindices,
該過 程由指針kvstart/kvend/kvindex控制,其中kvstart表示存有數據的內存段初始位置,kvindex表示未存儲數據的內存段初始位置,而在正常寫 入情況下,kvend=kvstart,一旦滿足溢寫條件,則kvend=kvindex,此時指針區間[kvstart, kvend)為有效數據區間。
kvindices即位置索引數組,用于保存key/value值在數據緩沖區kvbuffer中的起始位置。
kvbuffer即數據緩沖區,用于保存實際的key/value值,默認情況下最多可使用io.sort.mb中的95%,當該緩沖區使用率超過 io.sort.spill.percent(默認80%)后,便會觸發線程SpillThread將數據寫入磁盤。
更多的詳細信息你可以參考《Hadoop技術內幕:深入解析MapReduce架構設計與實現原理 》
你可以點這里掃描二維碼(或者微信搜 :孫中明) 回復關鍵字 3006 獲取相關書籍此類
數據結構
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。