Client → Protobuf → HRegionServer.execRegionServerService()
→ MultiRowMutationEndpoint.mutateRows()
→ HRegion.processRowsWithLocks() ← 總控入口
├── acquireRowLocks()
├── doWALAppend() ← 寫 WAL
└── writeToMemStore() ← 寫 MemStore
核心原則:先寫 WAL(順序追加、高吞吐),再寫 MemStore(隨機更新、服務讀取)。WAL 保證「掉電不丟數據」,MemStore 保證「查詢低延遲」。
WAL.append()long append(HRegionInfo info, WALKey key, WALEdit edits, boolean inMemstore) throws IOException;
HRegionInfo:Region 元數據WALKey:包含 Region 名、表名、序列號、寫入時間WALEdit:原子性單元,封裝同一 Row 所有列的 KeyValue(Cell) 集合inMemstore:是否已同步進 MemStore(影響恢復重放邏輯)一行多列更新打包為單個 WALEdit,確保行級原子性:
// WALEdit 核心結構
class WALEdit {
private final List cells = new ArrayList<>(); // 同一 Row 所有 Cell
public void add(Cell cell) { cells.add(cell); }
public List| getCells() { return cells; }
}
| |
恢復時,要么整行重放,要么整行丟棄,不會出現「同一行部分列生效」的中間態。
觸發條件 動作 配置參數
單個 WAL 文件達到大小閾值 滾動新文件 hbase.regionserver.hlog.blocksize (默認 64MB)
WAL 文件數量超過上限 強制刷盤最舊 Region,刪除舊文件 hbase.regionserver.maxlogs (默認 32)
定期檢查 調用 findRegionsToForceFlush() 清理可刪除文件 hbase.regionserver.logroll.period (默認 1h)
故障恢復流程
- RegionServer 重啟,
SplitLogManager 協調分割舊 WAL 文件
- 按 Region 拆分為
recovered.edits 臨時文件
- Region 上線時重放
recovered.edits 重建 MemStore 狀態
- 重放完成後刪除臨時文件,標記 WAL 文件可刪除
調優建議
hbase.regionserver.hlog.sync = true(默認),確保每次 append 落盤。hbase.regionserver.hlog.blocksize = 128MB 減少滾動頻率。hbase.regionserver.wal.files、hbase.regionserver.wal.size,積壓預示刷盤跟不上或 GC 停頓。HBase WAL 以 Row 級 WALEdit 保證原子性,以 序列號 + 最小未刷盤序列號 精準判斷文件可刪除,以 順序追加 + 定期滾動 實現高吞吐持久化。理解其源碼級調用鏈與刷盤判斷邏輯,是排查寫入延遲抖動、數據丟失風險、存儲空間洩漏的核心鑰匙。