1. 程式人生 > >hadoop出現元資料不能更新且SNN合併失效

hadoop出現元資料不能更新且SNN合併失效

問題表現: NameNode 儲存edits檔案 停留在5.3號凌晨。SNN執行合併檔案報 空指標錯誤,導致無法正常合併元資料 原因:要弄清原因首先需要清楚SNN合併流程,NN寫editslog流程等等。簡單說來如下: 1 在5.3號 SNN合併檔案後併成功將合併的資料put到NN。當NN在關閉臨時edit檔案edit.new,開啟edits檔案時報錯:unable to open  2 正常情況下,開啟edits檔案後,會將edits輸出流加入前面已經清空的edits輸出流列表。在1 失敗下,該操作未做,所以edits輸出流列表為空表物件 3 開啟失敗下,會將失敗的路徑自動移除掉,以便後面的自動嘗試恢復。同時自動嘗試恢復是在SNN合併檔案時出發。但是咱們的情況是2個edits路徑全部失敗,導致 路徑集合為null。 4 新的SNN合併請求過來後會先得到儲存路徑集合,此時報Null退出 。 5 對於檔案操作的日誌,因為2操作沒有執行,沒有可用的edits輸出流列表,所以直接往下執行其他操作,導致edits檔案也不再更新。 解決思路: 1 因為NN不再更新edits檔案,SNN也無法合併Img,所以以前NN儲存的元資料無法使用。所以必須恢復元資料到最新。這可以通過hdfs提供的api匯出hdfs目錄元資料並儲存。 這個操作必須在安全模式下執行。 2 從上面5點看,很多操作時由於打不開edit後導致的edits輸出流列表為空表(不是Null)和NN的元資料儲存路徑為Null 3 恢復edits輸出流列表,才能讓NN正常寫edits,這個操作可以呼叫hdfs提供的api實現。 4 恢復NN的元資料儲存路徑也可以呼叫hdfs提供的api重新設定。 解決方案: 1 讓叢集進入安全模式,使用匯出元資料的jsp ,匯出最新元資料,停止叢集,,拷貝新的元資料替換舊的元資料後重啟叢集。 2 讓叢集進入安全模式,使用匯出元資料的jsp ,匯出最新元資料,拷貝新的元資料替換舊的元資料。恢復edits流列表,恢復NN的元資料儲存路徑列表,離開安全模式。(測試正常,但沒在線上應用) 附件: 1 匯出元資料的jsp:
<%@ page
  contentType="text/html; charset=UTF-8"
  isThreadSafe="false"
  import="java.io.*"
  import="java.lang.reflect.*"
  import="org.apache.hadoop.hdfs.*"
  import="org.apache.hadoop.hdfs.server.namenode.*"
  import="org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory"
  import="org.apache.hadoop.hdfs.server.common.Storage.StorageDirType"
%>
<%
String path = request.getParameter("dir");
if (path == null) {
  throw new IllegalArgumentException("specify dir parameter");
}
File dir = new File(path);
if (!dir.exists()) {
  dir.mkdir();
}

NameNode nn = (NameNode)application.getAttribute("name.node");
if (!nn.isInSafeMode()) {
  throw new IllegalStateException("not in safe mode");
}

// Use reflection to find saveCurrent()
FSImage image = nn.getFSImage();
Method m = FSImage.class.getDeclaredMethod("saveCurrent", StorageDirectory.class);
m.setAccessible(true);

// Use reflection to find the IMAGE_AND_EDITS enum, since it's package-protected
Class c = Class.forName("org.apache.hadoop.hdfs.server.namenode.FSImage$NameNodeDirType");
StorageDirType[] constants = (StorageDirType[])c.getEnumConstants();

StorageDirType t = null;
for (StorageDirType sdt : constants) {
  if (sdt.toString().equals("IMAGE_AND_EDITS")) {
    t = sdt;
  }
}
if (t == null) {
  throw new IllegalStateException("no type");
}

// Actually save
StorageDirectory sd = image.new StorageDirectory(dir, t);
m.invoke(image, sd);
%>
Saved image to <%= sd.getCurrentDir() %>

2 檢視 edit流列表及儲存路徑集合及其他物件jsp:
<%@ page
  contentType="text/html; charset=UTF-8"
  isThreadSafe="false"
  import="java.io.*"
  import="java.util.*"
  import="java.lang.reflect.*"
  import="org.apache.hadoop.hdfs.*"
  import="org.apache.hadoop.hdfs.server.namenode.*"
  import="org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory"
  import="org.apache.hadoop.hdfs.server.common.Storage.StorageDirType"
%>

