由於需要規范HBase數據表命名,對測試環境的數據進行了重命名操作。
停掉所有服務后執行下面改名操作
# 禁用活躍用戶表 disable 'DC_XXL:ACTIVE_USERS' # 創建快照 snapshot 'DC_XXL:ACTIVE_USERS', 'tony_snapshot' # 克隆快照為新的表(使用新名稱) clone_snapshot 'tony_snapshot', 'DC_XXL:ACTIVE_USERS_LOG' # 按命名空間查看克隆的表是否存在 list_namespace_tables 'DC_XXL' # 查看快照 list_snapshots # 刪除快照 delete_snapshot 'tony_snapshot' # 查看舊表詳情 desc 'DC_XXL:ACTIVE_USERS' # 查看新表詳情,比較兩個表是否一致 desc 'DC_XXL:ACTIVE_USERS_LOG' # 禁用舊表 disable "DC_XXL:ACTIVE_USERS" # 刪除舊表 drop 'DC_XXL:ACTIVE_USERS'
然后重新啟動測試服務。
操作完后發現測試服務器的存儲空間不足,想要刪除一些數據占用,使用df -h查看各服務器的磁盤空間占用情況,發現Hadoop存儲目錄已占用了90%以上的空間,所以順便使用命令查看一下Hadoop的空間使用情況
# 查看hadoop根目錄各文件夾占用空間 hadoop dfs -du -h / # 查看hbase占用空間 hadoop dfs -du -h /hbase
通過命令一層層查看,可以發現主要是hbase占用了存儲,而剛剛執行前面的命令操作后,在hbase目錄下面發現主要存儲空間占用的目錄有:data(項目數據表存儲目錄)與 archive(存檔目錄),而archive目錄一般存儲的是備份用的,理論上來說是可以直接刪除,所以網上查了一些資料說沒問題后,就直接使用 rmr(hadoop dfs -rmr /hbase/archive/data/DC_XXL/ACTIVE_USERS)命令將里面的存檔文件刪除了,沒想到引發了一系列的故障......
過了一會繼續查看磁盤空間占用,發現磁盤使用在持續快速增長,很快有的服務器已達到100%
使用 hadoop dfs -du -h /hbase 查看發現,MasterProcWALs 目錄突然間多了幾十G,經查詢這是HBase狀態日志目錄,進去將它們全部刪除,發現磁盤占用還是100%沒有變化
繼續排查,使用 hadoop dfs -du -h / 發現,原來直接使用rmr刪除后,hadoop會將文件移動到 /user/root/.Trash/Current/hbase/ 這個垃圾站目錄下面
而這時在查看服務運行日志時,也發現了大量的IO異常
Hbase_thrift.IOError: IOError(message=b'org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=16, exceptions: Mon Jul 06 20:01:52 CST 2020, RpcRetryingCaller{globalStartTime=1594036912662, pause=100, maxAttempts=16}, org.apache.hadoop.hbase.NotServingRegionException: org.apache.hadoop.hbase.NotServingRegionException: DC_XXL:ACTIVE_USERS_LOG,4,1593765189585.73133efd2d876b7f7edabc3ab6709cae. is not online on slave2,16020,1594035938293 at org.apache.hadoop.hbase.regionserver.HRegionServer.getRegionByEncodedName(HRegionServer.java:3249) at org.apache.hadoop.hbase.regionserver.HRegionServer.getRegion(HRegionServer.java:3226) at org.apache.hadoop.hbase.regionserver.RSRpcServices.getRegion(RSRpcServices.java:1414) at org.apache.hadoop.hbase.regionserver.RSRpcServices.get(RSRpcServices.java:2429) ......
從日志中可以看到,是由於寫入數據時,所要寫入的region下線所引發的IO異常,在瀏覽器中進入HBase web管理器(http://master:16010),可以看到所有節點都是在線的,拉到 Tables 位置,查看對應的數據表狀態,會發現該表的Other Regions標識了出現問題的數量。
經過查找資料與思考分析,執行快照操作,HBase會在HDFS中創建一個和unix硬鏈接相同的存儲文件,而執行鏡像克隆操作時,實際上新表與舊表共用相同的數據塊,新表只在data目錄創建新表文件,但並不會復制region,只是通過linkfile定位舊表文件地址。當刪除舊表以后,HBase應該會將舊表數據移動到 archive 目錄下面,只有在新數據寫入並提交compact時,才會數據遷移到新表文件中。所以執行快照和克隆操作是秒級,幾百G的數據執行命令后立馬結果就出來了。
而我直接刪除了備份文件,數據並沒有遷移完,導致某些region直接丟失了。
隨后將回收站的文件重新移動到 archive 目錄下面,使用 hbck 命令修復,發現修復失敗,由於是測試數據只需要從kafka中生成最近一周的就可以了,且舊數據占用太多空間需要清理,所以沒有繼續研究修復,直接將它清除,決定創建新表運行相關服務批量重新生成測試數據。
進入hbase shell中,執行命令
disable 'DC_XXL:ACTIVE_USERS_LOG'
發現命令卡死,直到超時才退出,發現數據表禁用不了也刪除不了。
登錄 zookeeper ,刪除對應的數據
# 連接zookeeper服務 /usr/local/zookeeper/bin/zkCli.sh -server master:2181 # 查看hbase數據表 ls /hbase/table # 刪除數據表 rmr /hbase/table/DC_XXL:ACTIVE_USERS_LOG
刪除Hadoop存儲的數據
# 查看hadoop的dfs文件 hadoop dfs -du -h /hbase/data/DC_XXL # 刪除文件 hadoop dfs -rmr /hbase/data/DC_XXL/ACTIVE_USERS_LOG # 清除垃圾站文件 hadoop dfs -rmr /user/root/.Trash/Current/hbase/data/DC_XXL/ACTIVE_USERS_LOG
再次進入hbase shell,輸入list已查看不到數據表了,輸入命令創建新表
create 'DC_XXL:ACTIVE_USERS_LOG',{NAME=>'c',COMPRESSION=>'lz4',VERSIONS=>1},SPLITS=>['2','4','6','9']
這時直接提示:ERROR: Table already exists 異常信息,經過排查發現原來meta表還存儲了數據表以及對應的region信息,需要一一清除干凈才行
# 掃描meta表,查找當前數據表相關記錄 scan 'hbase:meta',{STARTROW=>'DC_XXL:ACTIVE_USERS_LOG',ENDROW=>'DC_XXL:ACTIVE_USERS_LO~'} # 刪除表記錄命令(這一條命令必須在shell執行,腳本可能刪不干凈) deleteall 'hbase:meta','DC_XXL:ACTIVE_USERS_LOG' # 記錄量少的話可以手動一條條刪除 ......
批量刪除 hbase:meta表數據表相關記錄腳本
import happybase connect = happybase.Connection(host='master', port=9090, timeout=300000, autoconnect=True, compat='0.98', transport='buffered', protocol='binary') def scan(table, row_prefix=None, columns=None): t = happybase.Table(table, connect) scan = t.scan(row_prefix=row_prefix, columns=columns) data = [] for key, value in scan: result = {row.decode().replace('c:', '').lower(): value[row].decode() for row in value} result['pk'] = key.decode() data.append(result) return data def delete(table, rowkey): t = happybase.Table(table, connect) t.delete(rowkey) if __name__ == '__main__': columns = ['info:server'] row_prefix = 'DC_XXL:ACTIVE_USERS_LOG'.encode() result = scan('hbase:meta', row_prefix, columns=columns) print(len(result)) for row in result: pk = row.get('pk') print(pk) delete('hbase:meta', pk)
腳本執行成功后,需要在shell中執行前面的scan語句檢查一次,看看是否全部都刪除干凈
然后重啟hbase服務,進入shell中執行創建數據表語句,這次就可以執行成功了(不重啟hbase服務,可能會影響數據表狀態,然后產生大量的異常狀態記錄占用存儲空間)
在這次事件中出現了幾次錯誤操作,導致本次故障。由於之前也試過多次改名,並沒有出現問題,導致本次操作時過於輕心。沒有深入了解快照和克隆快照的底層原理,而網上查到的 archive 相關文章在不了解其背景的情況下,就以為可以直接刪除文件,導致異常的發生。當存儲空間不足時,沒有全面排查了解存儲空間丟失原因,就進行一些處理,導致直接恢復刪除文件並沒有修復問題。而對hbase一些命令的底層運行原理不了解,也造成一些操作上的誤判。好在這只是測試環境,數據丟失影響不大,接下來需要深入研究hbase各方面的運行機制,避免這種低級問題的發生。