hadoop出现元数据不能更新且SNN合并失效

来源:互联网 发布:2015网络银行交易金额 编辑:程序博客网 时间:2024/06/01 20:04
问题表现: 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-protectedClass 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 saveStorageDirectory 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下 。

原创粉丝点击