[置顶] 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下 。

你可能感兴趣的:(hadoop,jsp,null,import,Constructor,Constants)