這個問題我去網上搜尋了一下,發現了很多的解決方案都是增加的nproc數量,即使用者最大執行緒數的數量,但我修改了並沒有解決問題,最終是通過修改hadoop叢集的最大執行緒數解決問題的。
並且網路上的回答多數關於增加nproc的答案不完整,我這裡順便記錄一下。
使用者最大執行緒數可以通過linux下的命令
ulimit -a
檢視,螢幕輸出中的max user processes就是使用者最大執行緒數,預設通常為1024.
修改這個引數的地方是在/etc/security/limits.conf以及/etc/security/limits.d/90-nproc.conf(可能這個檔案的名字會不一樣)
/etc/security/limits.conf修改如下
* soft nofile 65536
* hard nofile 65536
xxx soft nproc 65535
xxx hard nproc 65535
其中 xxx表示啟動hbase的使用者,如使用hadoop啟動hbase,則配置如下:
hadoop hard nproc 65535
hadoop soft nproc 65535
這裡說明一下,noproc 是代表最大程式數,nofile 是代表最大檔案開啟數
然後,一般來說,修改ulimit的數值,只需要修改/etc/security/limits.conf即可,但是這個引數需要修改/etc/security/limits.d/90-nproc.conf。
至於為什麼需要修改這裡,可以看看這篇blog。
在裡面新增
hadoop hard nproc 65535
hadoop soft nproc 65535
就修改成功啦。
但這個修改並沒有讓我的問題得到解決。我從java.lang.OutOfMemoryError入手,懷疑是否是Hbase或者是DataNode的Jvm程式記憶體不足導致記憶體溢位。於是使用jmap -heap命令分別檢視了各個節點的DataNode,確實發現了有一些DataNode的老年代佔有率過高,於是修改hadoop配置檔案HADOOP_HOME/etc/hadoop/hadoop-env.sh。在最後新增
export HADOOP_DATANODE_OPTS="-Xmx8192m -Xms256m -Dcom.sun.management.jmxremote $HADOOP_DATANODE_OPTS"
這個配置的作用是將DataNode的最大記憶體加到8G,在各個節點修改配置檔案,重啟DataNode。
再次啟動spark讀取hbase,確實有一點點改善,但最終還是會報錯。
這次我再去檢視了hadoop的日誌,發現了不一樣的錯誤,java.io.IOException: Premature EOF from inputStream。
再去網上查,發現其原因是檔案操作超租期,實際上就是data stream操作過程中檔案被刪掉了。通常是因為Mapred多個task操作同一個檔案,一個task完成後刪掉檔案導致。這個錯誤跟dfs.datanode.max.transfer.threads引數到達上限有關。這個是datanode同時處理請求的任務上限,總預設值是 4096,該引數取值範圍[1 to 8192]。
這不正是和unable to create new native thread有關嗎,繼續修改整個叢集,在HADOOP_HOME/etc/hadoop/hdfs-site.xml中增加以下配置
<property>
<name>dfs.datanode.max.transfer.threads</name>
<value>8192</value>
</property>
再次啟動spark任務,操作成功!!