快下班的時候突然收到zk、HBase宕機的告警,瞬間一萬匹草泥馬奔騰而過,但是問題終究得解決啊,搞起來。
下圖爲master的日誌記錄:
從上圖可以看到zk中/Hbase/replication/rs
的節點信息無法獲取,然後我們立馬去檢查zk日誌發現zk已經全部斷聯而且已經癱瘓,截圖如下:
上網一番查找發現java.nio.channels.CancelledKeyException
是zk 3.4.10
之前版本的bug,筆者使用的正是3.4.8
,此bug在3.4.10已修復。
至此,zk宕機原因找到了,將zk節點全部重啓然後重啓HBase,核心問題來了,遇到了一個老兄弟,java.io.IOException: Packet len6075380 is out of range !
master退出,啓動失敗。
按照以前的經驗,去zkCli.sh修改了-Djute.maxbuffer=41943040
的配置,第一次修改直接將值翻倍後重啓還是報同樣的錯誤,多次翻倍終無效果;一氣之下直接將值多加了兩個00,變成了之前的上千倍,數值達到了百億級別,重啓依然無效。然後決定刪除zk中的HBase節點,rmr /habse竟然報錯了,更巧的是同樣的java.io.IOException: Packet len6075380 is out of range !
好難受啊!!!
折騰了這麼半天沒有思路了,突然運維的同事提醒我說我改的值應該已經超出zk的限制了,估計都不會生效,聽了這麼一個提醒,心裏竊喜的很啊,馬上一番操作下載zk源碼看看到底怎麼回事。
void readLength() throws IOException {
int len = incomingBuffer.getInt();
if (len < 0 || len >= packetLen) {
throw new IOException("Packet len" + len + " is out of range!");
}
incomingBuffer = ByteBuffer.allocate(len);
}
packetLen爲配置文件的值,而incomingBuffer爲HBase啓動報錯的值:6075380 > 4194304(默認值),所以拋出上述異常:
private int packetLen = ZKClientConfig.CLIENT_MAX_PACKET_LENGTH_DEFAULT;
查看源碼發現zk初始化的時候會去加載配置文件的·jute.maxbuffer·值,如果值的大小不爲空就採用此值,如果爲空就用默認值,上圖紅色部分爲默認是大小4M=4194304,但還有一個前提就是配置的值必須是int範圍內的值,否則Integer.parseInt(value.trim())方法會報錯。
try {
packetLen = clientConfig.getInt(ZKConfig.JUTE_MAXBUFFER,
ZKClientConfig.CLIENT_MAX_PACKET_LENGTH_DEFAULT);
LOG.info("{} value is {} Bytes", ZKConfig.JUTE_MAXBUFFER,
packetLen);
} catch (NumberFormatException e) {
String msg = MessageFormat.format(
"Configured value {0} for property {1} can not be parsed to int",
clientConfig.getProperty(ZKConfig.JUTE_MAXBUFFER),
ZKConfig.JUTE_MAXBUFFER);
LOG.error(msg);
throw new IOException(msg);
}
}
public int getInt(String key, int defaultValue) {
String value = getProperty(key);
if (value != null) {
return Integer.parseInt(value.trim());
}
return defaultValue;
}
而筆者最後修改的值爲百億,已然超出了int範圍,所以是無效的配置。至此,原因找到了,立馬改成了10M的配置重新啓動zk並刪除/hbase節點成功。
但是,調整此參數始終治標不治本,結合本司集羣中的數據量(200億+)和region數量(10W+)考慮,master重啓是一項浩大的工程,因爲重啓會導致region的狀態變更,而變更的中間狀態是在zk節點維護,當大量的region需要分配,而分配速度又很慢就會導致zk中/hbase/下的部分節點存儲數據量太大從而導致異常。
所以我們需要從兩個方面入手:
1、儘量合理的劃分region。
2、提高處理region分配的線程數。修改配置項hbase.assignment.threads.max
,該配置默認值爲30。
<property>
<name>hbase.assignment.threads.max</name>
<value>100</value>
</property>
然後重啓HBase,順利啓動。
往期推薦
▬
Uber基於Apache Hudi構建PB級數據湖實踐
數據湖 | 一文讀懂Data Lake的概念、特徵、架構與案例
認識 Delta Lake:讓數倉進化到數據湖
乾貨 | Kafka 內核知識梳理,附思維導圖