您好,登錄后才能下訂單哦!
本篇內容介紹了“HBase Flush對讀寫服務的影響是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
HBase的Flush操作的觸發條件:
1)Manual調用,HRegionInterface#flushRegion,可以被用戶態org.apache.hadoop.hbase.client.HBaseAdmin調用flush操作實現,該操作會直接觸發HRegion的internalFlush。
2)HRegionServer的一次更新操作,使得整個內存使用超過警戒線。警戒線是globalMemStoreLimit, RS_JVM_HEAPSIZE * conf.getFloat(“hbase.regionserver.global.memstore.upperLimit”),凡是超過這個值的情況,會直接觸發FlushThread,從全局的HRegion中選擇一個,將其MemStore刷入hdfs,從而保證rs全局的memstore容量在可控的范圍。
RS上HRegion的選擇算法:
步驟1:RS上的Region,按照其MemStore的容量進行排序。
步驟2:選出Region下的Store中的StoreFile的個數未達到hbase.hstore.blockingStoreFiles,并且MemStore使用最多的Region。— bestFlushableRegion
步驟3:選出Region下的MemStore使用最多的Region。— bestAnyRegion
步驟4:如果bestAnyRegion的memstore使用量超出了bestFlushableRegion的兩倍,這從另外一個角度說明,雖然當前bestAnyRegion有超過blockingStoreFiles個數的文件,但是考慮到RS內存的壓力,冒著被執行Compaction的風險,也選擇這個Region,因為收益大。否則,直接使用bestFlushableRegion。
指定的Region寫入hdfs的過程:
步驟1:獲得updatesLock的寫鎖,阻塞所有對于該Region的更新操作。由此,可知Flush操作會阻塞Region區域內Row的更新操作(Put、Delete、Increment),因為在阻塞更新操作期間,涉及到Memstore的snapshot操作,如果不做限制,那么很可能一個put操作的多個KV,分別落在kvset和snapshot當中,從而與hbase保證row的原子性相悖。
步驟2:mvcc推進一次寫操作事務。每個Region維護了一個mvcc對象(Multi Version
Consistency Control),用來控制讀寫操作的事務性。
步驟3:從HLog中獲取一個新的newSeqNum,更新HLog的lastSeqWritten。由于此時該Region的更新操作會暫停,因此,會暫時刪除lastSeqWritten記錄的<RegionName,lastSeqNum>,寫入<”snp”+RegionName, newSeqNum>到lastSeqWritten中。這里的lastSeqWritten是HLog用來存儲每個Regiond到當前時刻最后一次提交操作的SeqNum。
步驟4:為Region下的每個Store的MemStore執行snapshot操作。
如上圖所示,HRegion上Store的個數是由Table中ColumnFamily的個數確定,每個Store是由一個MemStore和數個StoreFile(HFile)文件組成,在正常的更新操作過程中,更新的內容會寫入MemStore里的kvset結構中。HRegion執行Flush操作,實際上是把MemStore的內容全部刷入hdfs的過程。雖然,目前更新操作已經通過加寫鎖阻塞,可是讀操作仍然可以繼續,因此,在memstore執行snapshot的過程中,通過reference,snapshot會指向kvset,然后給kvset指向一個全新的內存區域。代碼如下:
步驟5:釋放updatesLock的寫鎖,此時該HRegion可以接收更新操作。
步驟6:更新mvcc讀版本到當前寫版本號。
這里有一個小插曲,在更新操作時,mvcc. completeMemstoreInsert 的操作在updatesLock的范圍之外,這樣在多線程高并發情況下,就存在已經寫入MemStore的kvset當中,但是事務還未完成提交的情況。該場景相關代碼如下:
從4358行,我們可以清晰看到,通過updatesLock保證了更新操作寫入了MemStore的kvset,但假定Flush線程在其它更新線程4363行之后,獲得了updatesLock寫鎖,并執行了snapshot操作。那么,這里的mvcc就會出現讀寫的事務號不一致的情況,因此,在Region的Flush線程就需要使用waitForRead(w),等待更新到目前寫版本號。
步驟7:將Store內的snapshot寫成一個StoreFile臨時文件。
步驟8:重命名storefile文件,更新Store里文件和Memstore狀態。
在步驟8完成之前,整個Hregion的讀請求,是和之前沒有影響的。因為在讀請求過程中,StoreScanner對于kvset和snapshot進行進行同步讀取,即使kvset切換成snapshot,scan的操作仍然可以繼續,這部分的內容是由MemStoreScanner來控制。
在讀過程中,Store里的scanner有兩部份,一個是StoreFileScanner,另外一個是MemStoreScanner,它們都繼承了KeyValueScanner接口,并通過StoreScanner中的KeyValueHeap封裝起來。于此類似,在RegionScannerImpl也是通過一個KeyValueHeap把每個Store的StoreScanner封裝起來,從而直接提供對外的服務。
讀到這里,可能細心的工程師們,就會有一個疑問:Flush操作對于讀的影響究竟有沒有呢?
有影響,但比較小。在步驟8以前那些階段,MemStoreScanner做到了對于kvset與snapshot的自由切換。
如上所示,如果kvset被重置,那么theNext將不再等于kvsetNextRow,從而切換成開始從snapshot迭代器中獲取數據。
因此,在步驟1~7之間,對于讀服務影響不大。但是在步驟8操作最后一步時,需要把生成storefile更新到可用的Store中的StoreFile列表,并清除snapshot的內容。
于是,此時ChangedReaderOberver就開始起作用了。
// Tell listeners of the change in readers.
notifyChangedReadersObservers();
這里最為關鍵的是,將storescanner用來封裝全部StoreFileScanner和MemStoreScanner的heap清空,它會觸犯的作用是在執行next()操作時,會觸發resetScannerStack操作,會重新加載Store下的所有Scanner,并執行seek到最后一次更新的key。這個過程會使得flush操作對于某些next操作變得突然頓一下。
“HBase Flush對讀寫服務的影響是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。