HBase的數據寫入操做,會先記錄到HLog中,再真正寫入到MemStore中。
前者是對寫入友好的格式,後者是對查詢友好的格式。因此前者吞吐量更高,寫入成功率大,提升了系統的可靠性,「基本」能夠實現宕機後繼續沒有完成的數據更新操做。app
WAL interface提供了對外的WAL API。
spa
其中最經常使用的方法是append()。3d
long append(HRegionInfo info, WALKey key, WALEdit edits, boolean inMemstore) throws IOException;
它追加寫入一系列WALEdit。日誌
每個HBase region有一個單獨的WAL interface的實例:code
HBase客戶端 == Protobuf協議 ==> HRegionServer.execRegionServerService() => MultiRowMutationProtos.callMethod() => MultiRowMutationProtos.mutateRows()=> MultiRowMutationEndpoint.mutateRows() => HRegion.processRowsWithLocks() =>HRegion.doWALAppend()會寫入WAL。對象
HRegion.processRowsWithLocks()是HRegion更新操做的總控方法——驅動了 獲取所、寫入WAL、寫入MemStore 這一流程。blog
爲了實現HBase寫入一行裏的多個列時的原子性,對一行上全部列(即全部KeyValue)的更新操做,都包含在同一個WALEdit對象中:it
因此WALEdit中最主要的成員變量,是一系列KeyValue(也就是Cell)的集合:io
所謂Flush應該是指將這個Region的業務數據從MemStore寫入Store。class
若是一個Region被Flush了,那麼其業務數據已經落地到了HFile中。則這個Region的WAL日誌(數據操做記錄)就沒有必要存在了,能夠刪除,以騰出磁盤空間。
AbstractFSWAL.findRegionsToForceFlush() 用於找到已經被Flush的、相應WAL日誌能夠被刪除的Region。
1. 從AbstractFWSAL.byWalRegionSequenceIds找到第一個文件。
ConcurrentNavigableMap<Path, Map<byte[], Long>> byWalRegionSequenceIds 維護了當前WAL的全部文件,以及每一個文件所涉及的Region (包括Region的byte[]名稱和這個Region中最後一次append操做的sequence id)
即 Path (WAL文件名) => (byte[] Region名稱, Long sequence id)
2. 從第一個文件,找到它的全部Region中,哪些尚未被Flush
ConcurrentMap<byte[], ConcurrentMap<byte[], Long>> AbstractFWSAL.SequenceIdAccounting.lowestUnflushedSequenceIds 維護了byte[] Region名稱 + byte[] family名稱 到第一個(即最小的)沒有被Flush的sequence id的映射,稱爲lowestUnflushedSequenceId。這裏,每一次append操做對應一個自增的sequence id。全部大於等於lowestUnflushedSequenceId的sequence id,其對應的append操做都沒有被Flush。
所以對於第一步獲得的第一個WAL日誌文件所涉及的全部Region, 和每一個Region的最大sequence id,若是這個最大的sequece id大於這個Region的lowestUnflushedSequenceId,說明這個Region有WAL日誌尚未被Flush。那麼這個Region就會被包含在findRegionsToForceFlush()的結果中。