<%
   NameNode nn = (NameNode)application.getAttribute("name.node");
   
   out.println("namenode="+nn.toString());
   final FSImage nnImage = (FSImage)application.getAttribute("name.system.image");
   out.println("storagedirs="+nnImage.listStorageDirectories());
  Method m = FSImage.class.getDeclaredMethod("getFsImageName", null);
  m.setAccessible(true);
  out.println("nnImage.getFsImageName()="+m.invoke(nnImage,null));
 
   out.println("httpserver name.system.image="+nnImage.toString());
   out.println("getFsImage from nn="+nn.getFSImage());
  out.println("<br/>");
   File eFile=new File("/data0/hadoop/hdfs/name/current/edits");
   RandomAccessFile rp = new RandomAccessFile(eFile, "rw");
   FileOutputStream  fp = new FileOutputStream(rp.getFD());
  // FSEditLog.EditLogOutputStream eStream = new FSEditLog.EditLogFileOutputStream(eFile);
   out.println("fileoutputstream="+fp.toString());   

   out.println("<br/>");
  m = FSImage.class.getDeclaredMethod("getRemovedStorageDirs", null);
  m.setAccessible(true);
 List<StorageDirectory> list=(List<StorageDirectory>)m.invoke(nnImage,null);
  out.println("removedStorageDirs.size="+list.size());
  for(StorageDirectory dir:list)
   out.println("removeddir="+dir.getRoot().getPath().toString());

out.println("<br/>");
FSNamesystem fsNamesystem=nn.getNamesystem();
Method mm = FSNamesystem.class.getDeclaredMethod("getEditLog", null);
mm.setAccessible(true);
FSEditLog editlog=(FSEditLog)mm.invoke(fsNamesystem,null);
out.println("nn's editlog="+editlog.toString());


Method mm1 = FSEditLog.class.getDeclaredMethod("getNumEditStreams", null);
mm1.setAccessible(true);
out.println("getNumEditStreams="+mm1.invoke(editlog,null));
%>


3 恢復 edits流列表jsp:
<%@ page
  contentType="text/html; charset=UTF-8"
  isThreadSafe="false"
  import="java.io.*"
  import="java.util.*"
  import="java.lang.reflect.*"
  import="org.apache.hadoop.hdfs.*"
  import="org.apache.hadoop.hdfs.server.namenode.*"
  import="org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory"
  import="org.apache.hadoop.hdfs.server.common.Storage.StorageDirType"
%>

<%
NameNode nn = (NameNode)application.getAttribute("name.node");
FSNamesystem fsNamesystem=nn.getNamesystem();
Method mm = FSNamesystem.class.getDeclaredMethod("getEditLog", null);
mm.setAccessible(true);
FSEditLog editlog=(FSEditLog)mm.invoke(fsNamesystem,null);
out.println("nn's editlog="+editlog.toString());


Method mm1 = FSEditLog.class.getDeclaredMethod("getNumEditStreams", null);
mm1.setAccessible(true);
out.println("getNumEditStreams="+mm1.invoke(editlog,null));


 Field field=FSEditLog.class.getDeclaredField("editStreams");
 field.setAccessible(true);
 ArrayList editStreams=(ArrayList)field.get(editlog);
 out.println(editStreams.size());
 
 out.println("<br/>begin to reset editStreams...");
 editStreams.clear();
 Class c = Class.forName("org.apache.hadoop.hdfs.server.namenode.FSEditLog$EditLogFileOutputStream");
 Constructor constructor=c.getDeclaredConstructor(File.class);
 constructor.setAccessible(true);
 File f=new File("/analyser/hdfs/dfs/name/current/edits");
 editStreams.add(constructor.newInstance(f));
 //f=new File("/data0/hadoop/aernfs/name/current/edits");
 //editStreams.add(constructor.newInstance(f));
out.println("<br/> reset editStreams success!");
 out.println("editStreams.size()="+editStreams.size());
 out.println("getNumEditStreams="+mm1.invoke(editlog,null));







%>

4 恢復NN儲存路徑列表jsp:
<%@ page
  contentType="text/html; charset=UTF-8"
  isThreadSafe="false"
  import="java.io.*"
  import="java.util.*"
  import="java.lang.reflect.*"
  import="org.apache.hadoop.hdfs.*"
  import="org.apache.hadoop.conf.*"
  import="org.apache.hadoop.hdfs.server.namenode.*"
  import="org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory"
  import="org.apache.hadoop.hdfs.server.common.Storage.StorageDirType"
%>

<%
   NameNode nn = (NameNode)application.getAttribute("name.node");
   
   out.println("namenode="+nn.toString());
   final FSImage nnImage = (FSImage)application.getAttribute("name.system.image");
   out.println("storagedirs="+nnImage.listStorageDirectories());
  Method m = FSImage.class.getDeclaredMethod("getFsImageName", null);
  m.setAccessible(true);
  out.println("nnImage.getFsImageName()="+m.invoke(nnImage,null));
    
  out.println("<br/>begin resetStorageDirectories...");
  Method m1=FSImage.class.getDeclaredMethod("setStorageDirectories", Collection.class,Collection.class);
  m1.setAccessible(true);
  Configuration conf = new Configuration();
  m1.invoke(nnImage,FSNamesystem.getNamespaceDirs(conf),FSNamesystem.getNamespaceEditsDirs(conf));
  out.println("<br/> resetStorageDirectories success!");
  out.println("<br/>");
 out.println("nnImage.getFsImageName()="+m.invoke(nnImage,null));
  out.println("storagedirs="+nnImage.listStorageDirectories());
%>


jsp執行 前 請將jsp放到webapp/hdfs下 。